-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprobe_style_values.py
More file actions
182 lines (160 loc) · 6.33 KB
/
Copy pathprobe_style_values.py
File metadata and controls
182 lines (160 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import json
import os
import time
import load_dotenv
from uwazi_api.client import UwaziClient
from uwazi_api.domain.property_schema import PropertySchema
from uwazi_api.domain.property_type import PropertyType
from uwazi_api.domain.template import Template
load_dotenv.load_dotenv()
UWAZI_USER = os.getenv("UWAZI_USER", "admin")
UWAZI_PASSWORD = os.getenv("UWAZI_PASSWORD", "admin")
UWAZI_URL = os.getenv("UWAZI_URL", "http://localhost:3000")
# Probe values to round-trip through the real API. ``fill`` / ``fit``
# are what the Uwazi UI calls the styles in the template editor; the
# server actually persists ``cover`` / ``contain`` on disk, so we send
# the agent-side labels and read back the wire-side value. The rest are
# guesses to see whether Uwazi silently accepts/rejects/coerces them.
CANDIDATE_STYLES = [
"cover",
"fill",
"fit",
"", # legacy empty string (Uwazi's stored sentinel)
"contain",
"stretch",
"center",
"scale-down",
"thumbnail",
"tile",
"none",
"Cover", # wrong case
"FIT",
"full",
"crop",
]
def _delete_template(client: UwaziClient, template_id: str) -> int | None:
resp = client.http.request_adapter.delete(
url=f"{client.http.url}/api/templates",
params={"_id": template_id},
headers=client.http.headers,
cookies={},
)
return getattr(resp, "status_code", None)
def probe(style_value, property_type: PropertyType):
client = UwaziClient(user=UWAZI_USER, password=UWAZI_PASSWORD, url=UWAZI_URL)
safe_name = f"style_probe_{property_type.value}_{int(time.time() * 1000)}"
# Build the template as a raw dict so unknown style values are sent over
# the wire as-is. PropertySchema's validator would otherwise reject any
# string that isn't a PropertyStyle member before Uwazi ever sees it,
# which defeats the whole point of the probe.
template = Template(
name=safe_name,
properties=[
PropertySchema(
name="probe_prop",
label="Probe Prop",
type=property_type,
)
],
)
payload = template.model_dump(by_alias=True, exclude_none=True)
payload["properties"][0]["style"] = style_value
result = {
"input": style_value,
"type": property_type.value,
"create_status": None,
"create_body": None,
"read_back_style": None,
"read_back_full": None,
"raw_stored_style": None,
"delete_status": None,
"error": None,
}
try:
create_resp = client.http.request_adapter.post(
url=f"{client.http.url}/api/templates",
headers=client.http.headers,
cookies={"locale": "en"},
data=json.dumps(payload),
)
result["create_status"] = create_resp.status_code
try:
result["create_body"] = create_resp.json()
except Exception:
result["create_body"] = create_resp.text[:500]
if create_resp.status_code in (200, 201):
body = create_resp.json()
template_id = body.get("_id") or (body.get("template") or {}).get("_id")
if not template_id and isinstance(body, dict):
for v in body.values():
if isinstance(v, dict) and v.get("_id"):
template_id = v["_id"]
break
else:
template_id = None
except Exception as e:
result["error"] = f"create exception: {e!r}"
template_id = None
if template_id:
try:
templates = client.templates.get()
read_back = next((t for t in templates if t.name == safe_name), None)
if read_back is not None:
prop = next(
(p for p in read_back.properties if p.name == "probe_prop"),
None,
)
if prop is not None:
result["read_back_style"] = prop.style.value if prop.style is not None else None
result["read_back_full"] = {
"name": prop.name,
"type": prop.type.value,
"style": prop.style.value if prop.style is not None else None,
}
except Exception as e:
result["error"] = (result["error"] or "") + f" read exception: {e!r}"
# Also fetch the raw JSON so we can see what Uwazi actually stored,
# independent of the local PropertyStyle enum.
try:
raw_resp = client.http.request_adapter.get(
url=f"{client.http.url}/api/templates",
headers=client.http.headers,
cookies={},
)
raw_rows = json.loads(raw_resp.text).get("rows", [])
raw_match = next((t for t in raw_rows if t.get("name") == safe_name), None)
if raw_match is not None:
raw_prop = next(
(p for p in raw_match.get("properties", []) if p.get("name") == "probe_prop"),
None,
)
if raw_prop is not None:
result["raw_stored_style"] = raw_prop.get("style")
except Exception as e:
result["error"] = (result["error"] or "") + f" raw read exception: {e!r}"
try:
del_status = _delete_template(client, template_id)
result["delete_status"] = del_status
except Exception as e:
result["error"] = (result["error"] or "") + f" delete exception: {e!r}"
client.templates.clear_cache()
return result, template_id
def main():
print(f"Probing {UWAZI_URL} as {UWAZI_USER}\n")
for prop_type in (PropertyType.IMAGE, PropertyType.PREVIEW):
print(f"=== Property type: {prop_type.value} ===")
for value in CANDIDATE_STYLES:
r, _ = probe(value, prop_type)
print(
f" input={r['input']!r:18} "
f"create={r['create_status']} "
f"raw_stored={r['raw_stored_style']!r:20} "
f"read_back_style={r['read_back_style']!r} "
f"err={r['error']}"
)
if r["create_status"] not in (200, 201) and r["create_body"] is not None:
snippet = str(r["create_body"])[:200]
print(f" body: {snippet}")
print()
if __name__ == "__main__":
main()