diff --git a/CloudlogOffline2QRZ.py b/CloudlogOffline2QRZ.py new file mode 100644 index 0000000..e5458b4 --- /dev/null +++ b/CloudlogOffline2QRZ.py @@ -0,0 +1,165 @@ +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 +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' + } + + 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): + + 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): + + 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', + ) + + +# adding the defined resources along with their corresponding urls +api.add_resource(ApiTest, '/index.php/api/auth/' ) +api.add_resource(UploadQso, '/index.php/api/qso') + + +# driver function +if __name__ == '__main__': + qrz = QRZ() + app.run(debug=True, host='0.0.0.0')