diff options
author | Mike Crute <mike@crute.us> | 2021-11-22 07:54:18 -0800 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2021-11-22 07:54:42 -0800 |
commit | 114dbb5ab7952ab66a041c814d5c6a028c8e3039 (patch) | |
tree | aecdeeb2e79b233775eb893c2abc0277cfd707fb | |
parent | 20484058825f0137a89712f41ae8c50dcc7e697d (diff) | |
download | cloud-identity-broker-114dbb5ab7952ab66a041c814d5c6a028c8e3039.tar.bz2 cloud-identity-broker-114dbb5ab7952ab66a041c814d5c6a028c8e3039.tar.xz cloud-identity-broker-114dbb5ab7952ab66a041c814d5c6a028c8e3039.zip |
Split assets from templates
-rw-r--r-- | cmd/web/server.go | 1 | ||||
-rw-r--r-- | templates/assets/site.css | 62 | ||||
-rw-r--r-- | templates/assets/site.js | 102 | ||||
-rw-r--r-- | templates/index.tpl | 171 |
4 files changed, 168 insertions, 168 deletions
diff --git a/cmd/web/server.go b/cmd/web/server.go index d2ea861..3797acd 100644 --- a/cmd/web/server.go +++ b/cmd/web/server.go | |||
@@ -154,6 +154,7 @@ func webMain(cfg app.Config, embeddedTemplates fs.FS, version string) { | |||
154 | } | 154 | } |
155 | s.GET("/favicon.ico", echo.NotFoundHandler) | 155 | s.GET("/favicon.ico", echo.NotFoundHandler) |
156 | s.GET("/logout", controllers.LogoutHandler) | 156 | s.GET("/logout", controllers.LogoutHandler) |
157 | s.CachedStaticRoute("/assets", "assets") | ||
157 | s.GET("/", controllers.IndexHandler, am.Middleware) | 158 | s.GET("/", controllers.IndexHandler, am.Middleware) |
158 | 159 | ||
159 | runner := service.NewAppRunner(ctx, s.Logger) | 160 | runner := service.NewAppRunner(ctx, s.Logger) |
diff --git a/templates/assets/site.css b/templates/assets/site.css new file mode 100644 index 0000000..65fb4ce --- /dev/null +++ b/templates/assets/site.css | |||
@@ -0,0 +1,62 @@ | |||
1 | html { | ||
2 | display: grid; | ||
3 | grid-template-columns: [left] 10% [main] auto [right] 10%; | ||
4 | grid-template-rows: [main] auto; | ||
5 | } | ||
6 | body { | ||
7 | grid-column: main; | ||
8 | grid-row: main; | ||
9 | } | ||
10 | table { | ||
11 | width: 100%; | ||
12 | border: 1px solid black; | ||
13 | border-collapse: collapse; | ||
14 | } | ||
15 | td, th { | ||
16 | border: 1px solid black; | ||
17 | padding: 0.5em; | ||
18 | } | ||
19 | th { | ||
20 | background-color: #CCCCCC; | ||
21 | } | ||
22 | textarea { | ||
23 | height: 10em; | ||
24 | width: 100%; | ||
25 | resize: none; | ||
26 | } | ||
27 | a, a:visited { | ||
28 | color: blue; | ||
29 | } | ||
30 | h1 { | ||
31 | text-align: center; | ||
32 | } | ||
33 | tt { | ||
34 | background-color: #CCC; | ||
35 | border: 1px solid #999; | ||
36 | padding: 0.25em; | ||
37 | } | ||
38 | #api-key { | ||
39 | margin: auto; | ||
40 | } | ||
41 | #api-key textarea { | ||
42 | height: 100%; | ||
43 | } | ||
44 | #api-error { | ||
45 | border: 0.25em solid red; | ||
46 | color: white; | ||
47 | font-size: 2em; | ||
48 | background-color: #ff8080; | ||
49 | padding: 1em; | ||
50 | text-align: center; | ||
51 | display: none; | ||
52 | } | ||
53 | #account-table tr td:nth-child(2), | ||
54 | #account-table tr td:nth-child(3) { | ||
55 | text-align: center; | ||
56 | } | ||
57 | .admin { | ||
58 | display: none; | ||
59 | } | ||
60 | body.isAdmin .admin { | ||
61 | display: initial; | ||
62 | } | ||
diff --git a/templates/assets/site.js b/templates/assets/site.js new file mode 100644 index 0000000..485a4cd --- /dev/null +++ b/templates/assets/site.js | |||
@@ -0,0 +1,102 @@ | |||
1 | function fillTemplate(templateId, values) { | ||
2 | var tpl = document.getElementById(templateId).text; | ||
3 | |||
4 | Object.keys(values).forEach(function(key) { | ||
5 | tpl = tpl.replace(new RegExp("\\[\\[ \\." + key + " \\]\\]", "g"), values[key]); | ||
6 | }); | ||
7 | |||
8 | var out = []; | ||
9 | tpl.split("\n").forEach(function(line) { | ||
10 | line = line.replace(/^\s+/, "").replace(/\s+$/, ""); | ||
11 | if (line !== "") { | ||
12 | out.push(line); | ||
13 | } | ||
14 | }); | ||
15 | |||
16 | return out.join("\n"); | ||
17 | } | ||
18 | |||
19 | function getJSON(response) { | ||
20 | if (!response.ok) { | ||
21 | document.getElementById("api-error").style.display = "block"; | ||
22 | throw new Error("Error loading api"); | ||
23 | } | ||
24 | |||
25 | return response.json(); | ||
26 | } | ||
27 | |||
28 | function accountTableLinkClick(event) { | ||
29 | event.preventDefault(); | ||
30 | |||
31 | var thisRow = event.target.parentElement.parentElement; | ||
32 | var template = event.target.getAttribute("data-template"); | ||
33 | var account = thisRow.getAttribute("data-account-name"); | ||
34 | var credentialEndpoint = thisRow.getAttribute("data-global-credential-endpoint"); | ||
35 | var oldText = event.target.text; | ||
36 | |||
37 | var existingTr = document.getElementById("credentials-for-" + account); | ||
38 | if (existingTr) { | ||
39 | existingTr.remove(); | ||
40 | } | ||
41 | |||
42 | event.target.text = "Loading..."; | ||
43 | |||
44 | fetch(credentialEndpoint).then(getJSON).then(function(vals) { | ||
45 | vals["ShortName"] = account; | ||
46 | |||
47 | var newTr = fillTemplate("credential_row_template", { | ||
48 | "Account": account, | ||
49 | "Content": fillTemplate(template, vals) | ||
50 | }); | ||
51 | |||
52 | event.target.text = oldText; | ||
53 | thisRow.insertAdjacentHTML("afterend", newTr); | ||
54 | thisRow.nextElementSibling.getElementsByTagName("button")[0].addEventListener("click", function(event) { | ||
55 | event.target.parentNode.parentNode.remove(); | ||
56 | }); | ||
57 | }); | ||
58 | |||
59 | return false; | ||
60 | } | ||
61 | |||
62 | function populateAccountTable() { | ||
63 | fetch("/api/account").then(getJSON).then(function(response) { | ||
64 | response.forEach(populateAccountRow); | ||
65 | }); | ||
66 | } | ||
67 | |||
68 | function populateAccountRow(row) { | ||
69 | var out = fillTemplate("account_row_template", row); | ||
70 | document.querySelector("#account-table tr").insertAdjacentHTML("afterend", out); | ||
71 | |||
72 | document.querySelectorAll("#account-row-" + row["short_name"] + " a[data-template]").forEach(function(element) { | ||
73 | element.addEventListener("click", accountTableLinkClick); | ||
74 | }); | ||
75 | } | ||
76 | |||
77 | function getCookie(name) { | ||
78 | return document.cookie.match(new RegExp(name + "=\"?([^;\"]*)\"?;?"))[1]; | ||
79 | } | ||
80 | |||
81 | function parseJWT(token) { | ||
82 | return JSON.parse(atob(token.split(".")[1])); | ||
83 | } | ||
84 | |||
85 | function parseJWTExpires(token) { | ||
86 | return new Date(parseJWT(token)["exp"] * 1000); | ||
87 | } | ||
88 | |||
89 | function isAdmin(token) { | ||
90 | return parseJWT(token)["admin"]; | ||
91 | } | ||
92 | |||
93 | function populateAPIKey() { | ||
94 | document.querySelector("#api-key textarea").innerText = getCookie("github-token"); | ||
95 | document.querySelector("#session-expires").innerText = parseJWTExpires(getCookie("github-token")); | ||
96 | } | ||
97 | |||
98 | function setAdminClass() { | ||
99 | if (isAdmin(getCookie("github-token"))) { | ||
100 | document.body.classList.add("isAdmin"); | ||
101 | } | ||
102 | } | ||
diff --git a/templates/index.tpl b/templates/index.tpl index 3a6acbf..da0b59e 100644 --- a/templates/index.tpl +++ b/templates/index.tpl | |||
@@ -3,70 +3,7 @@ | |||
3 | <head> | 3 | <head> |
4 | <title>Select Account</title> | 4 | <title>Select Account</title> |
5 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | 5 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
6 | <style type="text/css"> | 6 | <link rel="stylesheet" type="text/css" href="/assets/site.css" /> |
7 | html { | ||
8 | display: grid; | ||
9 | grid-template-columns: [left] 10% [main] auto [right] 10%; | ||
10 | grid-template-rows: [main] auto; | ||
11 | } | ||
12 | body { | ||
13 | grid-column: main; | ||
14 | grid-row: main; | ||
15 | } | ||
16 | table { | ||
17 | width: 100%; | ||
18 | border: 1px solid black; | ||
19 | border-collapse: collapse; | ||
20 | } | ||
21 | td, th { | ||
22 | border: 1px solid black; | ||
23 | padding: 0.5em; | ||
24 | } | ||
25 | th { | ||
26 | background-color: #CCCCCC; | ||
27 | } | ||
28 | textarea { | ||
29 | height: 10em; | ||
30 | width: 100%; | ||
31 | resize: none; | ||
32 | } | ||
33 | a, a:visited { | ||
34 | color: blue; | ||
35 | } | ||
36 | h1 { | ||
37 | text-align: center; | ||
38 | } | ||
39 | tt { | ||
40 | background-color: #CCC; | ||
41 | border: 1px solid #999; | ||
42 | padding: 0.25em; | ||
43 | } | ||
44 | #api-key { | ||
45 | margin: auto; | ||
46 | } | ||
47 | #api-key textarea { | ||
48 | height: 100%; | ||
49 | } | ||
50 | #api-error { | ||
51 | border: 0.25em solid red; | ||
52 | color: white; | ||
53 | font-size: 2em; | ||
54 | background-color: #ff8080; | ||
55 | padding: 1em; | ||
56 | text-align: center; | ||
57 | display: none; | ||
58 | } | ||
59 | #account-table tr td:nth-child(2), | ||
60 | #account-table tr td:nth-child(3) { | ||
61 | text-align: center; | ||
62 | } | ||
63 | .admin { | ||
64 | display: none; | ||
65 | } | ||
66 | body.isAdmin .admin { | ||
67 | display: initial; | ||
68 | } | ||
69 | </style> | ||
70 | <script id="shell_template" type="text/template"> | 7 | <script id="shell_template" type="text/template"> |
71 | export AWS_CREDS_EXPIRATION="[[ .expiration ]]" | 8 | export AWS_CREDS_EXPIRATION="[[ .expiration ]]" |
72 | export AWS_ACCESS_KEY_ID="[[ .access_key ]]" | 9 | export AWS_ACCESS_KEY_ID="[[ .access_key ]]" |
@@ -87,14 +24,12 @@ | |||
87 | expiration=[[ .expiration ]] | 24 | expiration=[[ .expiration ]] |
88 | </script> | 25 | </script> |
89 | <script id="credential_row_template" type="text/template"> | 26 | <script id="credential_row_template" type="text/template"> |
90 | <body> | ||
91 | <tr id="credentials-for-[[ .Account ]]"> | 27 | <tr id="credentials-for-[[ .Account ]]"> |
92 | <td colspan="3"> | 28 | <td colspan="3"> |
93 | <textarea>[[ .Content ]]</textarea> | 29 | <textarea>[[ .Content ]]</textarea> |
94 | <button>Close</button> | 30 | <button>Close</button> |
95 | </td> | 31 | </td> |
96 | </tr> | 32 | </tr> |
97 | </body> | ||
98 | </script> | 33 | </script> |
99 | <script id="account_row_template" type="text/template"> | 34 | <script id="account_row_template" type="text/template"> |
100 | <tr id="account-row-[[ .short_name ]]" data-account-name="[[ .short_name ]]" data-global-credential-endpoint="[[ .global_credential_url ]]"> | 35 | <tr id="account-row-[[ .short_name ]]" data-account-name="[[ .short_name ]]" data-global-credential-endpoint="[[ .global_credential_url ]]"> |
@@ -109,111 +44,11 @@ | |||
109 | </td> | 44 | </td> |
110 | </tr> | 45 | </tr> |
111 | </script> | 46 | </script> |
47 | <script type="text/javascript" src="/assets/site.js"></script> | ||
112 | <script type="text/javascript"> | 48 | <script type="text/javascript"> |
113 | function fillTemplate(templateId, values) { | ||
114 | var tpl = document.getElementById(templateId).text; | ||
115 | |||
116 | Object.keys(values).forEach(function(key) { | ||
117 | tpl = tpl.replace(new RegExp("\\[\\[ \\." + key + " \\]\\]", "g"), values[key]); | ||
118 | }); | ||
119 | |||
120 | var out = []; | ||
121 | tpl.split("\n").forEach(function(line) { | ||
122 | line = line.replace(/^\s+/, "").replace(/\s+$/, ""); | ||
123 | if (line !== "") { | ||
124 | out.push(line); | ||
125 | } | ||
126 | }); | ||
127 | |||
128 | return out.join("\n"); | ||
129 | } | ||
130 | |||
131 | function getJSON(response) { | ||
132 | if (!response.ok) { | ||
133 | document.getElementById("api-error").style.display = "block"; | ||
134 | throw new Error("Error loading api"); | ||
135 | } | ||
136 | |||
137 | return response.json(); | ||
138 | } | ||
139 | |||
140 | function accountTableLinkClick(event) { | ||
141 | event.preventDefault(); | ||
142 | |||
143 | var thisRow = event.target.parentElement.parentElement; | ||
144 | var template = event.target.getAttribute("data-template"); | ||
145 | var account = thisRow.getAttribute("data-account-name"); | ||
146 | var credentialEndpoint = thisRow.getAttribute("data-global-credential-endpoint"); | ||
147 | var oldText = event.target.text; | ||
148 | |||
149 | var existingTr = document.getElementById("credentials-for-" + account); | ||
150 | if (existingTr) { | ||
151 | existingTr.remove(); | ||
152 | } | ||
153 | |||
154 | event.target.text = "Loading..."; | ||
155 | |||
156 | fetch(credentialEndpoint).then(getJSON).then(function(vals) { | ||
157 | vals["ShortName"] = account; | ||
158 | |||
159 | var newTr = fillTemplate("credential_row_template", { | ||
160 | "Account": account, | ||
161 | "Content": fillTemplate(template, vals) | ||
162 | }); | ||
163 | |||
164 | event.target.text = oldText; | ||
165 | thisRow.insertAdjacentHTML("afterend", newTr); | ||
166 | thisRow.nextElementSibling.getElementsByTagName("button")[0].addEventListener("click", function(event) { | ||
167 | event.target.parentNode.parentNode.remove(); | ||
168 | }); | ||
169 | }); | ||
170 | |||
171 | return false; | ||
172 | } | ||
173 | |||
174 | function populateAccountTable() { | ||
175 | fetch("/api/account").then(getJSON).then(function(response) { | ||
176 | response.forEach(populateAccountRow); | ||
177 | }); | ||
178 | } | ||
179 | |||
180 | function populateAccountRow(row) { | ||
181 | var out = fillTemplate("account_row_template", row); | ||
182 | document.querySelector("#account-table tr").insertAdjacentHTML("afterend", out); | ||
183 | |||
184 | document.querySelectorAll("#account-row-" + row["short_name"] + " a[data-template]").forEach(function(element) { | ||
185 | element.addEventListener("click", accountTableLinkClick); | ||
186 | }); | ||
187 | } | ||
188 | |||
189 | function getCookie(name) { | ||
190 | return document.cookie.match(new RegExp(name + "=\"?([^;\"]*)\"?;?"))[1]; | ||
191 | } | ||
192 | |||
193 | function parseJWT(token) { | ||
194 | return JSON.parse(atob(token.split(".")[1])); | ||
195 | } | ||
196 | |||
197 | function parseJWTExpires(token) { | ||
198 | return new Date(parseJWT(token)["exp"] * 1000); | ||
199 | } | ||
200 | |||
201 | function isAdmin(token) { | ||
202 | return parseJWT(token)["admin"]; | ||
203 | } | ||
204 | |||
205 | function populateAPIKey() { | ||
206 | document.querySelector("#api-key textarea").innerText = getCookie("github-token"); | ||
207 | document.querySelector("#session-expires").innerText = parseJWTExpires(getCookie("github-token")); | ||
208 | } | ||
209 | |||
210 | window.addEventListener('load', populateAPIKey); | 49 | window.addEventListener('load', populateAPIKey); |
211 | window.addEventListener('load', populateAccountTable); | 50 | window.addEventListener('load', populateAccountTable); |
212 | window.addEventListener('load', function() { | 51 | window.addEventListener('load', setAdminClass); |
213 | if (isAdmin(getCookie("github-token"))) { | ||
214 | document.body.classList.add("isAdmin"); | ||
215 | } | ||
216 | }); | ||
217 | </script> | 52 | </script> |
218 | </head> | 53 | </head> |
219 | <body> | 54 | <body> |