CloudlogOffline2QRZ/CloudlogOffline2QRZ.py

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)