• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DemocracyClub / aggregator-api / 932b0b48-8d1a-4bbd-a9fd-a090d6114750

pending completion
932b0b48-8d1a-4bbd-a9fd-a090d6114750

push

circleci

Sym Roe
Use S3 ballot cache rather than WCIVF directly

507 of 582 relevant lines covered (87.11%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.71
/api/common/middleware.py
1
from common.auth_models import User
1✔
2
from starlette.datastructures import Headers, QueryParams
1✔
3
from starlette.middleware import Middleware
1✔
4
from starlette.middleware.cors import CORSMiddleware
1✔
5

6

7
class ForwardedForMiddleware:
1✔
8
    def __init__(
1✔
9
        self,
10
        app,
11
    ):
12
        self.app = app
1✔
13

14
    async def __call__(self, scope, receive, send):
1✔
15
        if scope["type"] == "http":
1✔
16
            headers = Headers(scope=scope)
1✔
17
            forwarded_for = (
1✔
18
                headers.get("x-forwarded-host", "").split(":")[0].encode()
19
            )
20
            if forwarded_for:
1✔
21
                for i, header in enumerate(scope["headers"]):
×
22
                    if header[0] == b"host":
×
23
                        scope["headers"].pop(i)
×
24
                scope["headers"].append((b"host", forwarded_for))
×
25
        await self.app(scope, receive, send)
1✔
26

27

28
class UTMParamsMiddleware:
1✔
29
    """
30
    Pull any UTM tracking params from the querystring and attach them to the
31
    scope for use later.
32

33
    This saves parsing the querystring in each view, and standardises the
34
    use of UTM params.
35
    """
36

37
    def __init__(self, app):
1✔
38
        self.app = app
1✔
39

40
    async def __call__(self, scope, receive, send):
1✔
41
        utm_dict = {}
1✔
42
        params = QueryParams(scope.get("query_string"))
1✔
43

44
        utm_dict["utm_source"] = params.get("utm_source")
1✔
45
        utm_dict["utm_campaign"] = params.get("utm_campaign")
1✔
46
        utm_dict["utm_medium"] = params.get("utm_medium")
1✔
47

48
        scope["utm_dict"] = utm_dict
1✔
49
        await self.app(scope, receive, send)
1✔
50

51

52
class APIGatewayAuthenticatorContextMiddleware:
1✔
53
    """
54
    Some app functions are behind an AWS API Gateway Authorizer.
55

56
    The Authorizer will control access to the Lambdas functions "behind" it,
57
    and will also insert context data about the authenticated user.
58

59
    We want to use this data when logging access, so this middleware parses the
60
    context in to a User model that can be used by functions.
61

62
    There are two other cases to consider:
63

64
    1. When we're on AWS Lambda but running an unauthenticated function.
65
       We don't know who the user is in this case, so we can just create a fake user
66
    2. When we're not on AWS Lambda, like when running tests or local dev.
67

68
    """
69

70
    def __init__(self, app):
1✔
71
        self.app = app
1✔
72

73
    async def __call__(self, scope, receive, send):
1✔
74
        aws_event = scope.get("aws.event", {})
1✔
75
        authorizer_data = aws_event.get("requestContext", {}).get(
1✔
76
            "authorizer", {}
77
        )
78

79
        if authorizer_data:
1✔
80
            # We've been passed through an authorizer so we can create a User model
81
            user = User.from_authorizer_data(authorizer_data)
×
82
        elif aws_event:
1✔
83
            # We're on AWS Lambda, but this isn't a function with an authorizer
84
            user = User(
×
85
                user_id="unauthenticated_user", api_key="unauthenticated_user"
86
            )
87
        else:
88
            # We're not on AWS Lambda
89
            user = User(user_id="direct_access", api_key="local-dev")
1✔
90

91
        scope["api_user"] = user
1✔
92
        await self.app(scope, receive, send)
1✔
93

94

95
MIDDLEWARE = [
1✔
96
    Middleware(ForwardedForMiddleware),
97
    Middleware(
98
        CORSMiddleware,
99
        allow_origins=["*"],
100
        allow_headers=["Token", "Origin", "X-Requested-With"],
101
    ),
102
    Middleware(UTMParamsMiddleware),
103
    Middleware(APIGatewayAuthenticatorContextMiddleware),
104
]
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc