170 lines
6.0 KiB
Python
170 lines
6.0 KiB
Python
import urllib
|
|
import re
|
|
import os
|
|
import sys
|
|
import configparser
|
|
from pathlib import Path
|
|
from flask import Flask, jsonify, request, Response
|
|
from flask_restful import Resource, Api
|
|
from waitress import serve
|
|
import requests
|
|
from requests.structures import CaseInsensitiveDict
|
|
|
|
|
|
app = Flask(__name__)
|
|
api = Api(app)
|
|
|
|
class QRZ():
|
|
#class QRZ():
|
|
"""QRZ class"""
|
|
|
|
def __init__(self):
|
|
"""initialize things"""
|
|
|
|
self.config = configparser.ConfigParser()
|
|
self.home_dir = str(Path.home())
|
|
self.config_dir = self.home_dir + "/.config/CloudlogOffline2QRZ/"
|
|
# Check if config directory exists and else create it
|
|
Path(self.config_dir).mkdir(parents=True, exist_ok=True)
|
|
self.config_file = os.path.expanduser(self.config_dir + 'CloudlogOffline2QRZ.ini')
|
|
self.read_config(self.config, self.config_file)
|
|
|
|
# headers for all POST requests
|
|
self.headers = CaseInsensitiveDict()
|
|
self.headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
|
|
|
|
@staticmethod
|
|
def read_config(config, file_name):
|
|
"""reads the configuration from the config file or
|
|
creates a default config file if none could be found"""
|
|
if os.path.isfile(file_name):
|
|
config.read(file_name)
|
|
else:
|
|
config = configparser.ConfigParser()
|
|
config['qrz.com'] = {
|
|
'station_call': 'MYCALL',
|
|
'api_key': '1234-ABCD-1234-A1B2',
|
|
'url': 'https://logbook.qrz.com/api'}
|
|
config['general'] = {
|
|
'api_key': 'API_KEY_FOR_THIS_API',
|
|
'install_path': '/'
|
|
}
|
|
|
|
with open(file_name, 'w') as configfile:
|
|
config.write(configfile)
|
|
print("\nNo configuration file found. A new configuration file has been created.")
|
|
print("\nPlease edit the file " + file_name + " and restart the application.\n" )
|
|
sys.exit()
|
|
return config
|
|
|
|
|
|
def send_request(self, post_data):
|
|
"""Sends a POST request to QRZ.com, checks for errors
|
|
and returns the response"""
|
|
try:
|
|
resp = requests.post(qrz.config['qrz.com']['url'], headers=self.headers, data=post_data)
|
|
if resp.status_code == 200:
|
|
str_resp = resp.content.decode("utf-8")
|
|
response = urllib.parse.unquote(str_resp)
|
|
resp_list = response.splitlines()
|
|
if resp_list[0]:
|
|
if "invalid api key" in resp_list[0]:
|
|
print("\nThe API key configured \
|
|
in config.ini is not correct.\n")
|
|
else:
|
|
return response
|
|
elif resp.status_code == 404:
|
|
print("\nThe API URL could not be found. \
|
|
Please check the URL in config.ini\n")
|
|
except requests.exceptions.ConnectionError as e_conn:
|
|
print("\nUnable to connect to xmldata.qrz.com:")
|
|
print(e_conn)
|
|
print("\nPlease check if you are connected to the internet")
|
|
except: # pylint: disable=bare-except
|
|
print("\nsomething unexpected has happened:\n")
|
|
print(e_conn)
|
|
return None
|
|
|
|
|
|
def send_qso(self, adif):
|
|
"""Sends the previously collected QSO information as a new
|
|
QRZ.com logbook entry via the API"""
|
|
|
|
logid = "null"
|
|
|
|
# construct POST data
|
|
post_data = { 'KEY' : self.config['qrz.com']['api_key'], \
|
|
'ACTION' : 'INSERT', 'ADIF' : adif }
|
|
|
|
# URL encode the payload
|
|
data = urllib.parse.urlencode(post_data)
|
|
# send the POST request to QRZ.com
|
|
response = self.send_request(data)
|
|
|
|
# Check if the upload failed and print out
|
|
# the reason plus some additional info
|
|
if response:
|
|
if "STATUS=FAIL" in response:
|
|
print("QSO upload failed. QRZ.com has send the following reason:\n")
|
|
resp_list = response.split("&")
|
|
for item in resp_list:
|
|
print(item)
|
|
print("\nPlease review the following request that led to this error:\n")
|
|
print(post_data)
|
|
else:
|
|
try:
|
|
logid = re.search('LOGID=(\d+)', response).group(1)
|
|
print("QSO successfully uploaded to QRZ.com (LOGID "+ logid + ")")
|
|
log_status = "SUCCESS: "
|
|
except: # pylint: disable=bare-except
|
|
logid = "null"
|
|
print("\nQSO upload to QRZ.com failed!\n")
|
|
return logid
|
|
|
|
|
|
class ApiTest(Resource):
|
|
"""Listens on the API endpoint /api/auth to validate
|
|
the configured API key in CloudlogOffline"""
|
|
|
|
def get(self, key):
|
|
if key and key == qrz.config['general']['api_key']:
|
|
print("API Key is valid!")
|
|
return Response("{'status':'ok'}", status=200, mimetype='application/json')
|
|
print("Wrong API key configured in CloudlogOffline")
|
|
return Response("{'status':'not ok'}", status=403, mimetype='application/json')
|
|
|
|
|
|
class UploadQso(Resource):
|
|
"""Listens on the API endpoint /api/qso to receive
|
|
single ADIF strings from CloudlogOffline"""
|
|
|
|
def post(self):
|
|
data = request.json
|
|
key = data['key']
|
|
adif = data['string']
|
|
|
|
if key == qrz.config['general']['api_key']:
|
|
print("\n Sending the following QSO: " + adif)
|
|
logid = qrz.send_qso(adif)
|
|
if logid != "null":
|
|
return jsonify(
|
|
status='created',
|
|
)
|
|
return jsonify(
|
|
status='failed',
|
|
)
|
|
print("Wrong API key configured in CloudlogOffline")
|
|
return jsonify(
|
|
status='wrong api key',
|
|
)
|
|
|
|
|
|
# main
|
|
if __name__ == '__main__':
|
|
qrz = QRZ()
|
|
api.add_resource(ApiTest, qrz.config['general']['install_path'] + 'index.php/api/auth/<string:key>' )
|
|
api.add_resource(UploadQso, qrz.config['general']['install_path'] + 'index.php/api/qso')
|
|
#app.run(debug=True)
|
|
serve(app, host='127.0.0.1', port=5000)
|