webfinger/webfinger/io.py

103 lines
2.9 KiB
Python

"""
Functions that perform read-write operations
"""
import json
from os import environ as env
from urllib.parse import quote_plus as url_encode
from pathlib import Path
from webfinger.models import JRD, Link
DictJRD = dict[str, str | list[str] | dict[str,str] | list[dict[str,str]]]
def get_jrd_as_dict(resource: str) -> DictJRD:
"""
Obtain a JSON Resource Descriptor (JRD) as a dictionary
A JRD is a JSON object containing the following:
- subject (string value; SHOULD be present)
- aliases (array of string values; OPTIONAL)
- properties (object containing key-value pairs as strings; OPTIONAL)
- links (array of objects containing link relation information; OPTIONAL)
Parameters:
resource (str): The URI of the resouce
Returns:
jrd (dict): Parsed JRD dictionary
Raises:
FileNotFoundError: No JRD file exists in the resource directory
OSError: A file may exist, but it is not readable
json.JSONDecodeError: A file exists, but does not contain a valid JSON object
"""
# Get a filename for the resource document.
directory = env.get("RESOURCE_DIR") or "resource"
filename = resource
path = f"{directory}/{filename}.jrd"
# If we can't get a file, try percent-encoding
if not Path(path).is_file():
filename = url_encode(resource)
path = f"{directory}/{filename}.jrd"
# Try plain JSON
if not Path(path).is_file():
filename = resource
path = f"{directory}/{filename}.json"
# Try plain JSON and percent-encoding
if not Path(path).is_file():
filename = resource
path = f"{directory}/{filename}.json"
# Open the file and load the JSON as a dictionary.
# This may fail and raise an exception.
with open(path, mode="r", encoding="utf-8") as file:
jrd: DictJRD = json.loads(file.read())
return {k: v for k, v in jrd.items() if v} # remove null values
def get_jrd(resource: str) -> JRD:
"""
Obtain a JSON Resource Descriptor (JRD) as a Pydantic model
A JRD is a JSON object containing the following:
- subject (string value; SHOULD be present)
- aliases (array of string values; OPTIONAL)
- properties (object containing key-value pairs as strings; OPTIONAL)
- links (array of objects containing link relation information; OPTIONAL)
Parameters:
resource (str): The URI of the resouce
Returns:
jrd (JRD): Parsed and valid JRD model
Raises:
FileNotFoundError: No JRD file exists in the resource directory
OSError: A file may exist, but it is not readable
json.JSONDecodeError: A file exists, but does not contain a valid JSON object
pydantic.ValidationError: A file exists and was parsed, but some properties failed validation
"""
jrd = get_jrd_as_dict(resource)
return JRD(
subject = jrd.get('subject') or resource,
aliases = jrd.get('aliases'),
properties = jrd.get('properties'),
links = [
Link(
rel = link.get('rel'),
type = link.get('type'),
href = link.get('href'),
titles = link.get('titles'),
properties = link.get('properties'),
)
for link in jrd.get('links', [])
],
)