chore: initial commit
This commit is contained in:
104
api/views/activate.php
Normal file
104
api/views/activate.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php defined('BASEPATH') || exit('No direct script access allowed'); ?>
|
||||
<?php init_head(); ?>
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<h4>Module Activation 🔑</h4>
|
||||
<hr class="hr-panel-heading">
|
||||
<p>👉 Enter your license purchase key below (<a target="_blank" href="https://help.market.envato.com/hc/en-us/articles/202822600-Where-Is-My-Purchase-Code-">Where do I get this from?</a>)</p>
|
||||
<br>
|
||||
<?php echo form_open($submit_url, ['autocomplete' => 'off', 'id' => 'verify-form']); ?>
|
||||
<?php echo form_hidden('original_url', $original_url); ?>
|
||||
<?php echo form_hidden('module_name', $module_name); ?>
|
||||
<?php echo render_input('purchase_key', 'purchase_key', '', 'text', ['required' => true]); ?>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="confirmation" name="confirmation" required value="">
|
||||
<label for="confirmation">I confirm that I adhere to the <a href="https://codecanyon.net/licenses/standard" target="_blank">Envato Licensing Terms</a></label>
|
||||
</div>
|
||||
<div class="row mbot20">
|
||||
<div class="col-md-12">
|
||||
<br>
|
||||
<button id="submit" type="submit" class="btn btn-primary">Click to activate ✔️</button>
|
||||
</div>
|
||||
</div><br>
|
||||
<?php echo form_close(); ?>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
{} <?php echo 'Version ' . $this->app_modules->get($module_name)['headers']['version'] ?? ''; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<center>
|
||||
<i class="fa fa-gavel fa-fw fa-lg tw-mr-0.5 group-hover:tw-text-neutral-800 tw-text-neutral-300"></i><h4>License Compliance & Terms</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li><i class="fa fa-check-circle"></i> Your license is valid for one instance only.</li>
|
||||
<li><i class="fa fa-check-circle"></i> A Regular License allows you to create one end product for yourself/a client.</li>
|
||||
<li><i class="fa fa-exclamation-circle"></i> Violations of these terms may result in license termination.</li>
|
||||
</ul>
|
||||
<br>
|
||||
<i class="fa fa-thumbs-down fa-fw fa-lg tw-mr-0.5 group-hover:tw-text-neutral-800 tw-text-neutral-300"></i><h4>Prohibited Usage</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li><i class="fa fa-ban"></i> Resell product/end product to multiple clients without an Extended License.</li>
|
||||
<li><i class="fa fa-ban"></i> Redistribute the product as-is or with minor modifications.</li>
|
||||
<li><i class="fa fa-ban"></i> Use the product in third party applications as a bundled product.</li>
|
||||
<li><i class="fa fa-ban"></i> Extract code components from the product for separate use.</li>
|
||||
<li><i class="fa fa-ban"></i> Edit the copyrights of the code (name, author etc).</li>
|
||||
</ul>
|
||||
</center>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<center>📋 <a style="color:#000" href="https://codecanyon.net/licenses/terms/regular">Envato License Aggrement »</center>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
appValidateForm($('#verify-form'), {
|
||||
purchase_key: 'required',
|
||||
confirmation: 'required'
|
||||
}, manage_verify_form, {
|
||||
confirmation: {
|
||||
required: "You didnt accept the terms - Please reload the page to activate your license."
|
||||
}
|
||||
});
|
||||
|
||||
function manage_verify_form(form) {
|
||||
// Get and trim the value of the purchase_key input field
|
||||
var purchaseKey = $('#purchase_key').val().trim();
|
||||
|
||||
// Log the value to check if trimming is happening correctly
|
||||
console.log("Trimmed Purchase Key: '" + purchaseKey + "'");
|
||||
|
||||
// Set the trimmed value back to the input field
|
||||
$('#purchase_key').val(purchaseKey);
|
||||
|
||||
// Disable the submit button and show loading icon
|
||||
$("#submit").prop('disabled', true).prepend('<i class="fa fa-spinner fa-pulse"></i> ');
|
||||
|
||||
// Send the form data using AJAX
|
||||
$.post(form.action, $(form).serialize()).done(function(response) {
|
||||
var response = $.parseJSON(response);
|
||||
if (!response.status) {
|
||||
alert_float("danger", response.message);
|
||||
}
|
||||
if (response.status) {
|
||||
alert_float("success", "Activating your license..");
|
||||
window.location.href = response.original_url;
|
||||
}
|
||||
// Enable the submit button and remove the loading icon
|
||||
$("#submit").prop('disabled', false).find('i').remove();
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
94
api/views/api_management.php
Normal file
94
api/views/api_management.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
|
||||
<?php init_head(); ?>
|
||||
|
||||
<link href="<?php echo base_url('modules/api/assets/main.css'); ?>" rel="stylesheet" type="text/css" />
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<div class="_buttons">
|
||||
<a href="<?php echo admin_url('api/create_user/') ?>" class="btn btn-info pull-left display-block"><?php echo _l('new_user_api'); ?></a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<hr class="hr-panel-heading" />
|
||||
<div class="clearfix"></div>
|
||||
<table class="apitable table dt-table">
|
||||
<thead>
|
||||
<th><?php echo _l('id'); ?></th>
|
||||
<th><?php echo _l('user_api'); ?></th>
|
||||
<th><?php echo _l('name_api'); ?></th>
|
||||
<th><?php echo _l('token_api'); ?></th>
|
||||
<th><?php echo _l('request_limit'); ?></th>
|
||||
<th><?php echo _l('time_window'); ?></th>
|
||||
<th><?php echo _l('quota_active'); ?></th>
|
||||
<th><?php echo _l('expiration_date'); ?></th>
|
||||
<th><?php echo _l('options'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($user_api as $user) { ?>
|
||||
<tr>
|
||||
<td><?php echo addslashes($user['id']); ?></td>
|
||||
<td><?php echo addslashes($user['user']); ?></td>
|
||||
<td><?php echo addslashes($user['name']); ?></td>
|
||||
<td><code onclick="copyToken('<?php echo $user['token'] ?>')"><?php echo substr($user['token'], 0, 20) . '...'; ?></code></td>
|
||||
<td><?php echo addslashes($user['request_limit'] ?? 1000); ?></td>
|
||||
<td><?php echo format_time_window($user['time_window'] ?? 3600); ?></td>
|
||||
<td>
|
||||
<span class="label label-<?php echo ($user['quota_active'] ?? 1) ? 'success' : 'danger'; ?>">
|
||||
<?php echo ($user['quota_active'] ?? 1) ? _l('active') : _l('inactive'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo addslashes($user['expiration_date'] ?? ""); ?></td>
|
||||
<td>
|
||||
<a href="<?php echo admin_url('api/edit_user/' . $user['id']) ?>" class="btn btn-default btn-icon" title="<?php echo _l('edit_user'); ?>"><i class="fa fa-pencil"></i></a>
|
||||
<a href="<?php echo admin_url('api/user_stats/' . $user['id']) ?>" class="btn btn-success btn-icon" title="<?php echo _l('user_statistics'); ?>"><i class="fa fa-bar-chart"></i></a>
|
||||
<a href="<?php echo admin_url('api/delete_user/' . addslashes($user['id'])); ?>" class="btn btn-danger btn-icon _delete" title="<?php echo _l('delete_user'); ?>"><i class="fa fa-remove"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="user_api" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<?php echo form_open(admin_url('api/user')); ?>
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">
|
||||
<span class="edit-title"><?php echo _l('edit_user_api'); ?></span>
|
||||
<span class="add-title"><?php echo _l('new_user_api'); ?></span>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="additional"></div>
|
||||
<?php echo render_input('user','user_api'); ?>
|
||||
<?php echo render_input('name','name_api'); ?>
|
||||
<?php echo render_datetime_input('expiration_date','expiration_date'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo _l('close'); ?></button>
|
||||
<button type="submit" class="btn btn-info"><?php echo _l('submit'); ?></button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
<?php echo form_close(); ?>
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<?php init_tail(); ?>
|
||||
|
||||
<script src="<?php echo base_url('modules/api/assets/main.js'); ?>"></script>
|
||||
275
api/views/api_reporting.php
Normal file
275
api/views/api_reporting.php
Normal file
@@ -0,0 +1,275 @@
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
|
||||
<?php init_head(); ?>
|
||||
|
||||
<link href="<?php echo base_url('modules/api/assets/main.css'); ?>" rel="stylesheet" type="text/css" />
|
||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4 class="no-margin"><?php echo _l('api_reporting'); ?></h4>
|
||||
<hr class="hr-panel-heading" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('filters'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<?php echo form_open(admin_url('api/reporting'), 'method="get"', ['id' => 'reporting-filters']); ?>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label for="api_key"><?php echo _l('api_key'); ?></label>
|
||||
<select name="api_key" id="api_key" class="form-control">
|
||||
<option value=""><?php echo _l('all_api_keys'); ?></option>
|
||||
<?php foreach ($api_keys as $key) { ?>
|
||||
<option value="<?php echo $key['api_key']; ?>" <?php echo ($api_key == $key['api_key']) ? 'selected' : ''; ?>>
|
||||
<?php echo $key['api_key']; ?>
|
||||
</option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label for="start_date"><?php echo _l('start_date'); ?></label>
|
||||
<input type="date" name="start_date" id="start_date" class="form-control" value="<?php echo $start_date; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label for="end_date"><?php echo _l('end_date'); ?></label>
|
||||
<input type="date" name="end_date" id="end_date" class="form-control" value="<?php echo $end_date; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label> </label>
|
||||
<div>
|
||||
<button type="submit" class="btn btn-info"><?php echo _l('apply_filters'); ?></button>
|
||||
<a href="<?php echo admin_url('api/reporting/export?' . http_build_query($_GET)); ?>" class="btn btn-success"><?php echo _l('export'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo form_close(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary Cards -->
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('total_requests'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<h2><?php echo number_format($usage_stats->total_requests ?? 0); ?></h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-success">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('success_rate'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<h2><?php echo ($usage_stats->total_requests ?? 0) > 0 ? round((($usage_stats->success_requests ?? 0) / ($usage_stats->total_requests ?? 1)) * 100, 2) : 0; ?>%</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-warning">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('avg_response_time'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<h2><?php echo round($usage_stats->avg_response_time ?? 0, 4); ?>s</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('error_requests'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<h2><?php echo number_format($usage_stats->error_requests ?? 0); ?></h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Charts -->
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('request_timeline'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="request-timeline-chart" style="height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('response_codes'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="response-codes-chart" style="height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Endpoint Statistics -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('endpoint_statistics'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo _l('endpoint'); ?></th>
|
||||
<th><?php echo _l('request_count'); ?></th>
|
||||
<th><?php echo _l('avg_response_time'); ?></th>
|
||||
<th><?php echo _l('success_count'); ?></th>
|
||||
<th><?php echo _l('error_count'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($endpoint_stats as $stat) { ?>
|
||||
<tr>
|
||||
<td><?php echo $stat->endpoint; ?></td>
|
||||
<td><?php echo number_format($stat->request_count ?? 0); ?></td>
|
||||
<td><?php echo round($stat->avg_response_time ?? 0, 4); ?>s</td>
|
||||
<td><?php echo number_format($stat->success_count ?? 0); ?></td>
|
||||
<td><?php echo number_format($stat->error_count ?? 0); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Key Summary -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title"><?php echo _l('api_key_summary'); ?></h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo _l('api_key'); ?></th>
|
||||
<th><?php echo _l('total_requests'); ?></th>
|
||||
<th><?php echo _l('avg_response_time'); ?></th>
|
||||
<th><?php echo _l('success_requests'); ?></th>
|
||||
<th><?php echo _l('error_requests'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($api_key_summary as $summary) { ?>
|
||||
<tr>
|
||||
<td><?php echo $summary->api_key; ?></td>
|
||||
<td><?php echo number_format($summary->total_requests ?? 0); ?></td>
|
||||
<td><?php echo round($summary->avg_response_time ?? 0, 4); ?>s</td>
|
||||
<td><?php echo number_format($summary->success_requests ?? 0); ?></td>
|
||||
<td><?php echo number_format($summary->error_requests ?? 0); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Request Timeline Chart
|
||||
var timelineData = <?php echo json_encode($hourly_usage); ?>;
|
||||
var timelineChart = Highcharts.chart('request-timeline-chart', {
|
||||
title: {
|
||||
text: '<?php echo _l('request_timeline'); ?>'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
title: {
|
||||
text: '<?php echo _l('time'); ?>'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: '<?php echo _l('requests'); ?>'
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: '<?php echo _l('requests'); ?>',
|
||||
data: timelineData.map(function(item) {
|
||||
return [new Date(item.hour).getTime(), parseInt(item.request_count)];
|
||||
})
|
||||
}],
|
||||
tooltip: {
|
||||
pointFormat: '{series.name}: <b>{point.y}</b>'
|
||||
}
|
||||
});
|
||||
|
||||
// Response Codes Chart
|
||||
var responseCodesData = <?php echo json_encode($response_codes); ?>;
|
||||
var responseCodesChart = Highcharts.chart('response-codes-chart', {
|
||||
chart: {
|
||||
type: 'pie'
|
||||
},
|
||||
title: {
|
||||
text: '<?php echo _l('response_codes'); ?>'
|
||||
},
|
||||
series: [{
|
||||
name: '<?php echo _l('requests'); ?>',
|
||||
data: responseCodesData.map(function(item) {
|
||||
return [item.response_code.toString(), parseInt(item.count)];
|
||||
})
|
||||
}],
|
||||
tooltip: {
|
||||
pointFormat: '{series.name}: <b>{point.y}</b>'
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="<?php echo base_url('modules/api/assets/main.js'); ?>"></script>
|
||||
83
api/views/create_user_api.php
Normal file
83
api/views/create_user_api.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
|
||||
<?php init_head(); ?>
|
||||
|
||||
<link href="<?php echo base_url('modules/api/assets/main.css'); ?>" rel="stylesheet" type="text/css" />
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<?php echo form_open('admin/api/user/'); ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<?php echo render_input('user', 'user_api'); ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?php echo render_input('name', 'name_api'); ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?php echo render_datetime_input('expiration_date', 'expiration_date'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4 class="no-margin"><?php echo _l('quota_settings'); ?></h4>
|
||||
<hr class="hr-panel-heading" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="request_limit" class="control-label"><?php echo _l('request_limit'); ?> <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" name="request_limit" id="request_limit" value="1000" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="time_window" class="control-label"><?php echo _l('time_window'); ?> <span class="text-danger">*</span></label>
|
||||
<select class="form-control" name="time_window" id="time_window" required>
|
||||
<option value="3600">1 Hour</option>
|
||||
<option value="86400" selected>24 Hours</option>
|
||||
<option value="604800">7 Days</option>
|
||||
<option value="2592000">30 Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="burst_limit" class="control-label"><?php echo _l('burst_limit'); ?> <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" name="burst_limit" id="burst_limit" value="100" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" name="quota_active" id="quota_active" value="1" checked>
|
||||
<label><?php echo _l('quota_active'); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php $this->load->view('permissions'); ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<button type="submit" class="btn btn-primary pull-right permission-save-btn" id="permission-form-submit">
|
||||
<?php echo _l('submit'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php echo form_close(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
|
||||
<script src="<?php echo base_url('modules/api/assets/main.js'); ?>"></script>
|
||||
92
api/views/edit_user_api.php
Normal file
92
api/views/edit_user_api.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
|
||||
<?php init_head(); ?>
|
||||
|
||||
<link href="<?php echo base_url('modules/api/assets/main.css'); ?>" rel="stylesheet" type="text/css" />
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<?php echo form_open('admin/api/user/'); ?>
|
||||
|
||||
<input type="hidden" name="id" value="<?php echo $user_api['id'] ?? ''?>" />
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<?php echo render_input('user', 'user_api', $user_api['user'] ?? ''); ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?php echo render_input('name', 'name_api', $user_api['name'] ?? ''); ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?php echo render_datetime_input('expiration_date', 'expiration_date', $user_api['expiration_date'] ?? ''); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<?php echo render_input('token', 'token_api', $user_api['token'] ?? '', 'text', ['readonly' => true]); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4 class="no-margin"><?php echo _l('quota_settings'); ?></h4>
|
||||
<hr class="hr-panel-heading" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="request_limit" class="control-label"><?php echo _l('request_limit'); ?> <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" name="request_limit" id="request_limit"
|
||||
value="<?php echo $user_api['request_limit'] ?? 1000; ?>" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="time_window" class="control-label"><?php echo _l('time_window'); ?> <span class="text-danger">*</span></label>
|
||||
<select class="form-control" name="time_window" id="time_window" required>
|
||||
<option value="3600" <?php echo ($user_api['time_window'] ?? 3600) == 3600 ? 'selected' : ''; ?>>1 Hour</option>
|
||||
<option value="86400" <?php echo ($user_api['time_window'] ?? 3600) == 86400 ? 'selected' : ''; ?>>24 Hours</option>
|
||||
<option value="604800" <?php echo ($user_api['time_window'] ?? 3600) == 604800 ? 'selected' : ''; ?>>7 Days</option>
|
||||
<option value="2592000" <?php echo ($user_api['time_window'] ?? 3600) == 2592000 ? 'selected' : ''; ?>>30 Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="burst_limit" class="control-label"><?php echo _l('burst_limit'); ?> <span class="text-danger">*</span></label>
|
||||
<input type="number" class="form-control" name="burst_limit" id="burst_limit"
|
||||
value="<?php echo $user_api['burst_limit'] ?? 100; ?>" min="1" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" name="quota_active" id="quota_active" value="1"
|
||||
<?php echo ($user_api['quota_active'] ?? 1) ? 'checked' : ''; ?>/>
|
||||
<label><?php echo _l('quota_active'); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php $this->load->view('permissions'); ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<button type="submit" class="btn btn-primary pull-right permission-save-btn" id="permission-form-submit">
|
||||
<?php echo _l('submit'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php echo form_close(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
|
||||
<script src="<?php echo base_url('modules/api/assets/main.js'); ?>"></script>
|
||||
104
api/views/permissions.php
Normal file
104
api/views/permissions.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php $api_permissions_count = count(get_available_api_permissions()); ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<?php echo _l('permissions'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered roles no-margin">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Feature</th>
|
||||
<th>Capabilities</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$api_permission_index = 0;
|
||||
foreach (get_available_api_permissions() as $feature => $permission) {
|
||||
$api_permission_index += 1;
|
||||
if ($api_permission_index >= floor($api_permissions_count / 2)) continue;
|
||||
?>
|
||||
<tr data-name="<?php echo $feature; ?>">
|
||||
<td>
|
||||
<b><?php echo $permission['name']; ?></b>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
foreach ($permission['capabilities'] as $capability => $name) {
|
||||
$checked = '';
|
||||
if (isset($user_api) && api_can($user_api['id'] ?? '', $feature, $capability)) {
|
||||
$checked = ' checked ';
|
||||
}
|
||||
?>
|
||||
<div class="checkbox" style="padding-left: 20px">
|
||||
<input type="checkbox" <?php echo $checked; ?> class="capability" id="<?php echo $feature . '_' . $capability; ?>" name="permissions[<?php echo $feature; ?>][]" value="<?php echo $capability; ?>">
|
||||
<label for="<?php echo $feature . '_' . $capability; ?>"> <?php echo $name; ?></label>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php }
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered roles no-margin">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Feature</th>
|
||||
<th>Capabilities</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$api_permission_index = 0;
|
||||
foreach (get_available_api_permissions() as $feature => $permission) {
|
||||
$api_permission_index += 1;
|
||||
if ($api_permission_index < floor($api_permissions_count / 2)) continue;
|
||||
?>
|
||||
<tr data-name="<?php echo $feature; ?>">
|
||||
<td>
|
||||
<b><?php echo $permission['name']; ?></b>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
foreach ($permission['capabilities'] as $capability => $name) {
|
||||
$checked = '';
|
||||
if (isset($user_api) && api_can($user_api['id'] ?? '', $feature, $capability)) {
|
||||
$checked = ' checked ';
|
||||
}
|
||||
?>
|
||||
<div class="checkbox" style="padding-left: 20px">
|
||||
<input type="checkbox" <?php echo $checked; ?> class="capability" id="<?php echo $feature . '_' . $capability; ?>" name="permissions[<?php echo $feature; ?>][]" value="<?php echo $capability; ?>">
|
||||
<label for="<?php echo $feature . '_' . $capability; ?>"> <?php echo $name; ?></label>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php }
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
66
api/views/playground.php
Normal file
66
api/views/playground.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo $title; ?></title>
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo base_url('/modules/api/assets/swagger/swagger-ui.css') ?>">
|
||||
<script src="<?php echo base_url('/modules/api/assets/swagger/swagger-ui-bundle.js') ?>"></script>
|
||||
<script src="<?php echo base_url('/modules/api/assets/swagger/swagger-ui-standalone-preset.js') ?>"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<style>
|
||||
[data-param-name="check_api"] {
|
||||
display: none;
|
||||
}
|
||||
.schemes-server-container {
|
||||
opacity: 0;
|
||||
}
|
||||
.swagger-ui > div > .wrapper:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "<?php echo site_url('/api/playground-json'); ?>",
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [ ],
|
||||
requestInterceptor: (req) => {
|
||||
req.headers['X-Playground'] = 'enabled';
|
||||
return req;
|
||||
}
|
||||
});
|
||||
}
|
||||
function checkTryOutBtn() {
|
||||
if (document.querySelectorAll('.try-out__btn').length) {
|
||||
document.querySelectorAll('.try-out__btn').forEach(btyOutBtnEl => {
|
||||
btyOutBtnEl.removeEventListener('click', function() {});
|
||||
btyOutBtnEl.addEventListener('click', function() {
|
||||
setTimeout(function() {
|
||||
document.querySelectorAll('input').forEach(decimalEl => {
|
||||
if (decimalEl.closest('.parameters').querySelector('.prop-format') && decimalEl.closest('.parameters').querySelector('.prop-format').innerText === "($decimal)") {
|
||||
decimalEl.value = parseFloat(decimalEl.value).toFixed(2);
|
||||
decimalEl.setAttribute("value", parseFloat(decimalEl.value).toFixed(2));
|
||||
decimalEl.removeEventListener('change', function() {});
|
||||
decimalEl.addEventListener('change', function() {
|
||||
decimalEl.value = parseFloat(decimalEl.value).toFixed(2);
|
||||
decimalEl.setAttribute("value", parseFloat(decimalEl.value).toFixed(2));
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
setTimeout(function() {
|
||||
checkTryOutBtn();
|
||||
}, 1000);
|
||||
}
|
||||
checkTryOutBtn();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
307
api/views/playground/documentation.php
Normal file
307
api/views/playground/documentation.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo $title; ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/themes/prism.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.documentation-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.header-section {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 40px 0;
|
||||
margin-bottom: 30px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.content-section {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.section-header {
|
||||
background: #f8f9fa;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
border-radius: 10px 10px 0 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
.section-body {
|
||||
padding: 20px;
|
||||
}
|
||||
.endpoint-item {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.method-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.method-get { background: #28a745; color: white; }
|
||||
.method-post { background: #007bff; color: white; }
|
||||
.method-put { background: #ffc107; color: black; }
|
||||
.method-delete { background: #dc3545; color: white; }
|
||||
.code-block {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.nav-link {
|
||||
color: #495057;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.nav-link:hover {
|
||||
background-color: #e9ecef;
|
||||
color: #212529;
|
||||
}
|
||||
.nav-link.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="documentation-container">
|
||||
<!-- Header Section -->
|
||||
<div class="header-section text-center">
|
||||
<h1><i class="fas fa-book"></i> Perfex CRM API Documentation</h1>
|
||||
<p class="lead">Complete guide to using the Perfex CRM REST API</p>
|
||||
</div>
|
||||
|
||||
<!-- Navigation -->
|
||||
<div class="content-section">
|
||||
<div class="section-header">
|
||||
<h4><i class="fas fa-list"></i> Quick Navigation</h4>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a href="#authentication" class="nav-link">Authentication</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="#endpoints" class="nav-link">API Endpoints</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="#examples" class="nav-link">Examples</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="#playground" class="nav-link">API Playground</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Authentication Section -->
|
||||
<div class="content-section" id="authentication">
|
||||
<div class="section-header">
|
||||
<h4><i class="fas fa-key"></i> Authentication</h4>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<p>The Perfex CRM API uses JWT (JSON Web Token) authentication. You need to include your API key in the Authorization header of each request.</p>
|
||||
|
||||
<h5>Getting Your API Key</h5>
|
||||
<ol>
|
||||
<li>Log in to your Perfex CRM admin panel</li>
|
||||
<li>Go to <strong>API</strong> → <strong>API Keys</strong></li>
|
||||
<li>Create a new API key or use an existing one</li>
|
||||
<li>Copy the API key for use in your requests</li>
|
||||
</ol>
|
||||
|
||||
<h5>Using Your API Key</h5>
|
||||
<p>Include your API key in the Authorization header:</p>
|
||||
<div class="code-block">
|
||||
Authorization: Bearer YOUR_API_KEY_HERE
|
||||
</div>
|
||||
|
||||
<h5>Example Request</h5>
|
||||
<div class="code-block">
|
||||
curl -X GET "https://yourdomain.com/api/clients" \
|
||||
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
|
||||
-H "Content-Type: application/json"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- API Endpoints Section -->
|
||||
<div class="content-section" id="endpoints">
|
||||
<div class="section-header">
|
||||
<h4><i class="fas fa-code"></i> API Endpoints</h4>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<p>All API endpoints follow the pattern: <code>https://yourdomain.com/api/{resource}</code></p>
|
||||
|
||||
<h5>Available Resources</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-get">GET</span>
|
||||
<strong>/api/clients</strong>
|
||||
<p class="mb-0">Retrieve all clients</p>
|
||||
</div>
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-post">POST</span>
|
||||
<strong>/api/clients</strong>
|
||||
<p class="mb-0">Create a new client</p>
|
||||
</div>
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-get">GET</span>
|
||||
<strong>/api/projects</strong>
|
||||
<p class="mb-0">Retrieve all projects</p>
|
||||
</div>
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-post">POST</span>
|
||||
<strong>/api/projects</strong>
|
||||
<p class="mb-0">Create a new project</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-get">GET</span>
|
||||
<strong>/api/leads</strong>
|
||||
<p class="mb-0">Retrieve all leads</p>
|
||||
</div>
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-post">POST</span>
|
||||
<strong>/api/leads</strong>
|
||||
<p class="mb-0">Create a new lead</p>
|
||||
</div>
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-get">GET</span>
|
||||
<strong>/api/tickets</strong>
|
||||
<p class="mb-0">Retrieve all tickets</p>
|
||||
</div>
|
||||
<div class="endpoint-item">
|
||||
<span class="method-badge method-post">POST</span>
|
||||
<strong>/api/tickets</strong>
|
||||
<p class="mb-0">Create a new ticket</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>Response Format</h5>
|
||||
<p>All API responses are returned in JSON format with the following structure:</p>
|
||||
<div class="code-block">
|
||||
{
|
||||
"status": true,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
// Response data here
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Examples Section -->
|
||||
<div class="content-section" id="examples">
|
||||
<div class="section-header">
|
||||
<h4><i class="fas fa-lightbulb"></i> Examples</h4>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<h5>Create a New Lead</h5>
|
||||
<div class="code-block">
|
||||
curl -X POST "https://yourdomain.com/api/leads" \
|
||||
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"phone": "+1234567890",
|
||||
"company": "Example Corp",
|
||||
"source": "Website",
|
||||
"status": "New"
|
||||
}'
|
||||
</div>
|
||||
|
||||
<h5>Get All Clients</h5>
|
||||
<div class="code-block">
|
||||
curl -X GET "https://yourdomain.com/api/clients" \
|
||||
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
|
||||
-H "Content-Type: application/json"
|
||||
</div>
|
||||
|
||||
<h5>Create a New Ticket</h5>
|
||||
<div class="code-block">
|
||||
curl -X POST "https://yourdomain.com/api/tickets" \
|
||||
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"subject": "API Test Ticket",
|
||||
"message": "This is a test ticket created via API",
|
||||
"department": "Support",
|
||||
"priority": "Medium",
|
||||
"status": "Open"
|
||||
}'
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Playground Section -->
|
||||
<div class="content-section" id="playground">
|
||||
<div class="section-header">
|
||||
<h4><i class="fas fa-flask"></i> API Playground</h4>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<p>Test the API directly in your browser using our interactive playground:</p>
|
||||
<a href="<?php echo base_url('api/playground'); ?>" class="btn btn-primary">
|
||||
<i class="fas fa-play"></i> Open API Playground
|
||||
</a>
|
||||
<a href="<?php echo base_url('api/playground/swagger'); ?>" class="btn btn-outline-primary ms-2">
|
||||
<i class="fas fa-code"></i> View Swagger UI
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="text-center mt-4">
|
||||
<p class="text-muted">
|
||||
<a href="https://perfexcrm.themesic.com/apiguide/" target="_blank" class="btn btn-outline-primary">
|
||||
<i class="fas fa-external-link-alt"></i> View Full API Documentation
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://kit.fontawesome.com/your-fontawesome-kit.js" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
// Smooth scrolling for navigation links
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1276
api/views/playground/sandbox.php
Normal file
1276
api/views/playground/sandbox.php
Normal file
File diff suppressed because it is too large
Load Diff
120
api/views/playground/swagger.php
Normal file
120
api/views/playground/swagger.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo $title; ?></title>
|
||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui.css" />
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.swagger-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.swagger-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.swagger-ui {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.back-button {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
background: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.back-button:hover {
|
||||
background: rgba(255,255,255,0.3);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Header -->
|
||||
<div class="swagger-header">
|
||||
<h1><i class="fas fa-code"></i> Perfex CRM API - Swagger UI</h1>
|
||||
<p class="lead">Interactive API documentation and testing</p>
|
||||
</div>
|
||||
|
||||
<!-- Swagger UI Container -->
|
||||
<div class="swagger-container">
|
||||
<div class="swagger-ui">
|
||||
<div id="swagger-ui"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui-bundle.js"></script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui-standalone-preset.js"></script>
|
||||
<script src="https://kit.fontawesome.com/your-fontawesome-kit.js" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
.swagger-ui > div:nth-child(2) > .wrapper:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// Swagger UI configuration
|
||||
window.onload = function() {
|
||||
const ui = SwaggerUIBundle({
|
||||
url: '<?php echo base_url('api/playground/swagger'); ?>',
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
tryItOutEnabled: true,
|
||||
requestInterceptor: function(request) {
|
||||
// Add base URL to requests
|
||||
if (request.url.startsWith('/api/')) {
|
||||
request.url = '<?php echo base_url(); ?>' + request.url;
|
||||
}
|
||||
return request;
|
||||
},
|
||||
onComplete: function() {
|
||||
// Add authentication button
|
||||
const authButton = document.createElement('button');
|
||||
authButton.innerHTML = '<i class="fas fa-key"></i> Set API Key';
|
||||
authButton.className = 'btn btn-primary';
|
||||
authButton.style.margin = '10px';
|
||||
authButton.onclick = function() {
|
||||
const apiKey = prompt('Enter your API key:');
|
||||
if (apiKey) {
|
||||
// Set the API key in Swagger UI
|
||||
ui.preauthorizeApiKey('Bearer', apiKey);
|
||||
alert('API key set successfully!');
|
||||
}
|
||||
};
|
||||
|
||||
const topbar = document.querySelector('.swagger-ui .topbar');
|
||||
if (topbar) {
|
||||
topbar.appendChild(authButton);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
224
api/views/reporting.php
Normal file
224
api/views/reporting.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
|
||||
<?php init_head(); ?>
|
||||
|
||||
<link href="<?php echo base_url('modules/api/assets/main.css'); ?>" rel="stylesheet" type="text/css" />
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body padding-10">
|
||||
<div class="tw-flex tw-justify-between tw-items-center tw-p-1.5">
|
||||
<p class="tw-font-semibold tw-flex tw-items-center tw-mb-0 tw-space-x-1.5 rtl:tw-space-x-reverse">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw-w-6 tw-h-6 tw-text-neutral-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.125 2.25h-4.5c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125v-9M10.125 2.25h.375a9 9 0 019 9v.375M10.125 2.25A3.375 3.375 0 0113.5 5.625v1.5c0 .621.504 1.125 1.125 1.125h1.5a3.375 3.375 0 013.375 3.375M9 15l2.25 2.25L15 12" />
|
||||
</svg>
|
||||
|
||||
<span class="tw-text-neutral-700">
|
||||
<?php echo _l('all_apis'); ?>
|
||||
</span>
|
||||
</p>
|
||||
<div class="tw-divide-x tw-divide-solid tw-divide-neutral-300 tw-space-x-2 tw-flex tw-items-center">
|
||||
<div class="dropdown pull-right mright10">
|
||||
<a href="#" id="ApisChartMode" class="dropdown-toggle tw-pl-2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span id="Api-chart-mode" data-active-chart="hourly">
|
||||
<?php echo _l('hourly') ?>
|
||||
</span>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="ApisChartMode">
|
||||
<li>
|
||||
<a href="#" data-mode="hourly" onclick="update_apis_statistics(this); return false;">
|
||||
<?php echo _l('hourly') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-mode="daily" onclick="update_apis_statistics(this); return false;">
|
||||
<?php echo _l('daily') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-mode="weekly" onclick="update_apis_statistics(this); return false;">
|
||||
<?php echo _l('weekly') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-mode="monthly" onclick="update_apis_statistics(this); return false;">
|
||||
<?php echo _l('monthly') ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="-tw-mx-3 tw-mt-2 tw-mb-4">
|
||||
|
||||
<canvas height="130" class="all-apis-chart" id="all-apis-chart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body padding-10">
|
||||
<div class="tw-flex tw-justify-between tw-items-center tw-p-1.5">
|
||||
<p class="tw-font-semibold tw-flex tw-items-center tw-mb-0 tw-space-x-1.5 rtl:tw-space-x-reverse">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="tw-w-6 tw-h-6 tw-text-neutral-500">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.125 2.25h-4.5c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125v-9M10.125 2.25h.375a9 9 0 019 9v.375M10.125 2.25A3.375 3.375 0 0113.5 5.625v1.5c0 .621.504 1.125 1.125 1.125h1.5a3.375 3.375 0 013.375 3.375M9 15l2.25 2.25L15 12" />
|
||||
</svg>
|
||||
|
||||
<span class="tw-text-neutral-700">
|
||||
<?php echo _l('endpoints'); ?>
|
||||
</span>
|
||||
</p>
|
||||
<div class="tw-divide-x tw-divide-solid tw-divide-neutral-300 tw-space-x-2 tw-flex tw-items-center">
|
||||
<div class="dropdown pull-right mright10">
|
||||
<a href="#" id="EndpointsChartUri" class="dropdown-toggle tw-pl-2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span id="Endpoint-chart-uri" data-active-chart="<?php if (count($endpoints)) { echo $endpoints[0]; } ?>">
|
||||
<?php if (count($endpoints)) { echo $endpoints[0]; } ?>
|
||||
</span>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="EndpointsChartUri">
|
||||
<?php foreach ($endpoints as $endpoint) { ?>
|
||||
<li>
|
||||
<a href="#" data-uri="<?php echo $endpoint ?>" onclick="update_endpoints_statistics(this); return false;">
|
||||
<?php echo $endpoint ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown pull-right mright10">
|
||||
<a href="#" id="EndpointsChartMode" class="dropdown-toggle tw-pl-2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span id="Endpoint-chart-mode" data-active-chart="hourly">
|
||||
<?php echo _l('hourly') ?>
|
||||
</span>
|
||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="EndpointsChartMode">
|
||||
<li>
|
||||
<a href="#" data-mode="hourly" onclick="update_endpoints_statistics(null, this); return false;">
|
||||
<?php echo _l('hourly') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-mode="daily" onclick="update_endpoints_statistics(null, this); return false;">
|
||||
<?php echo _l('daily') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-mode="weekly" onclick="update_endpoints_statistics(null, this); return false;">
|
||||
<?php echo _l('weekly') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-mode="monthly" onclick="update_endpoints_statistics(null, this); return false;">
|
||||
<?php echo _l('monthly') ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="-tw-mx-3 tw-mt-2 tw-mb-4">
|
||||
|
||||
<canvas height="130" class="all-endpoints-chart" id="all-endpoints-chart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
|
||||
<script src="<?php echo base_url('modules/api/assets/main.js'); ?>"></script>
|
||||
|
||||
<script>
|
||||
var apis_statistics;
|
||||
var endpoints_statistics;
|
||||
|
||||
function update_apis_statistics(el) {
|
||||
let mode = $(el).data('mode');
|
||||
let $chartNameWrapper = $('#Api-chart-mode');
|
||||
$chartNameWrapper.data('active-chart', mode);
|
||||
$chartNameWrapper.text($(el).text());
|
||||
|
||||
if (typeof(apis_statistics) !== 'undefined') {
|
||||
apis_statistics.destroy();
|
||||
}
|
||||
|
||||
$.get(admin_url + 'api/statistics/' + mode, function(response) {
|
||||
apis_statistics = new Chart($('#all-apis-chart'), {
|
||||
type: 'bar',
|
||||
data: response,
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
}
|
||||
}]
|
||||
},
|
||||
},
|
||||
});
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
function update_endpoints_statistics(uri_el, mode_el = null) {
|
||||
console.log("Update Endpoints");
|
||||
let uri, mode;
|
||||
if (uri_el) {
|
||||
uri = $(uri_el).data('uri');
|
||||
|
||||
let $chartUriWrapper = $('#Endpoint-chart-uri');
|
||||
$chartUriWrapper.data('active-chart', uri);
|
||||
$chartUriWrapper.text($(uri_el).text());
|
||||
} else {
|
||||
uri = $('#Endpoint-chart-uri').data("active-chart");
|
||||
}
|
||||
|
||||
if (mode_el) {
|
||||
mode = $(mode_el).data('mode');
|
||||
|
||||
let $chartModeWrapper = $('#Endpoint-chart-mode');
|
||||
$chartModeWrapper.data('active-chart', mode);
|
||||
$chartModeWrapper.text($(mode_el).text());
|
||||
} else {
|
||||
mode = $('#Endpoint-chart-mode').data("active-chart");
|
||||
}
|
||||
|
||||
if (typeof(endpoints_statistics) !== 'undefined') {
|
||||
endpoints_statistics.destroy();
|
||||
}
|
||||
|
||||
$.get(admin_url + 'api/statistics/' + mode + "/" + encodeURIComponent(uri), function(response) {
|
||||
endpoints_statistics = new Chart($('#all-endpoints-chart'), {
|
||||
type: 'bar',
|
||||
data: response,
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
}
|
||||
}]
|
||||
},
|
||||
},
|
||||
});
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
update_apis_statistics($('[aria-labelledby="ApisChartMode"] [data-mode="hourly"]'));
|
||||
update_endpoints_statistics($('[aria-labelledby="EndpointsChartUri"] li:first-child a'));
|
||||
});
|
||||
</script>
|
||||
33
api/views/table.php
Normal file
33
api/views/table.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
$aColumns = [
|
||||
'name',
|
||||
];
|
||||
|
||||
$sIndexColumn = 'roleid';
|
||||
$sTable = db_prefix().'roles';
|
||||
|
||||
$result = data_tables_init($aColumns, $sIndexColumn, $sTable, [], [], ['roleid']);
|
||||
$output = $result['output'];
|
||||
$rResult = $result['rResult'];
|
||||
|
||||
foreach ($rResult as $aRow) {
|
||||
$row = [];
|
||||
for ($i = 0; $i < count($aColumns); $i++) {
|
||||
$_data = $aRow[$aColumns[$i]];
|
||||
if ($aColumns[$i] == 'name') {
|
||||
$_data = '<a href="' . admin_url('roles/role/' . $aRow['roleid']) . '" class="mbot10 display-block">' . $_data . '</a>';
|
||||
$_data .= '<span class="mtop10 display-block">' . _l('roles_total_users') . ' ' . total_rows(db_prefix().'staff', [
|
||||
'role' => $aRow['roleid'],
|
||||
]) . '</span>';
|
||||
}
|
||||
$row[] = $_data;
|
||||
}
|
||||
|
||||
$options = icon_btn('roles/role/' . $aRow['roleid'], 'pencil-square-o');
|
||||
$row[] = $options .= icon_btn('roles/delete/' . $aRow['roleid'], 'remove', 'btn-danger _delete');
|
||||
|
||||
$output['aaData'][] = $row;
|
||||
}
|
||||
280
api/views/user_stats.php
Normal file
280
api/views/user_stats.php
Normal file
@@ -0,0 +1,280 @@
|
||||
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
|
||||
|
||||
<?php init_head(); ?>
|
||||
|
||||
<link href="<?php echo base_url('modules/api/assets/main.css'); ?>" rel="stylesheet" type="text/css" />
|
||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||
|
||||
<div id="wrapper">
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h4 class="no-margin"><?php echo _l('user_statistics'); ?></h4>
|
||||
<hr class="hr-panel-heading" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="user_select" class="control-label"><?php echo _l('select_api_user'); ?></label>
|
||||
<select class="form-control" id="user_select" name="user_id">
|
||||
<option value=""><?php echo _l('select_api_user'); ?></option>
|
||||
<?php foreach ($api_users as $user) { ?>
|
||||
<option value="<?php echo $user['id']; ?>" <?php echo ($user_id == $user['id']) ? 'selected' : ''; ?>>
|
||||
<?php echo $user['name'] . ' (' . $user['user'] . ')'; ?>
|
||||
</option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label for="days_select" class="control-label"><?php echo _l('time_period'); ?></label>
|
||||
<select class="form-control" id="days_select" name="days">
|
||||
<option value="7"><?php echo _l('last_7_days'); ?></option>
|
||||
<option value="30" selected><?php echo _l('last_30_days'); ?></option>
|
||||
<option value="90"><?php echo _l('last_90_days'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label"> </label>
|
||||
<button type="button" id="load_stats" class="btn btn-primary btn-block"><?php echo _l('load_statistics'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="stats_content" style="display: none;">
|
||||
<!-- Quota Summary -->
|
||||
<div class="row" id="quota_summary">
|
||||
<div class="col-md-12">
|
||||
<h5><?php echo _l('quota_summary'); ?></h5>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body text-center">
|
||||
<h3 class="text-primary" id="total_requests">0</h3>
|
||||
<p class="text-muted"><?php echo _l('total_requests'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body text-center">
|
||||
<h3 class="text-success" id="success_requests">0</h3>
|
||||
<p class="text-muted"><?php echo _l('success_requests'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body text-center">
|
||||
<h3 class="text-danger" id="error_requests">0</h3>
|
||||
<p class="text-muted"><?php echo _l('error_requests'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel_s">
|
||||
<div class="panel-body text-center">
|
||||
<h3 class="text-info" id="avg_response_time">0ms</h3>
|
||||
<p class="text-muted"><?php echo _l('avg_response_time'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Usage Chart -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h5><?php echo _l('usage_over_time'); ?></h5>
|
||||
<div id="usage_chart" style="height: 300px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Endpoints -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h5><?php echo _l('top_endpoints'); ?></h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo _l('endpoint'); ?></th>
|
||||
<th><?php echo _l('request_count'); ?></th>
|
||||
<th><?php echo _l('success_count'); ?></th>
|
||||
<th><?php echo _l('error_count'); ?></th>
|
||||
<th><?php echo _l('avg_response_time'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="top_endpoints_table">
|
||||
<tr>
|
||||
<td colspan="5" class="text-center"><?php echo _l('no_data_available'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="no_user_selected" class="text-center" style="display: none;">
|
||||
<p class="text-muted"><?php echo _l('select_api_user_to_view_statistics'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php init_tail(); ?>
|
||||
|
||||
<script>
|
||||
// Ensure jQuery is available
|
||||
(function() {
|
||||
function initUserStats() {
|
||||
if (typeof jQuery === 'undefined') {
|
||||
console.error('jQuery is not loaded. Retrying in 100ms...');
|
||||
setTimeout(initUserStats, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery(document).ready(function($) {
|
||||
// Load stats if user is pre-selected
|
||||
<?php if ($user_id) { ?>
|
||||
loadUserStats();
|
||||
<?php } ?>
|
||||
|
||||
$('#load_stats').click(function() {
|
||||
loadUserStats();
|
||||
});
|
||||
|
||||
function loadUserStats() {
|
||||
var userId = $('#user_select').val();
|
||||
var days = $('#days_select').val();
|
||||
|
||||
if (!userId) {
|
||||
$('#stats_content').hide();
|
||||
$('#no_user_selected').show();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#no_user_selected').hide();
|
||||
$('#stats_content').show();
|
||||
|
||||
$.ajax({
|
||||
url: '<?php echo admin_url('api/get_user_stats_data'); ?>',
|
||||
type: 'POST',
|
||||
data: {
|
||||
user_id: userId,
|
||||
days: days
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.error) {
|
||||
alert('<?php echo _l('error_loading_statistics'); ?>');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update quota summary
|
||||
if (response.quota_summary) {
|
||||
$('#total_requests').text(response.quota_summary.total_requests || 0);
|
||||
$('#success_requests').text(response.quota_summary.success_requests || 0);
|
||||
$('#error_requests').text(response.quota_summary.error_requests || 0);
|
||||
$('#avg_response_time').text((response.quota_summary.avg_response_time || 0) + 'ms');
|
||||
}
|
||||
|
||||
// Update top endpoints table
|
||||
updateTopEndpointsTable(response.top_endpoints || []);
|
||||
|
||||
// Draw usage chart
|
||||
drawUsageChart(response.quota_stats || []);
|
||||
},
|
||||
error: function() {
|
||||
alert('<?php echo _l('error_loading_statistics'); ?>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopEndpointsTable(endpoints) {
|
||||
var tbody = $('#top_endpoints_table');
|
||||
tbody.empty();
|
||||
|
||||
if (endpoints.length === 0) {
|
||||
tbody.append('<tr><td colspan="5" class="text-center"><?php echo _l('no_data_available'); ?></td></tr>');
|
||||
return;
|
||||
}
|
||||
|
||||
endpoints.forEach(function(endpoint) {
|
||||
tbody.append(
|
||||
'<tr>' +
|
||||
'<td>' + endpoint.endpoint + '</td>' +
|
||||
'<td>' + endpoint.request_count + '</td>' +
|
||||
'<td>' + endpoint.success_count + '</td>' +
|
||||
'<td>' + endpoint.error_count + '</td>' +
|
||||
'<td>' + endpoint.avg_response_time + 'ms</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function drawUsageChart(stats) {
|
||||
if (typeof Highcharts === 'undefined') {
|
||||
console.log('Highcharts not loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
var categories = [];
|
||||
var requests = [];
|
||||
var errors = [];
|
||||
|
||||
stats.forEach(function(stat) {
|
||||
categories.push(stat.date);
|
||||
requests.push(parseInt(stat.request_count));
|
||||
errors.push(parseInt(stat.error_count));
|
||||
});
|
||||
|
||||
Highcharts.chart('usage_chart', {
|
||||
chart: {
|
||||
type: 'line'
|
||||
},
|
||||
title: {
|
||||
text: '<?php echo _l('usage_over_time'); ?>'
|
||||
},
|
||||
xAxis: {
|
||||
categories: categories
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: '<?php echo _l('request_count'); ?>'
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: '<?php echo _l('total_requests'); ?>',
|
||||
data: requests,
|
||||
color: '#1f77b4'
|
||||
}, {
|
||||
name: '<?php echo _l('error_requests'); ?>',
|
||||
data: errors,
|
||||
color: '#d62728'
|
||||
}]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Start the initialization
|
||||
initUserStats();
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script src="<?php echo base_url('modules/api/assets/main.js'); ?>"></script>
|
||||
Reference in New Issue
Block a user