implement new invitation system

* fix comments on the frontend
* move jwt token service to its own module
* other fixes and updates
This commit is contained in:
Philipinho
2024-05-14 22:55:11 +01:00
parent 525990d6e5
commit eefe63d1cd
75 changed files with 10965 additions and 7846 deletions

View File

@ -9,9 +9,21 @@ export class EnvironmentService {
return this.configService.get<string>('NODE_ENV');
}
getAppUrl(): string {
return (
this.configService.get<string>('APP_URL') ||
'http://localhost:' + this.getPort()
);
}
getPort(): number {
return parseInt(this.configService.get<string>('PORT'));
}
getAppSecret(): string {
return this.configService.get<string>('APP_SECRET');
}
getDatabaseURL(): string {
return this.configService.get<string>('DATABASE_URL');
}

View File

@ -7,6 +7,9 @@ export class EnvironmentVariables {
@IsUrl({ protocols: ['postgres', 'postgresql'], require_tld: false })
DATABASE_URL: string;
@IsString()
APP_SECRET: string;
}
export function validate(config: Record<string, any>) {
@ -14,7 +17,13 @@ export function validate(config: Record<string, any>) {
const errors = validateSync(validatedConfig);
if (errors.length > 0) {
throw new Error(errors.toString());
errors.map((error) => {
console.error(error.toString());
});
console.log(
'Please fix the environment variables and try again. Shutting down...',
);
process.exit(1);
}
return validatedConfig;
}

View File

@ -18,8 +18,9 @@ export class MailService {
async sendEmail(message: MailMessage): Promise<void> {
if (message.template) {
// in case this method is used directly
message.html = render(message.template);
// in case this method is used directly. we do not send the tsx template from queue
message.html = render(message.template, { pretty: true });
message.text = render(message.template, { plainText: true });
}
const sender = `${this.environmentService.getMailFromName()} <${this.environmentService.getMailFromAddress()}> `;
@ -29,7 +30,10 @@ export class MailService {
async sendToQueue(message: MailMessage): Promise<void> {
if (message.template) {
// transform the React object because it gets lost when sent via the queue
message.html = render(message.template);
message.html = render(message.template, { pretty: true });
message.text = render(message.template, {
plainText: true,
});
delete message.template;
}
await this.emailQueue.add(QueueJob.SEND_EMAIL, message);

View File

@ -23,7 +23,7 @@ export const paragraph = {
fontFamily:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
color: '#333',
lineHeight: 1.5,
lineHeight: 1,
fontSize: 14,
};
@ -51,3 +51,16 @@ export const footer = {
maxWidth: '580px',
margin: '0 auto',
};
export const button = {
backgroundColor: '#176ae5',
borderRadius: '3px',
color: '#fff',
fontFamily: "'Open Sans', 'Helvetica Neue', Arial",
fontSize: '16px',
textDecoration: 'none',
textAlign: 'center' as const,
display: 'block',
width: '100px',
padding: '8px',
};

View File

@ -3,11 +3,11 @@ import * as React from 'react';
import { content, paragraph } from '../css/styles';
import { MailBody } from '../partials/partials';
interface ChangePasswordEmailProps {
interface Props {
username?: string;
}
export const ChangePasswordEmail = ({ username }: ChangePasswordEmailProps) => {
export const ChangePasswordEmail = ({ username }: Props) => {
return (
<MailBody>
<Section style={content}>

View File

@ -0,0 +1,28 @@
import { Section, Text } from '@react-email/components';
import * as React from 'react';
import { content, paragraph } from '../css/styles';
import { MailBody } from '../partials/partials';
interface Props {
invitedUserName: string;
invitedUserEmail: string;
}
export const InvitationAcceptedEmail = ({
invitedUserName,
invitedUserEmail,
}: Props) => {
return (
<MailBody>
<Section style={content}>
<Text style={paragraph}>Hi there,</Text>
<Text style={paragraph}>
{invitedUserName} ({invitedUserEmail}) has accepted your invitation,
and is now a member of the workspace.
</Text>
</Section>
</MailBody>
);
};
export default InvitationAcceptedEmail;

View File

@ -0,0 +1,37 @@
import { Section, Text, Button } from '@react-email/components';
import * as React from 'react';
import { button, content, paragraph } from '../css/styles';
import { MailBody } from '../partials/partials';
interface Props {
inviteLink: string;
}
export const InvitationEmail = ({ inviteLink }: Props) => {
return (
<MailBody>
<Section style={content}>
<Text style={paragraph}>Hi there,</Text>
<Text style={paragraph}>You have been invited to Docmost.</Text>
<Text style={paragraph}>
Please click the button below to accept this invitation.
</Text>
</Section>
<Section
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
paddingLeft: '15px',
paddingBottom: '15px',
}}
>
<Button href={inviteLink} style={button}>
Accept Invite
</Button>
</Section>
</MailBody>
);
};
export default InvitationEmail;

View File

@ -40,7 +40,7 @@ export function MailFooter() {
<Section style={footer}>
<Row>
<Text style={{ textAlign: 'center', color: '#706a7b' }}>
© {new Date().getFullYear()}, All Rights Reserved <br />
© {new Date().getFullYear()} Docmost, All Rights Reserved <br />
</Text>
</Row>
</Section>