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/' ) 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)