Skip to content

Commit 5acf59d

Browse files
committed
feat: add responsive email template + support for org env
Resolves #52
1 parent 12d795b commit 5acf59d

File tree

10 files changed

+283
-80
lines changed

10 files changed

+283
-80
lines changed

TODO.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@ For the first version we will only support setting roles master list via env
1414
- [x] Return roles in users list for super admin
1515
- [x] Add roles to the JWT token generation
1616
- [x] Validate token should also validate the role, if roles to validate again is present in request
17+
18+
# Misc
19+
20+
- [x] Fix email template
21+
- [x] Add support for organization name in .env
22+
- [x] Add support for organization logo in .env

app/build/bundle.js

Lines changed: 21 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build/bundle.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/App.tsx

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,52 @@ import { AuthorizerProvider } from '@authorizerdev/authorizer-react';
44
import Root from './Root';
55

66
export default function App() {
7-
// @ts-ignore
8-
const globalState: Record<string, string> = window['__authorizer__'];
9-
return (
10-
<div style={{ display: 'flex', justifyContent: 'center' }}>
11-
<div
12-
style={{
13-
width: 400,
14-
margin: `10px auto`,
15-
border: `1px solid #D1D5DB`,
16-
padding: `25px 20px`,
17-
borderRadius: 5,
18-
}}
19-
>
20-
<BrowserRouter>
21-
<AuthorizerProvider
22-
config={{
23-
authorizerURL: globalState.authorizerURL,
24-
redirectURL: globalState.redirectURL,
25-
}}
26-
>
27-
<Root />
28-
</AuthorizerProvider>
29-
</BrowserRouter>
30-
</div>
31-
</div>
32-
);
7+
// @ts-ignore
8+
const globalState: Record<string, string> = window['__authorizer__'];
9+
return (
10+
<div
11+
style={{
12+
display: 'flex',
13+
justifyContent: 'center',
14+
flexDirection: 'column',
15+
}}
16+
>
17+
<div
18+
style={{
19+
display: 'flex',
20+
justifyContent: 'center',
21+
marginTop: 20,
22+
flexDirection: 'column',
23+
alignItems: 'center',
24+
}}
25+
>
26+
<img
27+
src={`${globalState.organizationLogo}`}
28+
alt="logo"
29+
style={{ height: 60, width: 60, objectFit: 'cover' }}
30+
/>
31+
<h1>{globalState.organizationName}</h1>
32+
</div>
33+
<div
34+
style={{
35+
width: 400,
36+
margin: `10px auto`,
37+
border: `1px solid #D1D5DB`,
38+
padding: `25px 20px`,
39+
borderRadius: 5,
40+
}}
41+
>
42+
<BrowserRouter>
43+
<AuthorizerProvider
44+
config={{
45+
authorizerURL: globalState.authorizerURL,
46+
redirectURL: globalState.redirectURL,
47+
}}
48+
>
49+
<Root />
50+
</AuthorizerProvider>
51+
</BrowserRouter>
52+
</div>
53+
</div>
54+
);
3355
}

