Skip to content

Commit 786a5b8

Browse files
committed
Added: working api route to get form backrefs (#344)
1 parent f157fa1 commit 786a5b8

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

libreforms_fastapi/app/__init__.py

+113
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,119 @@ async def api_form_read_all_needing_action(
15671567
return {"documents": dict_of_return_values}
15681568

15691569

1570+
# Read all forms that reference the given form_name and document_id
1571+
@app.get("/api/form/get_linked_refs/{form_name}/{document_id}", dependencies=[Depends(api_key_auth)])
1572+
async def api_form_read_all_needing_action(
1573+
form_name: str,
1574+
document_id: str,
1575+
background_tasks: BackgroundTasks,
1576+
request: Request,
1577+
config = Depends(get_config_depends),
1578+
mailer = Depends(get_mailer),
1579+
doc_db = Depends(get_doc_db),
1580+
session: SessionLocal = Depends(get_db),
1581+
key: str = Depends(X_API_KEY),
1582+
1583+
):
1584+
"""
1585+
This method returns a list of forms that reference the given form_name and document_id
1586+
in one of their fields. These are sometimes called linked references, or backrefs. It
1587+
returns full records in a flat format by default.
1588+
"""
1589+
1590+
if not config.API_ENABLED:
1591+
raise HTTPException(status_code=404, detail="This page does not exist")
1592+
1593+
if form_name not in get_form_names(config_path=config.FORM_CONFIG_PATH):
1594+
raise HTTPException(status_code=404, detail=f"Form '{form_name}' not found")
1595+
1596+
# Ugh, I'd like to find a more efficient way to get the user data. But alas, that
1597+
# the sqlalchemy-signing table is not optimized alongside the user model...
1598+
user = session.query(User).filter_by(api_key=key).first()
1599+
1600+
# Here we build a full structure containing all the form field links for each form
1601+
dict_of_fields_linked_to_forms = {} # This might not be relevant ... We will see.
1602+
1603+
# Now we build a dict for linked fields _applicable_ to the given form_name
1604+
dict_of_relevant_links = {}
1605+
1606+
for _form_name in get_form_names(config_path=config.FORM_CONFIG_PATH):
1607+
1608+
dict_of_relevant_links[_form_name] = []
1609+
1610+
__form_model = get_form_model(
1611+
form_name=_form_name,
1612+
config_path=config.FORM_CONFIG_PATH,
1613+
session=session,
1614+
User=User,
1615+
Group=Group,
1616+
doc_db=__doc_db,
1617+
)
1618+
1619+
dict_of_fields_linked_to_forms[_form_name] = __form_model.form_fields
1620+
1621+
for field_name, linked_form in __form_model.form_fields.items():
1622+
# If this field links to the form that this query is concerned with, then add it to the list
1623+
if linked_form == form_name:
1624+
dict_of_relevant_links[_form_name].append(field_name)
1625+
1626+
1627+
# read_all IS THE HIGHER PRIVILEGE OF THE TWO - SO WE SHOULD CHECK FOR THAT FIRST, AS IT
1628+
# INCLUDES read_own. https://github.com/signebedi/libreforms-fastapi/issues/307.
1629+
try:
1630+
user.validate_permission(form_name=form_name, required_permission="read_all")
1631+
limit_query_to = False
1632+
except Exception as e:
1633+
1634+
try:
1635+
user.validate_permission(form_name=form_name, required_permission="read_own")
1636+
limit_query_to = user.username
1637+
1638+
except Exception as e:
1639+
raise HTTPException(status_code=403, detail=f"{e}")
1640+
1641+
1642+
documents = []
1643+
1644+
for _form_name, _linked_fields in dict_of_relevant_links.items():
1645+
for _linked_field in _linked_fields:
1646+
_documents = []
1647+
# This query param will only return that matches the given document_id
1648+
query_params = {"data":{_linked_field: {"operator": "==","value": document_id}}}
1649+
1650+
_documents = doc_db.get_all_documents(
1651+
form_name=_form_name,
1652+
limit_users=limit_query_to,
1653+
exclude_journal=True,
1654+
collapse_data=True,
1655+
# sort_by_last_edited=True,
1656+
# newest_first=True,
1657+
query_params=query_params,
1658+
)
1659+
1660+
documents.extend(_documents)
1661+
1662+
# Placeholder: drop duplicates and sort!
1663+
1664+
# Write this query to the TransactionLog
1665+
if config.COLLECT_USAGE_STATISTICS:
1666+
1667+
endpoint = request.url.path
1668+
remote_addr = request.client.host
1669+
1670+
background_tasks.add_task(
1671+
write_api_call_to_transaction_log,
1672+
api_key=key,
1673+
endpoint=endpoint,
1674+
remote_addr=remote_addr,
1675+
query_params={},
1676+
)
1677+
1678+
return {"documents": documents}
1679+
1680+
1681+
1682+
15701683
# Read one form
15711684
@app.get("/api/form/read_one/{form_name}/{document_id}", dependencies=[Depends(api_key_auth)])
15721685
async def api_form_read_one(

0 commit comments

Comments
 (0)