diff --git a/.gitignore b/.gitignore
index d49dae3..dad1e51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,7 @@
__pycache__
siteconfig.py
siteconfig.pyc
-.venv
\ No newline at end of file
+.venv
+.vscode
+.DS_Store
+/tagging-recording/call_*
diff --git a/tagging-recording/README.md b/tagging-recording/README.md
new file mode 100644
index 0000000..2167039
--- /dev/null
+++ b/tagging-recording/README.md
@@ -0,0 +1,53 @@
+## Requirements
+
+- Python 3 and Pip
+
+## Install Dependencies
+
+Make sure you have run the following in the parent directory:
+```
+pip install -r requirements.txt
+```
+
+## Configuring the Script
+
+Please make sure you have configured the `siteconfig.py` in the parent directory.
+
+## Set up a Reverse Proxy
+
+This script will start up an HTTP server on port 8899.
+It is recommanded to set up another public web service and forward the web hook request to server.
+
+## Usage
+This script use `window.postMessage` to interacting with citron. So make sure open HL page with button on top of current page.
+
+The script will start up a web server on port 8899 and will listen for
+incoming webhooks of type `call` with a category of `attachment_created`.
+
+Each time it gets a new `attachment_created` event, the script will
+save the attachment id and uuid to the file named with call id.
+
+```
+> cat call_34c78f14-55a7-4d16-86c1-a6fe7837cf26
+5895ec01-c02c-42db-983a-9fdae98d0ace,31675
+a7c1de42-9900-41e6-9ef4-cdabf01d45e3,31674
+95d4f7a9-d5b8-46df-a3fc-504c51845910,31676
+4aec6d2a-263d-4227-9248-6d3d10592668,31677
+f4a753f2-ee63-4ec7-adaf-5044c88a7dcd,31678
+
+```
+We will tag the recording automatically when receive the `RECORDING_STARTED` event from citron.
+
+In `index.html`, we have one post function to backend:
+
+```
+POST http://127.0.0.1:8899 {'type': 'download', uuids: [....]}
+```
+This will try to look and parse the call files(if have one), then match the uuid with the attachment id and get the `signed_url` back.
+
+
+To run this script:
+
+```
+python3 server.py
+```
diff --git a/tagging-recording/index.html b/tagging-recording/index.html
new file mode 100644
index 0000000..ae20ff3
--- /dev/null
+++ b/tagging-recording/index.html
@@ -0,0 +1,228 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tagging-recording/server.py b/tagging-recording/server.py
new file mode 100644
index 0000000..a3e1c5c
--- /dev/null
+++ b/tagging-recording/server.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python3
+"""
+License: MIT License
+Copyright (c) 2023 Miel Donkers
+
+Very simple HTTP server in python for logging requests
+Usage::
+ ./server.py []
+"""
+from http.server import BaseHTTPRequestHandler, HTTPServer
+import logging
+import sys
+import datetime
+import json
+import jwt
+import os
+import time
+from os import walk
+
+sys.path.append('.')
+import libhelplightning
+import siteconfig
+
+current_dir = "/" + sys.path[0] + "/"
+
+class S(BaseHTTPRequestHandler):
+ def _set_response(self):
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ def get_logger(self, level=logging.DEBUG):
+ """
+ Sets up logging to be shared across
+ all classes/functions.
+ """
+ root = logging.getLogger()
+ root.setLevel(level)
+ ch = logging.StreamHandler(sys.stdout)
+ ch.setLevel(level)
+ root.addHandler(ch)
+ return root
+
+ def generate_token(self, partner_key):
+ # create a date that expires in 1 hour
+ exp = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=3600)
+
+ # load our private key, which is in pkcs8 format
+ with open(partner_key) as f:
+ secret = f.read()
+
+ # generate a new JWT token that will be valid for one hour and sign it with our secret
+ payload = {
+ 'iss': 'Ghazal',
+ 'sub': f'Partner:{siteconfig.SITE_ID}',
+ 'aud': 'Ghazal',
+ 'exp': exp
+ }
+
+ token = jwt.encode(payload, key=secret, algorithm='RS256')
+
+ return token
+
+ def save_data(self, call_id, uuid, attachement_id):
+ writepath = current_dir + call_id
+ mode = 'a' if os.path.exists(writepath) else 'w'
+ with open(writepath, mode) as f:
+ f.write(uuid + ',' + str(attachement_id) + '\n')
+
+ def save_recording_info(self, uuid, tag):
+ rec = self.get_recording_info()
+
+ if uuid not in rec:
+ writepath = current_dir + 'rec_' + str(datetime.date.today())
+ now = datetime.datetime.now()
+ dt_string = now.strftime("%d/%m/%Y-%H:%M:%S")
+ mode = 'a' if os.path.exists(writepath) else 'w'
+ with open(writepath, mode) as f:
+ f.write(tag + ',' + uuid + ',' + dt_string +'\n')
+
+ def get_recording_info(self):
+ path = current_dir + 'rec_' + str(datetime.date.today())
+ dictionary = {}
+ if os.path.exists(path):
+ with open(path, 'r') as file:
+ lines = file.readlines()
+ for line in lines:
+ line = line.strip()
+ data = line.split(",")
+ dictionary[data[1]] = [data[0], data[2]]
+
+ logging.info("\n %s", dictionary)
+ return dictionary
+
+ def get_cached_files(self, prefix):
+ filenames = next(walk(current_dir), (None, None, []))[2]
+ files = filter(lambda x: x.startswith(prefix), filenames)
+ return list(files)
+
+ def get_attachments_from_uuid(self, uuids):
+ calls = self.get_cached_files('call_')
+ dictionary = {}
+ for f in calls:
+ with open(current_dir + f, 'r') as file:
+ lines = file.readlines()
+ for line in lines:
+ line = line.strip()
+ data = line.split(",")
+ if data[0] in uuids:
+ dictionary[data[1]] = f # {attachment_id: call_id}
+
+
+ logging.info("\n %s", dictionary)
+ return dictionary
+
+ def get_call_attachments(self, call_attachment_dict):
+ logger = self.get_logger(level=logging.INFO)
+ token = self.generate_token(siteconfig.PARTNER_KEY)
+ e_client = libhelplightning.GaldrClient(
+ logger,
+ siteconfig.HELPLIGHTNING_ENDPOINT,
+ siteconfig.API_KEY,
+ token = token
+ )
+ attachments = {}
+
+ for attachment_id, call_id in call_attachment_dict.items():
+ time.sleep(0.100)
+ resp = e_client.get(f'/api/v1r1/enterprise/calls/{call_id}/attachments/{attachment_id}')
+ attachments[resp.get("uuid")] = resp.get("signed_url")
+
+ return attachments
+
+ def do_GET(self):
+ self.path = current_dir + 'index.html'
+ logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers))
+ file_to_open = open(self.path[1:]).read()
+ self._set_response()
+ self.wfile.write(bytes(file_to_open, 'utf-8'))
+
+ def do_POST(self):
+ response = "{}"
+ content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
+ post_data = self.rfile.read(content_length) # <--- Gets the data itself
+ logging.info("POST request,\nPath: %s\nHeaders:\n%s\n\nBody:\n%s\n",
+ str(self.path), str(self.headers), post_data.decode('utf-8'))
+
+ call_data = json.loads(post_data.decode('utf-8'))
+
+ type = call_data.get("type")
+ category = call_data.get("category")
+
+ if type == "call" and category == "attachment_created":
+ uuid = call_data.get("data").get("attachment").get("uuid")
+ attachement_id = call_data.get("data").get("attachment").get("id")
+ call_id = call_data.get("data").get("call_id")
+
+ logging.info("\nAttachment: id - %s \n call_id: %s \n uuid: %s \n", attachement_id, call_id, uuid)
+ self.save_data(call_id, uuid, attachement_id)
+
+
+ if type == "load":
+ local_rec = self.get_recording_info()
+ uuids = []
+ for x in local_rec.keys():
+ uuids.append(x)
+
+ call_attachment_dict = self.get_attachments_from_uuid(uuids)
+ attachments = self.get_call_attachments(call_attachment_dict)
+ data = []
+ for x in local_rec.keys():
+ url = attachments.get(x, "")
+ name = local_rec[x][0]
+ time = local_rec[x][1]
+ data.append({"uuid": x, "url": url, "name": name, "time": time})
+
+ response = json.dumps(data)
+
+ if type == "start_recording":
+ uuid = call_data.get("uuid")
+ tag = call_data.get("tag")
+ self.save_recording_info(uuid, tag)
+
+ if type == "reset":
+ files = self.get_cached_files('call_') + self.get_cached_files('rec_')
+ for f in files:
+ os.remove(current_dir + f)
+ response = []
+
+ self._set_response()
+ self.send_header('Content-Type', 'application/json')
+ self.wfile.write(response.encode('utf-8'))
+
+def run(server_class=HTTPServer, handler_class=S, port=8899):
+ logging.basicConfig(level=logging.INFO)
+ #logging.info(sys.path)
+ server_address = ('', port)
+ httpd = server_class(server_address, handler_class)
+ logging.info('Starting httpd...\n')
+ try:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ pass
+ httpd.server_close()
+ logging.info('Stopping httpd...\n')
+
+
+if __name__ == '__main__':
+ from sys import argv
+
+ if len(argv) == 2:
+ run(port=int(argv[1]))
+ else:
+ run()