|
| 1 | +"""Functions for working with the GetOrganized API.""" |
| 2 | + |
| 3 | +import json |
| 4 | +from urllib.parse import urljoin |
| 5 | +from typing import Literal |
| 6 | + |
| 7 | +from requests import Session |
| 8 | +from requests_ntlm import HttpNtlmAuth |
| 9 | + |
| 10 | + |
| 11 | +def create_session(username: str, password: str) -> Session: |
| 12 | + """Create a session for accessing GetOrganized API. |
| 13 | +
|
| 14 | + Args: |
| 15 | + username: Username for login. |
| 16 | + password: Password for login. |
| 17 | +
|
| 18 | + Returns: |
| 19 | + Return the session object |
| 20 | + """ |
| 21 | + session = Session() |
| 22 | + session.headers.setdefault("Content-Type", "application/json") |
| 23 | + session.auth = HttpNtlmAuth(username, password) |
| 24 | + return session |
| 25 | + |
| 26 | + |
| 27 | +def upload_document(*, apiurl: str, file: bytearray, case_id: str, filename: str, agent_name: str | None = None, date_string: str | None = None, session: Session, doc_category: str | None = None, case_type: str = Literal["EMN", "GEO"], overwrite: bool = True) -> tuple[str, Session]: |
| 28 | + """Upload a document to Get Organized. |
| 29 | +
|
| 30 | + Args: |
| 31 | + apiurl: Base url for API. |
| 32 | + session: Session token for request. |
| 33 | + file: Bytearray of file to upload. |
| 34 | + case_id: Case ID already present in GO. |
| 35 | + filename: Name of file when saved in GO. |
| 36 | + agent_name: Agent name, used for creating a folder in GO. Defaults to None. |
| 37 | + date_string: A date to add as metadata to GetOrganized. Defaults to None. |
| 38 | +
|
| 39 | + Returns: |
| 40 | + Return response text. |
| 41 | + """ |
| 42 | + url = apiurl + "/_goapi/Documents/AddToCase" |
| 43 | + payload = { |
| 44 | + "Bytes": list(file), |
| 45 | + "CaseId": case_id, |
| 46 | + "SiteUrl": urljoin(apiurl, f"/case{case_type}/{case_id}"), |
| 47 | + "ListName": "Dokumenter", |
| 48 | + "FolderPath": agent_name, |
| 49 | + "FileName": filename, |
| 50 | + "Metadata": f"<z:row xmlns:z='#RowsetSchema' ows_Dato='{date_string}' ows_Kategori='{doc_category}'/>", |
| 51 | + "Overwrite": overwrite |
| 52 | + } |
| 53 | + response = session.post(url, data=json.dumps(payload), timeout=60) |
| 54 | + response.raise_for_status() |
| 55 | + return response.text |
| 56 | + |
| 57 | + |
| 58 | +def delete_document(apiurl: str, document_id: int, session: Session) -> tuple[str, Session]: |
| 59 | + """Delete a document from GetOrganized. |
| 60 | +
|
| 61 | + Args: |
| 62 | + apiurl: Url of the GetOrganized API. |
| 63 | + session: Session object used for logging in. |
| 64 | + document_id: ID of the document to delete. |
| 65 | +
|
| 66 | + Returns: |
| 67 | + Return the response. |
| 68 | + """ |
| 69 | + url = urljoin(apiurl, "/_goapi/Documents/ByDocumentId/") |
| 70 | + payload = { |
| 71 | + "DocId": document_id, |
| 72 | + "ForceDelete": True |
| 73 | + } |
| 74 | + response = session.delete(url, timeout=60, data=json.dumps(payload)) |
| 75 | + response.raise_for_status() |
| 76 | + return response |
| 77 | + |
| 78 | + |
| 79 | +def create_case(session: Session, apiurl: str, title: str, category: str, department: str, kle: str, case_type: str = Literal["EMN", "GEO"]) -> str: |
| 80 | + """Create a case in GetOrganized. |
| 81 | +
|
| 82 | + Args: |
| 83 | + apiurl: Url for the GetOrganized API. |
| 84 | + session: Session object to access API. |
| 85 | + title: Title of the case being created. |
| 86 | + category: Case category to create the case for. |
| 87 | + department: Department for the case. |
| 88 | + kle: KLE number for the case (https://www.kle-online.dk/emneplan/00/) |
| 89 | +
|
| 90 | + Returns: |
| 91 | + Return the caseID of the created case. |
| 92 | + """ |
| 93 | + url = urljoin(apiurl, "/_goapi/Cases/") |
| 94 | + payload = { |
| 95 | + 'CaseTypePrefix': case_type, |
| 96 | + 'MetadataXml': f'''<z:row xmlns:z="#RowsetSchema" |
| 97 | + ows_Title="{title}" |
| 98 | + ows_CaseStatus="Åben" |
| 99 | + ows_CaseCategory="{category}" |
| 100 | + ows_Afdeling="{department}" |
| 101 | + ows_KLENummer="{kle}"/>''', |
| 102 | + 'ReturnWhenCaseFullyCreated': False |
| 103 | + } |
| 104 | + response = session.post(url, data=json.dumps(payload), timeout=60) |
| 105 | + response.raise_for_status() |
| 106 | + return response.json()["CaseID"] |
| 107 | + |
| 108 | + |
| 109 | +def get_case_metadata(session: Session, apiurl: str, case_id: str) -> str: |
| 110 | + """Get metadata for a GetOrganized case, to look through parameters and values. |
| 111 | +
|
| 112 | + Args: |
| 113 | + session: Session token. |
| 114 | + apiurl: Base URL for the API. |
| 115 | + case_id: Case ID to get metadata on. |
| 116 | +
|
| 117 | + Returns: |
| 118 | + Return the metadata for the case as an XML string. |
| 119 | + """ |
| 120 | + url = urljoin(apiurl, f"/_goapi/Cases/Metadata/{case_id}") |
| 121 | + response = session.get(url, timeout=60) |
| 122 | + response.raise_for_status() |
| 123 | + return response.json()["Metadata"] |
| 124 | + |
| 125 | + |
| 126 | +def find_case(session: Session, apiurl: str, case_title: str, case_type: str = Literal["EMN", "GEO"]) -> list[str]: |
| 127 | + """Search for an existing case in GO with the given case title. |
| 128 | + The search finds any case that contains the given title in its title. |
| 129 | +
|
| 130 | + Args: |
| 131 | + case_title: The title to search for. |
| 132 | + session: Session object to access the API. |
| 133 | +
|
| 134 | + Returns: |
| 135 | + The case id of the found case(s) if any. |
| 136 | + """ |
| 137 | + url = apiurl + "/_goapi/Cases/FindByCaseProperties" |
| 138 | + payload = { |
| 139 | + "FieldProperties": [ |
| 140 | + { |
| 141 | + "InternalName": "ows_Title", |
| 142 | + "Value": case_title, |
| 143 | + "ComparisonType": "Contains", |
| 144 | + } |
| 145 | + ], |
| 146 | + "CaseTypePrefixes": [case_type], |
| 147 | + "LogicalOperator": "AND", |
| 148 | + "ExcludeDeletedCases": True |
| 149 | + } |
| 150 | + response = session.post(url, data=json.dumps(payload), timeout=60) |
| 151 | + response.raise_for_status() |
| 152 | + cases = response.json()['CasesInfo'] |
| 153 | + |
| 154 | + return [case['CaseID'] for case in cases] |
0 commit comments