Spaces:
Paused
Paused
Download iserv-filter/browser_source.py from Luca448/APP-Backend: direct link, hf CLI and curl.
- Browser
- Download file 3.57 kB
-
https://huggingface.co/spaces/Luca448/APP-Backend/resolve/main/iserv-filter/browser_source.py
- Command line
-
hf download hf://spaces/Luca448/APP-Backend/iserv-filter/browser_source.py
-
curl -L -o browser_source.py https://huggingface.co/spaces/Luca448/APP-Backend/resolve/main/iserv-filter/browser_source.py
3.57 kB
| """Adapter for the Puppeteer fetcher (src/api/iserv.js of the app backend): its JSON in, tasks in the shape | |
| filter_task takes. Only title, description, dates, tags, the task id inside the url and the provided files are taken; | |
| the url itself (= the school domain) and the fetcher's own `id` (the same url) are dropped. | |
| The fetcher grew additive fields for this (descriptionText, tags, start, due, done, provided, attachmentsFailed). | |
| Without them (an older fetcher) the fields stay empty: no subject, no start date, no done flag, `description` is the | |
| broad block it always returned, and a file that failed to download is simply missing.""" | |
| import base64 | |
| import re | |
| from iserv import MAX_ATTACHMENTS, iso_date | |
| # the fetcher's own censor() writes these; they become the placeholders of the rest of the output (the NER filter | |
| # would turn "<NAME>" into "<[ORGANISATION]>") | |
| _PLACEHOLDERS = {"<NAME>": "[PERSON]", "<EMAIL>": "[KONTAKT]", "<TELEFON>": "[KONTAKT]"} | |
| _ISO = re.compile(r"\d{4}-\d{2}-\d{2}(T\d{2}:\d{2})?") | |
| def _text(value): | |
| value = value if isinstance(value, str) else "" | |
| for old, new in _PLACEHOLDERS.items(): | |
| value = value.replace(old, new) | |
| return value | |
| def _iso(value): | |
| """Dates are passed on as they are, so only a date in ISO form may pass: anything else would skip the filter.""" | |
| return value if isinstance(value, str) and _ISO.fullmatch(value) else None | |
| def _attachment(item): | |
| name = _text(item.get("filename")) | |
| try: | |
| data = base64.b64decode(item["data"], validate=True) | |
| except Exception: # missing or broken base64 | |
| return {"name": name, "failed": True} | |
| return {"name": name, "size": len(data), "data": data} | |
| def _failure(item): | |
| name = _text(item.get("filename")) | |
| return {"name": name, "size": None, "data": None} if item.get("reason") == "too_large" else {"name": name, "failed": True} | |
| def _files(item): | |
| """The files the teacher provided: downloaded ones, then the ones that could not be downloaded. A file of the own | |
| submission or of the teacher's feedback (provided is False) is never taken.""" | |
| def dicts(key): | |
| return [f for f in item.get(key) or [] if isinstance(f, dict) and f.get("provided") is not False] | |
| files = [_attachment(f) for f in dicts("attachments")] + [_failure(f) for f in dicts("attachmentsFailed")] | |
| return files[:MAX_ATTACHMENTS] + ([{"skipped": True}] if len(files) > MAX_ATTACHMENTS else []) | |
| def from_browser(items): | |
| """Tasks for filter_task. When the fetcher finds no rows (empty list, failed login) it invents three tasks | |
| (flagged mock, and without /exercise/show/<id> in their url); they are dropped here.""" | |
| tasks = [] | |
| for item in items: | |
| m = re.search(r"/exercise/show/(\d+)", item.get("url") or "") | |
| if not m or item.get("mock"): | |
| continue | |
| task = { | |
| "id": int(m.group(1)), | |
| "title": _text(item.get("title")), | |
| # descriptionText: only the task's own description. description: the broad block of older fetchers. | |
| "description": _text(item["descriptionText"] if isinstance(item.get("descriptionText"), str) else item.get("description")), | |
| "tags": _text(item.get("tags")), | |
| "start": _iso(item.get("start")), | |
| "due": _iso(item.get("due")) or iso_date(item.get("deadline") or ""), | |
| "attachments": _files(item), | |
| } | |
| if isinstance(item.get("done"), bool): | |
| task["done"] = item["done"] # no key = unknown: status null | |
| tasks.append(task) | |
| return tasks | |