-
Notifications
You must be signed in to change notification settings - Fork 1
/
website.py
142 lines (115 loc) · 5 KB
/
website.py
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
import os
from dataclasses import dataclass
from typing import Optional
import boto3
from microarchive import MicroArchive
from store import StoreSettings
from jinja2 import Environment, FileSystemLoader, select_autoescape
env = Environment(
extensions=['jinja_markdown.MarkdownExtension'],
loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))),
autoescape=select_autoescape()
)
def get_random_string(length: int) -> str:
import random, string
# choose from all lowercase letter
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(length))
class DistributionNotFound(Exception):
def __init__(self, site_id: str):
super(DistributionNotFound, self).__init__(f"Distribution not found with id {site_id}")
self.site_id = site_id
@dataclass
class SiteInfo:
id: str
domain: str
origin_id: str
status: str
def url(self):
return f"https://{self.domain}"
def make_html(slug: str, desc: MicroArchive, site_key: str) -> str:
return env.get_template("index.html.j2").render(name=slug, key=site_key, data=desc)
class Website:
def __init__(self, settings: StoreSettings):
self.settings = settings
self.client = self.client("cloudfront")
def client(self, service: str):
return boto3.client(service,
region_name=self.settings.region,
aws_access_key_id=self.settings.access_key,
aws_secret_access_key=self.settings.secret_key,)
def get_or_create_site(self, name: str, site_id: Optional[str] = None) -> SiteInfo:
"""If site_id is given, fetch the distribution info.
Otherwise, create the distribution."""
if site_id:
return self.get_site(site_id)
else:
return self.create_site(name)
def get_site(self, site_id: str) -> SiteInfo:
"""Get the distribution info for the given `site_id`"""
r = self.client.get_distribution(Id=site_id)
return SiteInfo(
id=r["Distribution"]["Id"],
status=r["Distribution"]["Status"],
domain=r["Distribution"]["DomainName"],
origin_id=r["Distribution"]["DistributionConfig"]["Origins"]["Items"][0]["OriginPath"]
)
def create_site(self, name: str) -> SiteInfo:
"""Create a new site with the given name as the origin id"""
bucket = self.settings.bucket
region = self.settings.region
# this is simply a reference used within the distribution and could be random,
# but here we associate it with the given name.
origin_id = bucket + "_" + name
# the suffix for the uploaded material, on top of the
# suffix for the input files
site_suffix = get_random_string(5)
key_prefix = f"webdata_{site_suffix}/"
# s3.create_origin_access_policy()
# ref is simply a random string to ensure request cannot be replayed
ref = get_random_string(10)
# bucket domain
bucket_domain = f"{bucket}.s3.{region}.amazonaws.com"
r = self.client.create_distribution(
DistributionConfig={
'CallerReference': ref,
'Enabled': True,
'DefaultRootObject': 'index.html',
'HttpVersion': 'http2and3',
'PriceClass': 'PriceClass_100',
'Comment': 'Created by the EHRI-3 WP11 Demo tool',
'Origins': {
'Quantity': 1,
'Items': [{
'Id': origin_id,
'OriginPath': "/" + key_prefix[:-1], # slash must be at the start
'DomainName': bucket_domain,
# 'OriginAccessControlId': oac_id,
'S3OriginConfig': {
'OriginAccessIdentity': ''
}
}]
},
'DefaultCacheBehavior': {
# 'CachePolicyId': '658327ea-f89d-4fab-a63d-7e88639e58f6', # CachingOptimized (from docs)
'CachePolicyId': '4135ea2d-6df8-44a3-9df3-4b5a84be39ad', # CachingDisabled (from docs)
'ResponseHeadersPolicyId': '5cc3b908-e619-4b99-88e5-2cf7f45965bd', # Allow CORS
'TargetOriginId': origin_id,
'ViewerProtocolPolicy': 'allow-all',
'AllowedMethods': {
'Quantity': 2,
'Items' : ['GET', 'HEAD'],
'CachedMethods': {
'Quantity': 2,
'Items': ['GET', 'HEAD']
}
}
}
}
)
return SiteInfo(
id=r["Distribution"]["Id"],
status=r["Distribution"]["Status"],
domain=r["Distribution"]["DomainName"],
origin_id=r["Distribution"]["DistributionConfig"]["Origins"]["Items"][0]["OriginPath"]
)