app/src/Root.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export default function Root() {
1010

1111
useEffect(() => {
1212
if (token) {
13-
const url = new URL(config.redirectURL);
13+
const url = new URL(config.redirectURL || '/app');
1414
if (url.origin !== window.location.origin) {
15-
window.location.href = config.redirectURL;
15+
window.location.href = config.redirectURL || '/app';
1616
}
1717
}
1818
return () => {};

app/src/pages/login.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import React, { Fragment } from 'react';
22
import { Authorizer } from '@authorizerdev/authorizer-react';
33

44
export default function Login() {
5-
return (
6-
<Fragment>
7-
<Authorizer />
8-
</Fragment>
9-
);
5+
return (
6+
<Fragment>
7+
<Authorizer />
8+
</Fragment>
9+
);
1010
}

server/constants/constants.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,8 @@ var (
3737
FACEBOOK_CLIENT_SECRET = ""
3838
TWITTER_CLIENT_ID = ""
3939
TWITTER_CLIENT_SECRET = ""
40+
41+
// Org envs
42+
ORGANIZATION_NAME = "Authorizer"
43+
ORGANIZATION_LOGO = "https://authorizer.dev/images/logo.png"
4044
)

server/env.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,12 @@ func InitEnv() {
174174
if constants.JWT_ROLE_CLAIM == "" {
175175
constants.JWT_ROLE_CLAIM = "role"
176176
}
177+
178+
if os.Getenv("ORGANIZATION_NAME") != "" {
179+
constants.ORGANIZATION_NAME = os.Getenv("ORGANIZATION_NAME")
180+
}
181+
182+
if os.Getenv("ORGANIZATION_LOGO") != "" {
183+
constants.ORGANIZATION_LOGO = os.Getenv("ORGANIZATION_LOGO")
184+
}
177185
}

server/handlers/app.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ func AppHandler() gin.HandlerFunc {
7575
}
7676
c.HTML(http.StatusOK, "app.tmpl", gin.H{
7777
"data": map[string]string{
78-
"authorizerURL": stateObj.AuthorizerURL,
79-
"redirectURL": stateObj.RedirectURL,
78+
"authorizerURL": stateObj.AuthorizerURL,
79+
"redirectURL": stateObj.RedirectURL,
80+
"organizationName": constants.ORGANIZATION_NAME,
81+
"organizationLogo": constants.ORGANIZATION_LOGO,
8082
},
8183
})
8284
}

server/utils/email.go

Lines changed: 183 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,96 @@ func SendVerificationMail(toEmail, token string) error {
1616

1717
Subject := "Please verify your email"
1818
message := fmt.Sprintf(`
19-
<!DOCTYPE HTML PULBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
20-
<html>
21-
<head>
22-
<meta http-equiv="content-type" content="text/html"; charset=ISO-8859-1">
23-
</head>
24-
<body>
25-
<h1>Please verify your email by clicking on the link below </h1><br/>
26-
<a href="%s">Click here to verify</a>
27-
</body>
28-
</html>
29-
`, constants.AUTHORIZER_URL+"/verify_email"+"?token="+token)
19+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
20+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
21+
22+
<head>
23+
<meta charset="UTF-8">
24+
<meta content="width=device-width, initial-scale=1" name="viewport">
25+
<meta name="x-apple-disable-message-reformatting">
26+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
27+
<meta content="telephone=no" name="format-detection">
28+
<title></title>
29+
<!--[if (mso 16)]>
30+
<style type="text/css">
31+
a {}
32+
</style>
33+
<![endif]-->
34+
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
35+
<!--[if gte mso 9]>
36+
<xml>
37+
<o:OfficeDocumentSettings>
38+
<o:AllowPNG></o:AllowPNG>
39+
<o:PixelsPerInch>96</o:PixelsPerInch>
40+
</o:OfficeDocumentSettings>
41+
</xml>
42+
<![endif]-->
43+
</head>
44+
45+
<body>
46+
<div class="es-wrapper-color">
47+
<!--[if gte mso 9]>
48+
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
49+
<v:fill type="tile" color="#ffffff"></v:fill>
50+
</v:background>
51+
<![endif]-->
52+
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
53+
<tbody>
54+
<tr>
55+
<td class="esd-email-paddings" valign="top">
56+
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
57+
<tbody>
58+
<tr>
59+
<td class="esd-stripe" align="center">
60+
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
61+
<tbody>
62+
<tr>
63+
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
64+
<table width="100%%" cellspacing="0" cellpadding="0">
65+
<tbody>
66+
<tr>
67+
<td class="esd-container-frame" width="518" align="left">
68+
<table width="100%%" cellspacing="0" cellpadding="0">
69+
<tbody>
70+
<tr>
71+
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0" align="center"><a target="_blank"><img src="%s" alt="icon" style="display: block;" title="icon" width="30"></a></td>
72+
</tr>
73+
<tr>
74+
<td class="esd-block-text es-m-txt-c" align="center">
75+
<h2>Hey there 👋<br></h2>
76+
</td>
77+
</tr>
78+
<tr>
79+
<td class="esd-block-text es-m-txt-c es-p15t" align="center">
80+
<p>We received a request to signup for <b>%s</b>. If this is correct, please confirm by clicking the button below.</p>
81+
</td>
82+
</tr>
83+
<tr>
84+
<td class="esd-block-button es-p20t es-p15b es-p10r es-p10l" align="center"><span class="es-button-border"><a href="%s" class="es-button" target="_blank" style="text-decoration: none;padding:10px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1.2em;">Confirm Email</a></span></td>
85+
</tr>
86+
</tbody>
87+
</table>
88+
</td>
89+
</tr>
90+
</tbody>
91+
</table>
92+
</td>
93+
</tr>
94+
</tbody>
95+
</table>
96+
</td>
97+
</tr>
98+
</tbody>
99+
</table>
100+
</td>
101+
</tr>
102+
</tbody>
103+
</table>
104+
</div>
105+
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
106+
</body>
107+
</html>
108+
`, constants.ORGANIZATION_LOGO, constants.ORGANIZATION_NAME, constants.AUTHORIZER_URL+"/verify_email"+"?token="+token)
30109
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
31110

32111
return sender.SendMail(Receiver, Subject, bodyMessage)
@@ -46,17 +125,99 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
46125
Subject := "Reset Password"
47126

48127
message := fmt.Sprintf(`
49-
<!DOCTYPE HTML PULBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
50-
<html>
51-
<head>
52-
<meta http-equiv="content-type" content="text/html"; charset=ISO-8859-1">
53-
</head>
54-
<body>
55-
<h1>Please use the link below to reset password </h1><br/>
56-
<a href="%s">Reset Password</a>
57-
</body>
58-
</html>
59-
`, constants.RESET_PASSWORD_URL+"?token="+token)
128+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
129+
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
130+
131+
<head>
132+
<meta charset="UTF-8">
133+
<meta content="width=device-width, initial-scale=1" name="viewport">
134+
<meta name="x-apple-disable-message-reformatting">
135+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
136+
<meta content="telephone=no" name="format-detection">
137+
<title></title>
138+
<!--[if (mso 16)]>
139+
<style type="text/css">
140+
a {text-decoration: none;}
141+
.es-button {
142+
143+
}
144+
</style>
145+
<![endif]-->
146+
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
147+
<!--[if gte mso 9]>
148+
<xml>
149+
<o:OfficeDocumentSettings>
150+
<o:AllowPNG></o:AllowPNG>
151+
<o:PixelsPerInch>96</o:PixelsPerInch>
152+
</o:OfficeDocumentSettings>
153+
</xml>
154+
<![endif]-->
155+
</head>
156+
157+
<body>
158+
<div class="es-wrapper-color">
159+
<!--[if gte mso 9]>
160+
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
161+
<v:fill type="tile" color="#ffffff"></v:fill>
162+
</v:background>
163+
<![endif]-->
164+
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
165+
<tbody>
166+
<tr>
167+
<td class="esd-email-paddings" valign="top">
168+
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
169+
<tbody>
170+
<tr>
171+
<td class="esd-stripe" align="center">
172+
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
173+
<tbody>
174+
<tr>
175+
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
176+
<table width="100%%" cellspacing="0" cellpadding="0">
177+
<tbody>
178+
<tr>
179+
<td class="esd-container-frame" width="518" align="left">
180+
<table width="100%%" cellspacing="0" cellpadding="0">
181+
<tbody>
182+
<tr>
183+
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0" align="center"><a target="_blank"><img src="%s" alt="icon" style="display: block;" title="icon" width="30"></a></td>
184+
</tr>
185+
<tr>
186+
<td class="esd-block-text es-m-txt-c" align="center">
187+
<h2>Hey there 👋<br></h2>
188+
</td>
189+
</tr>
190+
<tr>
191+
<td class="esd-block-text es-m-txt-c es-p15t" align="center">
192+
<p>We received a request to reset password for email: <b>%s</b>. If this is correct, please reset the password clicking the button below.</p>
193+
</td>
194+
</tr>
195+
<tr>
196+
<td class="esd-block-button es-p20t es-p15b es-p10r es-p10l" align="center"><span class="es-button-border"><a href="%s" class="es-button" target="_blank" style="text-decoration: none;padding:10px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1.2em;">Reset Password</a></span></td>
197+
</tr>
198+
</tbody>
199+
</table>
200+
</td>
201+
</tr>
202+
</tbody>
203+
</table>
204+
</td>
205+
</tr>
206+
</tbody>
207+
</table>
208+
</td>
209+
</tr>
210+
</tbody>
211+
</table>
212+
</td>
213+
</tr>
214+
</tbody>
215+
</table>
216+
</div>
217+
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
218+
</body>
219+
</html>
220+
`, constants.ORGANIZATION_LOGO, toEmail, constants.AUTHORIZER_URL+"/verify_email"+"?token="+token)
60221
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
61222

62223
return sender.SendMail(Receiver, Subject, bodyMessage)

0 commit comments

Comments
 (0)