mirror of
https://github.com/magicbug/Cloudlog
synced 2026-08-13 17:49:35 -04:00
Delete duplicate qso['lng'] assignments in application/controllers/Api.php. Longitude is stored in qso['long'], so removing the extra qso['lng'] assignments (from plot_latlng and dxcc fallback) avoids redundant/conflicting keys and keeps the QSO data consistent.
1632 lines
48 KiB
PHP
1632 lines
48 KiB
PHP
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
|
|
|
|
class API extends CI_Controller
|
|
{
|
|
|
|
// Do absolutely nothing
|
|
function index()
|
|
{
|
|
echo "nothing to see";
|
|
}
|
|
|
|
function help()
|
|
{
|
|
$this->load->model('user_model');
|
|
|
|
// Check if users logged in
|
|
|
|
if ($this->user_model->validate_session() == 0) {
|
|
// user is not logged in
|
|
redirect('user/login');
|
|
}
|
|
|
|
$this->load->model('api_model');
|
|
|
|
$data['api_keys'] = $this->api_model->keys();
|
|
|
|
$data['page_title'] = "API";
|
|
|
|
$this->load->view('interface_assets/header', $data);
|
|
$this->load->view('api/help');
|
|
$this->load->view('interface_assets/footer');
|
|
}
|
|
|
|
|
|
function edit($key)
|
|
{
|
|
$this->load->model('user_model');
|
|
|
|
// Check if users logged in
|
|
|
|
if ($this->user_model->validate_session() == 0) {
|
|
// user is not logged in
|
|
redirect('user/login');
|
|
}
|
|
|
|
$this->load->model('api_model');
|
|
|
|
$this->load->helper(array('form', 'url'));
|
|
|
|
$this->load->library('form_validation');
|
|
|
|
$this->form_validation->set_rules('api_desc', 'API Description', 'required');
|
|
$this->form_validation->set_rules('api_key', 'API Key is required do not change this field', 'required');
|
|
|
|
$data['api_info'] = $this->api_model->key_description($key);
|
|
|
|
if ($this->form_validation->run() == FALSE) {
|
|
$data['page_title'] = "Edit API Description";
|
|
|
|
$this->load->view('interface_assets/header', $data);
|
|
$this->load->view('api/description');
|
|
$this->load->view('interface_assets/footer');
|
|
} else {
|
|
// Success!
|
|
|
|
$this->api_model->update_key_description($this->input->post('api_key'), $this->input->post('api_desc'));
|
|
|
|
$this->session->set_flashdata('notice', 'API Key <b>' . $this->input->post('api_key') . "</b> description has been updated.");
|
|
|
|
redirect('api/help');
|
|
}
|
|
}
|
|
|
|
function generate($rights)
|
|
{
|
|
$this->load->model('user_model');
|
|
|
|
// Check if users logged in
|
|
|
|
if ($this->user_model->validate_session() == 0) {
|
|
// user is not logged in
|
|
redirect('user/login');
|
|
}
|
|
|
|
|
|
$this->load->model('api_model');
|
|
|
|
$data['api_keys'] = $this->api_model->generate_key($rights);
|
|
|
|
redirect('api/help');
|
|
}
|
|
|
|
function delete($key)
|
|
{
|
|
$this->load->model('user_model');
|
|
|
|
// Check if users logged in
|
|
|
|
if ($this->user_model->validate_session() == 0) {
|
|
// user is not logged in
|
|
redirect('user/login');
|
|
}
|
|
|
|
|
|
$this->load->model('api_model');
|
|
|
|
$this->api_model->delete_key($key);
|
|
|
|
$this->session->set_flashdata('notice', 'API Key <b>' . $key . "</b> has been deleted");
|
|
|
|
redirect('api/help');
|
|
}
|
|
|
|
// Example of authing
|
|
function auth($key)
|
|
{
|
|
$this->load->model('api_model');
|
|
header("Content-type: text/xml");
|
|
if ($this->api_model->access($key) == "No Key Found" || $this->api_model->access($key) == "Key Disabled") {
|
|
echo "<auth>";
|
|
echo "<message>Key Invalid - either not found or disabled</message>";
|
|
echo "</auth>";
|
|
} else {
|
|
echo "<auth>";
|
|
echo "<status>Valid</status>";
|
|
echo "<rights>" . $this->api_model->access($key) . "</rights>";
|
|
echo "</auth>";
|
|
}
|
|
}
|
|
|
|
function check_auth($key)
|
|
{
|
|
$this->load->model('api_model');
|
|
header("Content-type: text/xml");
|
|
if ($this->api_model->access($key) == "No Key Found" || $this->api_model->access($key) == "Key Disabled") {
|
|
// set the content type as json
|
|
header("Content-type: application/json");
|
|
|
|
// set the http response code to 401
|
|
http_response_code(401);
|
|
|
|
// return the json with the status as failed
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing or invalid api key"]);
|
|
} else {
|
|
// set the content type as json
|
|
header("Content-type: application/json");
|
|
|
|
// set the http response code to 200
|
|
http_response_code(200);
|
|
// return the json
|
|
echo json_encode(['status' => 'valid', 'rights' => $this->api_model->access($key)]);
|
|
}
|
|
}
|
|
|
|
function station_info($key)
|
|
{
|
|
$this->load->model('api_model');
|
|
$this->load->model('stations');
|
|
header("Content-type: application/json");
|
|
if (substr($this->api_model->access($key), 0, 1) == 'r') { /* Checkpermission for _r_eading */
|
|
$this->api_model->update_last_used($key);
|
|
$userid = $this->api_model->key_userid($key);
|
|
$station_ids = array();
|
|
$stations = $this->stations->all_of_user($userid);
|
|
foreach ($stations->result() as $row) {
|
|
$result['station_id'] = $row->station_id;
|
|
$result['station_profile_name'] = $row->station_profile_name;
|
|
$result['station_gridsquare'] = $row->station_gridsquare;
|
|
$result['station_callsign'] = $row->station_callsign;;
|
|
$result['station_active'] = $row->station_active;
|
|
array_push($station_ids, $result);
|
|
}
|
|
echo json_encode($station_ids);
|
|
} else {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing or invalid api key"]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get station logbooks that have public slugs for the API key owner.
|
|
* GET /api/logbook_public_slugs/{key}
|
|
*/
|
|
function logbook_public_slugs($key)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('logbooks_model');
|
|
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'missing or invalid api key']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
$query = $this->logbooks_model->public_slugs_by_user($user_id);
|
|
$logbooks = array();
|
|
|
|
foreach ($query->result() as $row) {
|
|
$logbooks[] = array(
|
|
'logbook_id' => (int)$row->logbook_id,
|
|
'logbook_name' => $row->logbook_name,
|
|
'public_slug' => $row->public_slug,
|
|
);
|
|
}
|
|
|
|
http_response_code(200);
|
|
echo json_encode(array(
|
|
'status' => 'success',
|
|
'count' => count($logbooks),
|
|
'logbooks' => $logbooks,
|
|
), JSON_PRETTY_PRINT);
|
|
}
|
|
|
|
/**
|
|
* Get all accessible station logbooks (owned + shared) that have public slugs for the API key owner.
|
|
* GET /api/logbook_public_slugs_accessible/{key}
|
|
*/
|
|
function logbook_public_slugs_accessible($key)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('logbooks_model');
|
|
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'missing or invalid api key']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
$query = $this->logbooks_model->public_slugs_accessible_by_user($user_id);
|
|
$logbooks = array();
|
|
|
|
foreach ($query->result() as $row) {
|
|
$logbooks[] = array(
|
|
'logbook_id' => (int)$row->logbook_id,
|
|
'logbook_name' => $row->logbook_name,
|
|
'public_slug' => $row->public_slug,
|
|
'access_level' => $row->access_level,
|
|
);
|
|
}
|
|
|
|
http_response_code(200);
|
|
echo json_encode(array(
|
|
'status' => 'success',
|
|
'count' => count($logbooks),
|
|
'logbooks' => $logbooks,
|
|
), JSON_PRETTY_PRINT);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Function: QSO
|
|
* Task: allows passing of ADIF data to Cloudlog
|
|
*/
|
|
function qso()
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
|
|
$this->load->model('stations');
|
|
|
|
$return_msg = array();
|
|
$return_count = 0;
|
|
|
|
// Decode JSON and store
|
|
$obj = json_decode(file_get_contents("php://input"), true);
|
|
if ($obj === NULL) {
|
|
// Decoding not valid try simple www-x-form-urlencoded
|
|
$objTmp = file_get_contents("php://input");
|
|
parse_str($objTmp, $obj);
|
|
if ($obj === NULL) {
|
|
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
|
|
die();
|
|
}
|
|
}
|
|
|
|
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
|
|
die();
|
|
}
|
|
|
|
$userid = $this->api_model->key_userid($obj['key']);
|
|
|
|
if (!isset($obj['station_profile_id']) || $this->stations->check_station_against_user($obj['station_profile_id'], $userid) == false) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "station id does not belong to the API key owner."]);
|
|
die();
|
|
}
|
|
|
|
if ($obj['type'] == "adif" && $obj['string'] != "") {
|
|
// Load the logbook model for adding QSO records
|
|
$this->load->model('logbook_model');
|
|
|
|
// Load ADIF Parser
|
|
$this->load->library('adif_parser');
|
|
|
|
// Feed in the ADIF string
|
|
$this->adif_parser->feed($obj['string']);
|
|
|
|
// Create QSO Record
|
|
while ($record = $this->adif_parser->get_record()) {
|
|
if (count($record) == 0) {
|
|
break;
|
|
};
|
|
|
|
|
|
if (isset($obj['station_profile_id'])) {
|
|
if (isset($record['station_callsign']) && $this->stations->check_station_against_callsign($obj['station_profile_id'], $record['station_callsign']) == false) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "station callsign does not match station callsign in station profile."]);
|
|
die();
|
|
}
|
|
|
|
if (!(isset($record['call'])) || (trim($record['call']) == '')) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "QSO Call is empty."]);
|
|
die();
|
|
}
|
|
|
|
$this->api_model->update_last_used($obj['key']);
|
|
|
|
$msg = $this->logbook_model->import($record, $obj['station_profile_id'], NULL, NULL, NULL, NULL, NULL, NULL, false, false, true);
|
|
|
|
if ($msg == "") {
|
|
$return_count++;
|
|
} else {
|
|
$return_msg[] = $msg;
|
|
}
|
|
}
|
|
};
|
|
http_response_code(201);
|
|
echo json_encode(['status' => 'created', 'type' => $obj['type'], 'string' => $obj['string'], 'imported_count' => $return_count, 'messages' => $return_msg]);
|
|
}
|
|
}
|
|
|
|
// API function to check if a callsign is in the logbook already
|
|
function logbook_check_callsign()
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
|
|
// Decode JSON and store
|
|
$obj = json_decode(file_get_contents("php://input"), true);
|
|
if ($obj === NULL) {
|
|
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
|
|
return;
|
|
}
|
|
|
|
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
|
|
return;
|
|
}
|
|
|
|
if (!isset($obj['logbook_public_slug']) || !isset($obj['callsign'])) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
|
|
return;
|
|
}
|
|
|
|
if ($obj['logbook_public_slug'] != "" && $obj['callsign'] != "") {
|
|
|
|
$logbook_slug = $obj['logbook_public_slug'];
|
|
$callsign = $obj['callsign'];
|
|
|
|
// If $obj['band'] exists
|
|
if (isset($obj['band'])) {
|
|
$band = $obj['band'];
|
|
} else {
|
|
$band = null;
|
|
}
|
|
|
|
$this->load->model('logbooks_model');
|
|
|
|
if ($this->logbooks_model->public_slug_exists($logbook_slug)) {
|
|
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
|
|
if ($logbook_id != false) {
|
|
// Get associated station locations for mysql queries
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
|
|
|
|
if (!$logbooks_locations_array) {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
|
|
die();
|
|
}
|
|
} else {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug . " has no associated station locations"]);
|
|
die();
|
|
}
|
|
// Search Logbook for callsign
|
|
$this->load->model('logbook_model');
|
|
|
|
$result = $this->logbook_model->check_if_callsign_worked_in_logbook($callsign, $logbooks_locations_array, $band);
|
|
|
|
http_response_code(201);
|
|
if ($result > 0) {
|
|
echo json_encode(['callsign' => $callsign, 'result' => 'Found']);
|
|
} else {
|
|
echo json_encode(['callsign' => $callsign, 'result' => 'Not Found']);
|
|
}
|
|
} else {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
|
|
die();
|
|
}
|
|
}
|
|
}
|
|
|
|
// API function to check if a grid is in the logbook already
|
|
function logbook_check_grid()
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
|
|
// Decode JSON and store
|
|
$obj = json_decode(file_get_contents("php://input"), true);
|
|
if ($obj === NULL) {
|
|
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
|
|
}
|
|
|
|
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
|
|
}
|
|
|
|
if (!isset($obj['logbook_public_slug']) || !isset($obj['grid'])) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
|
|
return;
|
|
}
|
|
|
|
if ($obj['logbook_public_slug'] != "" && $obj['grid'] != "") {
|
|
|
|
$logbook_slug = $obj['logbook_public_slug'];
|
|
$grid = $obj['grid'];
|
|
|
|
// If $obj['band'] exists
|
|
if (isset($obj['band'])) {
|
|
$band = $obj['band'];
|
|
} else {
|
|
$band = null;
|
|
}
|
|
|
|
$this->load->model('logbooks_model');
|
|
|
|
if ($this->logbooks_model->public_slug_exists($logbook_slug)) {
|
|
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
|
|
if ($logbook_id != false) {
|
|
// Get associated station locations for mysql queries
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
|
|
|
|
if (!$logbooks_locations_array) {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
|
|
die();
|
|
}
|
|
} else {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug . " has no associated station locations"]);
|
|
die();
|
|
}
|
|
// Search Logbook for callsign
|
|
$this->load->model('logbook_model');
|
|
|
|
$result = $this->logbook_model->check_if_grid_worked_in_logbook($grid, $logbooks_locations_array, $band);
|
|
|
|
http_response_code(201);
|
|
if ($result > 0) {
|
|
echo json_encode(['gridsquare' => strtoupper($grid), 'result' => 'Found']);
|
|
} else {
|
|
echo json_encode(['gridsquare' => strtoupper($grid), 'result' => 'Not Found']);
|
|
}
|
|
} else {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
|
|
die();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if a country has been worked before and confirmed in various ways
|
|
*
|
|
* This API endpoint checks if a specific country (derived from callsign) has been
|
|
* worked before in a given logbook, and whether it has been confirmed via different
|
|
* confirmation methods (QSL, LoTW, eQSL, QRZ).
|
|
*
|
|
* @api POST /api/logbook_check_country
|
|
* @header Content-Type application/json
|
|
*
|
|
* @param string key Required. API authentication key
|
|
* @param string logbook_public_slug Required. Public slug identifier for the logbook
|
|
* @param string callsign Required. Callsign to lookup country for
|
|
* @param string type Optional. Type of contact ("sat" for satellite, empty for regular)
|
|
* @param string band Optional. Amateur radio band (required for non-satellite contacts)
|
|
* @param string mode Optional. Amateur radio mode (required for non-satellite contacts)
|
|
*
|
|
* @return json Returns JSON object with:
|
|
* - workedBefore: boolean indicating if country was worked before
|
|
* - confirmed: object with confirmation status for qsl, lotw, eqsl, qrz
|
|
*
|
|
* @throws 401 Unauthorized - Missing or invalid API key, missing required fields
|
|
* @throws 404 Not Found - Logbook not found or empty logbook
|
|
* @throws 400 Bad Request - Invalid JSON format
|
|
*
|
|
* @example
|
|
* Request:
|
|
* {
|
|
* "key": "your-api-key",
|
|
* "logbook_public_slug": "my-logbook",
|
|
* "callsign": "W1AW",
|
|
* "band": "20M",
|
|
* "mode": "SSB"
|
|
* }
|
|
*
|
|
* Response:
|
|
* {
|
|
* "workedBefore": true,
|
|
* "confirmed": {
|
|
* "qsl": true,
|
|
* "lotw": false,
|
|
* "eqsl": false,
|
|
* "qrz": false
|
|
* }
|
|
* }
|
|
*/
|
|
function logbook_check_country()
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
|
|
// Decode JSON and store
|
|
$obj = json_decode(file_get_contents("php://input"), true);
|
|
if ($obj === NULL) {
|
|
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
|
|
return;
|
|
}
|
|
|
|
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
|
|
return;
|
|
}
|
|
|
|
if (!isset($obj['logbook_public_slug']) || !isset($obj['callsign'])) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
|
|
return;
|
|
}
|
|
|
|
// Load models
|
|
$this->load->model('logbook_model');
|
|
$this->load->model('logbooks_model');
|
|
|
|
$date = date("Y-m-d");
|
|
$callsign = $obj['callsign'];
|
|
$logbook_slug = $obj['logbook_public_slug'];
|
|
$type = isset($obj['type']) ? $obj['type'] : '';
|
|
$band = isset($obj['band']) ? $obj['band'] : '';
|
|
$mode = isset($obj['mode']) ? $obj['mode'] : '';
|
|
|
|
$callsign_dxcc_lookup = $this->logbook_model->dxcc_lookup($callsign, $date);
|
|
$country = $callsign_dxcc_lookup['entity'];
|
|
|
|
$return = [
|
|
"workedBefore" => false,
|
|
"confirmed" => [
|
|
"qsl" => false,
|
|
"lotw" => false,
|
|
"eqsl" => false,
|
|
"qrz" => false
|
|
]
|
|
];
|
|
|
|
if ($this->logbooks_model->public_slug_exists($logbook_slug)) {
|
|
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
|
|
if ($logbook_id != false) {
|
|
// Get associated station locations for mysql queries
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
|
|
|
|
if (!$logbooks_locations_array) {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
|
|
die();
|
|
}
|
|
} else {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug . " has no associated station locations"]);
|
|
die();
|
|
}
|
|
|
|
if (!empty($logbooks_locations_array)) {
|
|
if ($type == "sat") {
|
|
$this->db->where('COL_PROP_MODE', 'SAT');
|
|
} else {
|
|
$this->db->where('COL_MODE', $this->logbook_model->get_main_mode_from_mode($mode));
|
|
$this->db->where('COL_BAND', $band);
|
|
$this->db->where('COL_PROP_MODE !=', 'SAT');
|
|
}
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_COUNTRY', urldecode($country));
|
|
|
|
$query = $this->db->get($this->config->item('table_name'), 1, 0);
|
|
foreach ($query->result() as $workedBeforeRow) {
|
|
$return['workedBefore'] = true;
|
|
}
|
|
|
|
// Check each confirmation type separately
|
|
$confirmation_types = [
|
|
'qsl' => "COL_QSL_RCVD='Y'",
|
|
'lotw' => "COL_LOTW_QSL_RCVD='Y'",
|
|
'eqsl' => "COL_EQSL_QSL_RCVD='Y'",
|
|
'qrz' => "COL_QRZCOM_QSO_DOWNLOAD_STATUS='Y'"
|
|
];
|
|
|
|
foreach ($confirmation_types as $type_key => $where_clause) {
|
|
if ($type == "SAT") {
|
|
$this->db->where('COL_PROP_MODE', 'SAT');
|
|
} else {
|
|
$this->db->where('COL_MODE', $this->logbook_model->get_main_mode_from_mode($mode));
|
|
$this->db->where('COL_BAND', $band);
|
|
$this->db->where('COL_PROP_MODE !=', 'SAT');
|
|
}
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_COUNTRY', urldecode($country));
|
|
$this->db->where($where_clause);
|
|
|
|
$query = $this->db->get($this->config->item('table_name'), 1, 0);
|
|
|
|
if ($query->num_rows() > 0) {
|
|
$return['confirmed'][$type_key] = true;
|
|
}
|
|
}
|
|
|
|
http_response_code(201);
|
|
echo json_encode($return, JSON_PRETTY_PRINT);
|
|
} else {
|
|
http_response_code(201);
|
|
echo json_encode($return, JSON_PRETTY_PRINT);
|
|
}
|
|
} else {
|
|
// Logbook not found
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
|
|
die();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check worked and confirmation status for callsign and country.
|
|
*
|
|
* @api POST /api/logbook_worked_status
|
|
* @header Content-Type application/json
|
|
*
|
|
* Required fields:
|
|
* - key
|
|
* - logbook_public_slug
|
|
* - callsign
|
|
*
|
|
* Optional fields:
|
|
* - band
|
|
* - mode
|
|
* - gridsquare
|
|
*/
|
|
function logbook_worked_status()
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
|
|
$obj = json_decode(file_get_contents("php://input"), true);
|
|
if ($obj === NULL) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failed', 'reason' => "wrong JSON"]);
|
|
return;
|
|
}
|
|
|
|
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
|
|
return;
|
|
}
|
|
|
|
if (!isset($obj['logbook_public_slug']) || !isset($obj['callsign'])) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing fields"]);
|
|
return;
|
|
}
|
|
|
|
$this->load->model('logbook_model');
|
|
$this->load->model('logbooks_model');
|
|
|
|
$logbook_slug = trim($obj['logbook_public_slug']);
|
|
$callsign = strtoupper(trim($obj['callsign']));
|
|
$band = isset($obj['band']) && trim($obj['band']) !== '' ? strtoupper(trim($obj['band'])) : null;
|
|
$mode = isset($obj['mode']) && trim($obj['mode']) !== '' ? strtoupper(trim($obj['mode'])) : null;
|
|
$gridsquare = isset($obj['gridsquare']) && trim($obj['gridsquare']) !== '' ? strtoupper(trim($obj['gridsquare'])) : null;
|
|
|
|
$date = date("Y-m-d");
|
|
$callsign_dxcc_lookup = $this->logbook_model->dxcc_lookup($callsign, $date);
|
|
$country = isset($callsign_dxcc_lookup['entity']) ? $callsign_dxcc_lookup['entity'] : '';
|
|
|
|
if (!$this->logbooks_model->public_slug_exists($logbook_slug)) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "logbook not found"]);
|
|
return;
|
|
}
|
|
|
|
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($logbook_slug);
|
|
if ($logbook_id == false) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => $logbook_slug . " has no associated station locations"]);
|
|
return;
|
|
}
|
|
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
|
|
if (!$logbooks_locations_array) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => "Empty Logbook"]);
|
|
return;
|
|
}
|
|
|
|
$return = [
|
|
'callsign' => $callsign,
|
|
'country' => $country,
|
|
'band' => $band,
|
|
'mode' => $mode,
|
|
'gridsquare' => $gridsquare,
|
|
'worked' => [
|
|
'callsign_overall' => false,
|
|
'callsign_band' => $band !== null ? false : null,
|
|
'country_overall' => false,
|
|
'country_band' => $band !== null ? false : null,
|
|
'grid_overall' => $gridsquare !== null ? false : null,
|
|
'grid_band' => ($gridsquare !== null && $band !== null) ? false : null,
|
|
],
|
|
'confirmed' => [
|
|
'callsign' => [
|
|
'lotw' => false,
|
|
'qsl' => false,
|
|
'any' => false,
|
|
],
|
|
'country' => [
|
|
'lotw' => false,
|
|
'qsl' => false,
|
|
'any' => false,
|
|
],
|
|
],
|
|
];
|
|
|
|
$table_name = $this->config->item('table_name');
|
|
$main_mode = $mode !== null ? $this->logbook_model->get_main_mode_from_mode($mode) : null;
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_CALL', $callsign);
|
|
$callsign_overall_query = $this->db->get($table_name, 1, 0);
|
|
$return['worked']['callsign_overall'] = $callsign_overall_query->num_rows() > 0;
|
|
|
|
if ($band !== null) {
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_CALL', $callsign);
|
|
$this->db->where('COL_BAND', $band);
|
|
if ($main_mode !== null) {
|
|
$this->db->where('COL_MODE', $main_mode);
|
|
}
|
|
$callsign_band_query = $this->db->get($table_name, 1, 0);
|
|
$return['worked']['callsign_band'] = $callsign_band_query->num_rows() > 0;
|
|
}
|
|
|
|
if ($country !== '') {
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_COUNTRY', urldecode($country));
|
|
$country_overall_query = $this->db->get($table_name, 1, 0);
|
|
$return['worked']['country_overall'] = $country_overall_query->num_rows() > 0;
|
|
|
|
if ($band !== null) {
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_COUNTRY', urldecode($country));
|
|
$this->db->where('COL_BAND', $band);
|
|
if ($main_mode !== null) {
|
|
$this->db->where('COL_MODE', $main_mode);
|
|
}
|
|
$country_band_query = $this->db->get($table_name, 1, 0);
|
|
$return['worked']['country_band'] = $country_band_query->num_rows() > 0;
|
|
}
|
|
}
|
|
|
|
if ($gridsquare !== null) {
|
|
$grid_overall_result = $this->logbook_model->check_if_grid_worked_in_logbook($gridsquare, $logbooks_locations_array, null);
|
|
$return['worked']['grid_overall'] = $grid_overall_result > 0;
|
|
|
|
if ($band !== null) {
|
|
$grid_band_result = $this->logbook_model->check_if_grid_worked_in_logbook($gridsquare, $logbooks_locations_array, $band);
|
|
$return['worked']['grid_band'] = $grid_band_result > 0;
|
|
}
|
|
}
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_CALL', $callsign);
|
|
$this->db->where("COL_LOTW_QSL_RCVD='Y'");
|
|
$callsign_lotw_query = $this->db->get($table_name, 1, 0);
|
|
$return['confirmed']['callsign']['lotw'] = $callsign_lotw_query->num_rows() > 0;
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_CALL', $callsign);
|
|
$this->db->where("COL_QSL_RCVD='Y'");
|
|
$callsign_qsl_query = $this->db->get($table_name, 1, 0);
|
|
$return['confirmed']['callsign']['qsl'] = $callsign_qsl_query->num_rows() > 0;
|
|
$return['confirmed']['callsign']['any'] = $return['confirmed']['callsign']['lotw'] || $return['confirmed']['callsign']['qsl'];
|
|
|
|
if ($country !== '') {
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_COUNTRY', urldecode($country));
|
|
$this->db->where("COL_LOTW_QSL_RCVD='Y'");
|
|
$country_lotw_query = $this->db->get($table_name, 1, 0);
|
|
$return['confirmed']['country']['lotw'] = $country_lotw_query->num_rows() > 0;
|
|
|
|
$this->db->where_in('station_id', $logbooks_locations_array);
|
|
$this->db->where('COL_COUNTRY', urldecode($country));
|
|
$this->db->where("COL_QSL_RCVD='Y'");
|
|
$country_qsl_query = $this->db->get($table_name, 1, 0);
|
|
$return['confirmed']['country']['qsl'] = $country_qsl_query->num_rows() > 0;
|
|
$return['confirmed']['country']['any'] = $return['confirmed']['country']['lotw'] || $return['confirmed']['country']['qsl'];
|
|
}
|
|
|
|
http_response_code(200);
|
|
echo json_encode($return, JSON_PRETTY_PRINT);
|
|
}
|
|
|
|
/* ENDPOINT for Rig Control */
|
|
|
|
function radio()
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
|
|
//$json = '{"radio":"FT-950","frequency":14075,"mode":"SSB","timestamp":"2012/04/07 16:47"}';
|
|
|
|
$this->load->model('cat');
|
|
|
|
//var_dump(file_get_contents("php://input"), true);
|
|
|
|
// Decode JSON and store
|
|
$obj = json_decode(file_get_contents("php://input"), true);
|
|
|
|
if (!isset($obj['key']) || $this->api_model->authorize($obj['key']) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => "missing api key"]);
|
|
die();
|
|
}
|
|
|
|
$this->api_model->update_last_used($obj['key']);
|
|
|
|
$user_id = $this->api_model->key_userid($obj['key']);
|
|
|
|
// Store Result to Database
|
|
$this->cat->update($obj, $user_id);
|
|
|
|
// Return Message
|
|
|
|
$arr = array('status' => 'success');
|
|
|
|
echo json_encode($arr);
|
|
}
|
|
|
|
/*
|
|
* Radio Commands API Functions for Aurora Desktop App
|
|
*/
|
|
|
|
/**
|
|
* Get pending radio commands
|
|
* GET /api/radio_commands_pending/{key}
|
|
* GET /api/radio_commands_pending_by_name/{key}/{radio_name}
|
|
*/
|
|
function radio_commands_pending($key, $radio_id = null)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
if ($radio_id) {
|
|
// Get commands for specific radio by ID
|
|
$commands = $this->cat->get_pending_commands($radio_id, $user_id);
|
|
} else {
|
|
// Get all pending commands for user
|
|
$commands = $this->cat->get_all_pending_commands($user_id);
|
|
}
|
|
|
|
// Debug information
|
|
$debug_info = array(
|
|
'user_id' => $user_id,
|
|
'radio_id' => $radio_id,
|
|
'current_time' => date('Y-m-d H:i:s'),
|
|
'total_commands_in_db' => $this->db->where('user_id', $user_id)->count_all_results('radio_commands'),
|
|
'pending_commands_in_db' => $this->db->where('user_id', $user_id)->where('status', 'PENDING')->count_all_results('radio_commands')
|
|
);
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'commands' => $commands,
|
|
'count' => count($commands),
|
|
'debug' => $debug_info
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get pending radio commands by radio name (for Aurora)
|
|
* GET /api/radio_commands_pending_by_name/{key}/{radio_name}
|
|
*/
|
|
function radio_commands_pending_by_name($key, $radio_name = null)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
// Clean up expired commands for this user
|
|
$cleaned = $this->cat->cleanup_expired_commands($user_id);
|
|
|
|
if ($radio_name) {
|
|
// URL decode the radio name in case it has spaces/special chars
|
|
$decoded_radio_name = urldecode($radio_name);
|
|
|
|
// Additional cleanup - remove any extra whitespace
|
|
$decoded_radio_name = trim($decoded_radio_name);
|
|
|
|
// Debug: Check if radio exists in cat table for this user
|
|
$radio_check = $this->db->select('id, radio, user_id')
|
|
->where('radio', $decoded_radio_name)
|
|
->where('user_id', $user_id)
|
|
->get('cat');
|
|
|
|
// Debug: Check all radios for this user
|
|
$all_user_radios = $this->db->select('id, radio')
|
|
->where('user_id', $user_id)
|
|
->get('cat');
|
|
|
|
// Debug: Check if any commands exist for this user
|
|
$all_commands = $this->db->select('id, radio_id, radio_name, command_type, status, created_at, expires_at')
|
|
->where('user_id', $user_id)
|
|
->get('radio_commands');
|
|
|
|
// Get commands for specific radio by name
|
|
$commands = $this->cat->get_pending_commands_by_name($decoded_radio_name, $user_id);
|
|
|
|
$debug_info = array(
|
|
'user_id' => $user_id,
|
|
'decoded_radio_name' => $decoded_radio_name,
|
|
'radio_found_in_cat' => $radio_check->num_rows() > 0,
|
|
'radio_details' => $radio_check->num_rows() > 0 ? $radio_check->row_array() : null,
|
|
'all_user_radios' => $all_user_radios->result_array(),
|
|
'all_user_commands' => $all_commands->result_array(),
|
|
'current_time' => date('Y-m-d H:i:s')
|
|
);
|
|
} else {
|
|
// Get all pending commands for user
|
|
$commands = $this->cat->get_all_pending_commands($user_id);
|
|
$decoded_radio_name = null;
|
|
$debug_info = array('user_id' => $user_id);
|
|
}
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'commands' => $commands,
|
|
'count' => count($commands),
|
|
'radio_name' => $decoded_radio_name,
|
|
'original_param' => $radio_name,
|
|
'expired_cleaned' => $cleaned
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Update radio command status
|
|
* POST /api/radio_commands/update_status/{key}
|
|
* Body: {"command_id": 123, "status": "COMPLETED", "error_message": "optional"}
|
|
*/
|
|
function radio_commands_update_status($key)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
// Get JSON input
|
|
$input = json_decode(file_get_contents("php://input"), true);
|
|
|
|
if (!isset($input['command_id']) || !isset($input['status'])) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'missing command_id or status']);
|
|
return;
|
|
}
|
|
|
|
$command_id = $input['command_id'];
|
|
$status = $input['status'];
|
|
$error_message = isset($input['error_message']) ? $input['error_message'] : null;
|
|
|
|
// Validate status
|
|
$valid_statuses = ['PROCESSING', 'COMPLETED', 'FAILED'];
|
|
if (!in_array($status, $valid_statuses)) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'invalid status']);
|
|
return;
|
|
}
|
|
|
|
// Verify command belongs to user
|
|
$command = $this->cat->get_command($command_id, $user_id);
|
|
if (!$command) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'command not found']);
|
|
return;
|
|
}
|
|
|
|
// Update command status
|
|
$result = $this->cat->update_command_status($command_id, $status, $error_message);
|
|
|
|
if ($result) {
|
|
echo json_encode(['status' => 'success', 'updated' => true]);
|
|
} else {
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'update failed']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get radio command by ID
|
|
* GET /api/radio_commands/get/{key}/{command_id}
|
|
*/
|
|
function radio_commands_get($key, $command_id)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
$command = $this->cat->get_command($command_id, $user_id);
|
|
|
|
if ($command) {
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'command' => $command
|
|
]);
|
|
} else {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'command not found']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Queue a new radio command (for testing or external apps)
|
|
* POST /api/radio_commands_queue/{key}
|
|
* Body: {"radio_id": 1, "command_type": "SET_FREQ", "frequency": 14074000, "mode": "USB"}
|
|
* OR: {"radio_name": "FT-991A", "command_type": "SET_FREQ", "frequency": 14074000, "mode": "USB"}
|
|
*/
|
|
function radio_commands_queue($key)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
// Get JSON input
|
|
$input = json_decode(file_get_contents("php://input"), true);
|
|
|
|
if (!isset($input['command_type'])) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'missing command_type']);
|
|
return;
|
|
}
|
|
|
|
$radio_id = null;
|
|
|
|
// Check if radio_name is provided instead of radio_id
|
|
if (isset($input['radio_name'])) {
|
|
// Get radio ID from radio name
|
|
$radio_query = $this->db->select('id')
|
|
->where('radio', $input['radio_name'])
|
|
->where('user_id', $user_id)
|
|
->get('cat');
|
|
|
|
if ($radio_query->num_rows() == 0) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'radio not found']);
|
|
return;
|
|
}
|
|
|
|
$radio_id = $radio_query->row()->id;
|
|
|
|
} elseif (isset($input['radio_id'])) {
|
|
$radio_id = $input['radio_id'];
|
|
} else {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'missing radio_id or radio_name']);
|
|
return;
|
|
}
|
|
|
|
// Prepare command data
|
|
$command_data = array(
|
|
'radio_id' => $radio_id,
|
|
'user_id' => $user_id,
|
|
'command_type' => $input['command_type'],
|
|
'expires_at' => date('Y-m-d H:i:s', strtotime('+30 minutes'))
|
|
);
|
|
|
|
// Add optional parameters
|
|
if (isset($input['frequency'])) $command_data['frequency'] = $input['frequency'];
|
|
if (isset($input['mode'])) $command_data['mode'] = $input['mode'];
|
|
if (isset($input['vfo'])) $command_data['vfo'] = $input['vfo'];
|
|
if (isset($input['power'])) $command_data['power'] = $input['power'];
|
|
if (isset($input['station_id'])) $command_data['station_id'] = $input['station_id'];
|
|
|
|
$command_id = $this->cat->queue_command($command_data);
|
|
|
|
if ($command_id) {
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'command_id' => $command_id,
|
|
'message' => 'Command queued successfully'
|
|
]);
|
|
} else {
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'failed to queue command']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all pending radio commands for all user's radios (optimized for Aurora)
|
|
* GET /api/radio_commands_all_pending/{key}
|
|
*/
|
|
function radio_commands_all_pending($key)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
// Clean up expired commands for this user
|
|
$cleaned = $this->cat->cleanup_expired_commands($user_id);
|
|
|
|
// Get all pending commands for all user's radios
|
|
$commands = $this->cat->get_all_pending_commands($user_id);
|
|
|
|
// Group commands by radio for easier processing
|
|
$commands_by_radio = array();
|
|
$radio_names = array();
|
|
|
|
foreach ($commands as $command) {
|
|
$radio_name = $command['radio_name'];
|
|
if (!isset($commands_by_radio[$radio_name])) {
|
|
$commands_by_radio[$radio_name] = array();
|
|
$radio_names[] = $radio_name;
|
|
}
|
|
$commands_by_radio[$radio_name][] = $command;
|
|
}
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'commands' => $commands,
|
|
'commands_by_radio' => $commands_by_radio,
|
|
'radio_names' => $radio_names,
|
|
'total_commands' => count($commands),
|
|
'radios_with_commands' => count($commands_by_radio),
|
|
'expired_cleaned' => $cleaned,
|
|
'timestamp' => date('Y-m-d H:i:s')
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Cleanup expired radio commands (maintenance endpoint)
|
|
* POST /api/radio_commands_cleanup/{key}
|
|
* Body: {"cleanup_old": true, "days_old": 7} (optional parameters)
|
|
*/
|
|
function radio_commands_cleanup($key)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
$this->load->model('api_model');
|
|
$this->load->model('cat');
|
|
|
|
// Check API key
|
|
if (!$key || $this->api_model->authorize($key) == 0) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'unauthorized']);
|
|
return;
|
|
}
|
|
|
|
$this->api_model->update_last_used($key);
|
|
$user_id = $this->api_model->key_userid($key);
|
|
|
|
// Get optional JSON input
|
|
$input = json_decode(file_get_contents("php://input"), true);
|
|
$cleanup_old = isset($input['cleanup_old']) ? $input['cleanup_old'] : false;
|
|
$days_old = isset($input['days_old']) ? intval($input['days_old']) : 7;
|
|
|
|
// Clean up expired commands
|
|
$expired_cleaned = $this->cat->cleanup_expired_commands($user_id);
|
|
|
|
$old_cleaned = 0;
|
|
if ($cleanup_old) {
|
|
$old_cleaned = $this->cat->cleanup_old_commands($days_old, $user_id);
|
|
}
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'expired_commands_cleaned' => $expired_cleaned,
|
|
'old_commands_cleaned' => $old_cleaned,
|
|
'cleanup_old_enabled' => $cleanup_old,
|
|
'days_old_threshold' => $days_old,
|
|
'timestamp' => date('Y-m-d H:i:s')
|
|
]);
|
|
}
|
|
|
|
/*
|
|
*
|
|
* Stats API function calls
|
|
*
|
|
*/
|
|
|
|
function statistics($key = null)
|
|
{
|
|
header('Content-type: application/json');
|
|
$this->load->model('logbook_model');
|
|
|
|
$data['todays_qsos'] = $this->logbook_model->todays_qsos(null, $key);
|
|
$data['total_qsos'] = $this->logbook_model->total_qsos(null, $key);
|
|
$data['month_qsos'] = $this->logbook_model->month_qsos(null, $key);
|
|
$data['year_qsos'] = $this->logbook_model->year_qsos(null, $key);
|
|
|
|
http_response_code(201);
|
|
echo json_encode(['Today' => $data['todays_qsos'], 'total_qsos' => $data['total_qsos'], 'month_qsos' => $data['month_qsos'], 'year_qsos' => $data['year_qsos']]);
|
|
}
|
|
|
|
function lookup()
|
|
{
|
|
// start benchmarking
|
|
$this->output->enable_profiler(TRUE);
|
|
/*
|
|
*
|
|
* Callsign lookup function for Cloudlogs logging page or thirdparty systems
|
|
* which want to show previous QSO data on their system.
|
|
*
|
|
* TODO
|
|
* - Local data make one database call ONLY
|
|
* - Add eQSL status
|
|
* - Add Callbook returned data
|
|
* - Add QSO before data array
|
|
* - Add options for checking based on band/mode/sat
|
|
*
|
|
*/
|
|
|
|
|
|
// Make sure users logged in
|
|
$this->load->model('user_model');
|
|
if (!$this->user_model->authorize($this->config->item('auth_mode'))) {
|
|
return;
|
|
}
|
|
|
|
|
|
$this->load->model("logbook_model");
|
|
$date = date("Y-m-d");
|
|
|
|
// Return Array
|
|
$return = [
|
|
"callsign" => "",
|
|
"dxcc" => false,
|
|
"dxcc_lat" => "",
|
|
"dxcc_long" => "",
|
|
"dxcc_cqz" => "",
|
|
"name" => "",
|
|
"gridsquare" => "",
|
|
"location" => "",
|
|
"iota_ref" => "",
|
|
"state" => "",
|
|
"us_county" => "",
|
|
"qsl_manager" => "",
|
|
"bearing" => "",
|
|
"workedBefore" => false,
|
|
"lotw_member" => false,
|
|
"suffix_slash" => "", // Suffix Slash aka Portable
|
|
];
|
|
|
|
|
|
/*
|
|
*
|
|
* Handle POST data being sent to check lookups
|
|
*
|
|
*/
|
|
$raw_input = json_decode(file_get_contents("php://input"), true);
|
|
|
|
$lookup_callsign = strtoupper($raw_input['callsign']);
|
|
|
|
|
|
/*
|
|
*
|
|
* Handle Callsign field
|
|
*
|
|
*/
|
|
$return['callsign'] = $lookup_callsign;
|
|
|
|
/*
|
|
*
|
|
* Lookup DXCC and Suffix information
|
|
*
|
|
*/
|
|
|
|
$callsign_dxcc_lookup = $this->logbook_model->dxcc_lookup($lookup_callsign, $date);
|
|
|
|
$last_slash_pos = strrpos($lookup_callsign, '/');
|
|
|
|
if (isset($last_slash_pos) && $last_slash_pos > 4) {
|
|
$suffix_slash = $last_slash_pos === false ? $lookup_callsign : substr($lookup_callsign, $last_slash_pos + 1);
|
|
switch ($suffix_slash) {
|
|
case "P":
|
|
$suffix_slash_item = "Portable";
|
|
break;
|
|
case "M":
|
|
$suffix_slash_item = "Mobile";
|
|
case "MM":
|
|
$suffix_slash_item = "Maritime Mobile";
|
|
break;
|
|
default:
|
|
// If its not one of the above suffix slashes its likely dxcc
|
|
$ans2 = $this->logbook_model->dxcc_lookup($suffix_slash, $date);
|
|
$suffix_slash_item = null;
|
|
}
|
|
|
|
$return['suffix_slash'] = $suffix_slash_item;
|
|
}
|
|
|
|
// If the final slash is a DXCC then find it!
|
|
if (isset($ans2['call'])) {
|
|
$return['dxcc'] = $ans2['entity'];
|
|
$return['dxcc_lat'] = $ans2['lat'];
|
|
$return['dxcc_long'] = $ans2['long'];
|
|
$return['dxcc_cqz'] = $ans2['cqz'];
|
|
} else {
|
|
$return['dxcc'] = $callsign_dxcc_lookup['entity'];
|
|
$return['dxcc_lat'] = $callsign_dxcc_lookup['lat'];
|
|
$return['dxcc_long'] = $callsign_dxcc_lookup['long'];
|
|
$return['dxcc_cqz'] = $callsign_dxcc_lookup['cqz'];
|
|
}
|
|
|
|
/*
|
|
*
|
|
* Pool any local data we have for a callsign
|
|
*
|
|
*/
|
|
$call_lookup_results = $this->logbook_model->call_lookup_result($lookup_callsign);
|
|
|
|
if ($call_lookup_results != null) {
|
|
$return['name'] = $call_lookup_results->COL_NAME;
|
|
$return['gridsquare'] = $call_lookup_results->COL_GRIDSQUARE;
|
|
$return['location'] = $call_lookup_results->COL_QTH;
|
|
$return['iota_ref'] = $call_lookup_results->COL_IOTA;
|
|
$return['qsl_manager'] = $call_lookup_results->COL_QSL_VIA;
|
|
$return['state'] = $call_lookup_results->COL_STATE;
|
|
$return['us_county'] = $call_lookup_results->COL_CNTY;
|
|
|
|
if ($return['gridsquare'] != "") {
|
|
$return['latlng'] = $this->qralatlng($return['gridsquare']);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Check if callsign is active on LoTW
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
*
|
|
* Output Returned data
|
|
*
|
|
*/
|
|
echo json_encode($return, JSON_PRETTY_PRINT);
|
|
return;
|
|
|
|
// End benchmarking
|
|
$this->output->enable_profiler(FALSE);
|
|
}
|
|
|
|
function qralatlng($qra)
|
|
{
|
|
$this->load->library('Qra');
|
|
$latlng = $this->qra->qra2latlong($qra);
|
|
return $latlng;
|
|
}
|
|
|
|
/**
|
|
* API endpoint to get recent QSOs from a public logbook
|
|
*
|
|
* @api GET /api/recent_qsos/{public_slug}/{limit}
|
|
*
|
|
* @param string public_slug Required. Public slug identifier for the logbook
|
|
* @param int limit Optional. Number of QSOs to return (default: 10, max: 50)
|
|
*
|
|
* @return json Returns JSON array with recent QSO data or error message
|
|
*
|
|
* @throws 404 Not Found - Logbook not found or empty logbook
|
|
* @throws 400 Bad Request - Invalid limit parameter
|
|
*
|
|
* @example
|
|
* Request: GET /api/recent_qsos/my-public-logbook/5
|
|
*
|
|
* Response:
|
|
* {
|
|
* "qsos": [
|
|
* {
|
|
* "date": "2024-01-15",
|
|
* "time": "14:30",
|
|
* "callsign": "W1AW",
|
|
* "mode": "SSB",
|
|
* "band": "20M",
|
|
* "rst_sent": "59",
|
|
* "rst_rcvd": "59"
|
|
* }
|
|
* ],
|
|
* "count": 1,
|
|
* "logbook_slug": "my-public-logbook"
|
|
* }
|
|
*/
|
|
function recent_qsos($public_slug = null, $limit = 10)
|
|
{
|
|
header('Content-type: application/json');
|
|
|
|
// Validate and sanitize $limit
|
|
if (!is_numeric($limit)) {
|
|
$limit = 10; // Default to 10 if not numeric
|
|
} else {
|
|
$limit = intval($limit);
|
|
if ($limit < 1) {
|
|
$limit = 1; // Minimum limit of 1
|
|
} elseif ($limit > 50) {
|
|
$limit = 50; // Maximum limit of 50
|
|
}
|
|
}
|
|
|
|
if ($public_slug == null) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'missing public_slug parameter']);
|
|
return;
|
|
}
|
|
|
|
$this->load->model('logbooks_model');
|
|
$this->load->model('logbook_model');
|
|
|
|
if ($this->logbooks_model->public_slug_exists($public_slug)) {
|
|
$logbook_id = $this->logbooks_model->public_slug_exists_logbook_id($public_slug);
|
|
if ($logbook_id != false) {
|
|
// Get associated station locations for mysql queries
|
|
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
|
|
|
|
if (!$logbooks_locations_array) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'Empty Logbook']);
|
|
return;
|
|
}
|
|
|
|
// Get recent QSOs using existing method
|
|
$recent_qsos_query = $this->logbook_model->get_last_qsos($limit, $logbooks_locations_array);
|
|
|
|
if ($recent_qsos_query == null) {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'No QSOs found']);
|
|
return;
|
|
}
|
|
|
|
// Format the data for JSON response
|
|
$qsos = array();
|
|
foreach ($recent_qsos_query->result() as $row) {
|
|
$qso = array(
|
|
'date' => date('Y-m-d', strtotime($row->COL_TIME_ON)),
|
|
'time' => date('H:i', strtotime($row->COL_TIME_ON)),
|
|
'callsign' => strtoupper($row->COL_CALL),
|
|
'mode' => $row->COL_SUBMODE ? $row->COL_SUBMODE : $row->COL_MODE,
|
|
'band' => $row->COL_SAT_NAME ? $row->COL_SAT_NAME : $row->COL_BAND,
|
|
'rst_sent' => $row->COL_RST_SENT,
|
|
'rst_rcvd' => $row->COL_RST_RCVD
|
|
);
|
|
|
|
// Add optional fields if they exist
|
|
if ($row->COL_STX_STRING) {
|
|
$qso['stx_string'] = $row->COL_STX_STRING;
|
|
}
|
|
if ($row->COL_SRX_STRING) {
|
|
$qso['srx_string'] = $row->COL_SRX_STRING;
|
|
}
|
|
if ($row->COL_VUCC_GRIDS) {
|
|
$qso['gridsquare'] = $row->COL_VUCC_GRIDS;
|
|
} elseif ($row->COL_GRIDSQUARE) {
|
|
$qso['gridsquare'] = $row->COL_GRIDSQUARE;
|
|
}
|
|
if ($row->COL_QTH) {
|
|
$qso['qth'] = $row->COL_QTH;
|
|
}
|
|
if ($row->COL_NAME) {
|
|
$qso['name'] = $row->COL_NAME;
|
|
}
|
|
|
|
// Prefer grid-derived coordinates for plotting, including VUCC multi-grid line/corner records.
|
|
$plot_latlng = false;
|
|
if (!empty($row->COL_VUCC_GRIDS)) {
|
|
$plot_latlng = $this->qralatlng($row->COL_VUCC_GRIDS);
|
|
} elseif (!empty($row->COL_GRIDSQUARE)) {
|
|
$plot_latlng = $this->qralatlng($row->COL_GRIDSQUARE);
|
|
}
|
|
|
|
if (is_array($plot_latlng) && count($plot_latlng) === 2) {
|
|
$qso['lat'] = $plot_latlng[0];
|
|
$qso['long'] = $plot_latlng[1];
|
|
}
|
|
|
|
$dxcc = $this->logbook_model->check_dxcc_table(strtoupper(trim(strtoupper($row->COL_CALL))), $row->COL_TIME_ON);
|
|
if (empty($dxcc[0])) {
|
|
$dxcc_id = null;
|
|
} else {
|
|
$qso['country'] = $dxcc[1];
|
|
if (!isset($qso['lat']) || !isset($qso['long'])) {
|
|
$qso['lat'] = $dxcc[4];
|
|
$qso['long'] = $dxcc[5];
|
|
}
|
|
}
|
|
|
|
$qsos[] = $qso;
|
|
}
|
|
|
|
http_response_code(200);
|
|
echo json_encode([
|
|
'qsos' => $qsos,
|
|
'count' => count($qsos),
|
|
'logbook_slug' => $public_slug
|
|
], JSON_PRETTY_PRINT);
|
|
} else {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => $public_slug . ' has no associated station locations']);
|
|
}
|
|
} else {
|
|
http_response_code(404);
|
|
echo json_encode(['status' => 'failed', 'reason' => 'logbook not found']);
|
|
}
|
|
}
|
|
}
|