1 """Methods for the report-event-attribution and report-aggregate-attribution endpoints"""
3 from typing
import List
, Optional
, Tuple
, TypedDict
5 from wptserve
.request
import Request
6 from wptserve
.stash
import Stash
7 from wptserve
.utils
import isomorphic_decode
, isomorphic_encode
9 # Key used to access the reports in the stash.
10 REPORTS
= "4691a2d7fca5430fb0f33b1bd8a9d388"
12 Header
= Tuple
[str, str]
13 Status
= Tuple
[int, str]
14 Response
= Tuple
[Status
, List
[Header
], str]
17 def decode_headers(headers
: dict) -> dict:
18 """Decodes the headers from wptserve.
20 wptserve headers are encoded like
22 encoded(key): [encoded(value1), encoded(value2),...]
24 This method decodes the above using the wptserve.utils.isomorphic_decode
28 isomorphic_decode(key
): [isomorphic_decode(el
) for el
in value
29 ] for key
, value
in headers
.items()
32 def get_request_origin(request
: Request
) -> str:
33 return "%s://%s" % (request
.url_parts
.scheme
,
34 request
.url_parts
.netloc
)
37 def handle_post_report(request
: Request
, headers
: List
[Header
]) -> Response
:
38 """Handles POST request for reports.
40 Retrieves the report from the request body and stores the report in the
44 request
.server
.stash
, get_request_origin(request
), {
45 "body": request
.body
.decode("utf-8"),
46 "headers": decode_headers(request
.headers
)
48 return (201, "OK"), headers
, json
.dumps({
50 "message": "Report successfully stored."
54 def handle_get_reports(request
: Request
, headers
: List
[Header
]) -> Response
:
55 """Handles GET request for reports.
57 Retrieves and returns all reports from the stash.
59 reports
= take_reports(request
.server
.stash
, get_request_origin(request
))
60 headers
.append(("Access-Control-Allow-Origin", "*"))
61 return (200, "OK"), headers
, json
.dumps({
67 def store_report(stash
: Stash
, origin
: str, report
: str) -> None:
68 """Stores the report in the stash. Report here is a JSON."""
70 reports_dict
= stash
.take(REPORTS
)
73 reports
= reports_dict
.get(origin
, [])
74 reports
.append(report
)
75 reports_dict
[origin
] = reports
76 stash
.put(REPORTS
, reports_dict
)
80 def take_reports(stash
: Stash
, origin
: str) -> List
[str]:
81 """Takes all the reports from the stash and returns them."""
83 reports_dict
= stash
.take(REPORTS
)
87 reports
= reports_dict
.pop(origin
, [])
88 stash
.put(REPORTS
, reports_dict
)
92 def handle_reports(request
: Request
) -> Response
:
93 """Handles request to get or store reports."""
94 headers
= [("Content-Type", "application/json")]
95 if request
.method
== "POST":
96 return handle_post_report(request
, headers
)
97 if request
.method
== "GET":
98 return handle_get_reports(request
, headers
)
99 return (405, "Method Not Allowed"), headers
, json
.dumps({
101 "message": "Only GET or POST methods are supported."