added mail service

This commit is contained in:
2024-04-10 21:24:25 +03:00
parent c76d4b9717
commit 78107d4ec7
80 changed files with 3478 additions and 329 deletions

75
config/auth.ts Normal file
View File

@@ -0,0 +1,75 @@
import NextAuth from 'next-auth'
import { UserRole } from '@prisma/client'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { db } from '@/lib/db'
import authConfig from '@/auth.config'
import { getUserById } from '@/data/user'
import { AUTH_ERROR_URL, AUTH_LOGIN_URL } from '@/config/routes'
declare module 'next-auth' {
interface Session {
user: { role: UserRole }
}
}
export const VERIFICATION_TOKEN_EXPIRATION_DURATION = 3_600_000
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
pages: {
signIn: AUTH_LOGIN_URL,
error: AUTH_ERROR_URL,
},
events: {
async linkAccount ({ user }) {
await db.user.update({
where: { id: user.id as string },
data: { emailVerified: new Date() },
})
},
},
callbacks: {
async signIn ({ user, account }) {
// Bypass email verification when Oauth are being used
if (account?.provider !== 'credentials') return true
const existingUser = await getUserById(user.id as string)
// Prevent sign in without email verification
if (!existingUser?.emailVerified) return false
// TODO: Add 2FA check
return true
},
async session ({ token, session }) {
if (token.sub && session.user) {
session.user.id = token.sub
}
if (token.role && session.user) {
session.user.role = token.role as UserRole
}
return session
},
async jwt ({ token }) {
if (!token.sub) return token
const existingUser = await getUserById(token.sub)
if (!existingUser) return token
token.role = existingUser.role
return token
},
},
adapter: PrismaAdapter(db),
session: { strategy: 'jwt' },
...authConfig,
})

1
config/layout.ts Normal file
View File

@@ -0,0 +1 @@
export const bg: string = 'bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-sky-400 to-blue-800'

30
config/locales.ts Normal file
View File

@@ -0,0 +1,30 @@
// @https://www.localeplanet.com/icu/index.html
const defaultLocale = 'uk'
export type loc = ('uk' | 'en')
const importLocales = {
uk: () => import('@/locales/uk'), en: () => import('@/locales/en'),
}
const LC = [
{
id: 'uk_UA',
java: 'uk-UA',
iso: 'ukr',
code: 'uk',
name: 'Ukrainian',
originalName: 'Українська',
},
{
id: 'en_US',
java: 'en-US',
iso: 'eng',
code: 'en',
name: 'English',
originalName: 'English',
}]
const locales = LC.map(locale => locale.code)
export { locales, defaultLocale, LC, importLocales }

16
config/mailer.ts Normal file
View File

@@ -0,0 +1,16 @@
import { env } from 'process'
import SMTPTransport from 'nodemailer/lib/smtp-transport'
export const from: string = `"${env.MAIL_SERVER_SENDER_NAME}" <${env.MAIL_SERVER_USERNAME}>`
export const transportOptions: SMTPTransport | SMTPTransport.Options | string = {
host: env.MAIL_SERVER_HOST,
debug: env.MAIL_SERVER_DEBUG === 'true',
logger: env.MAIL_SERVER_LOG === 'true',
port: parseInt(env.MAIL_SERVER_PORT as string),
secure: env.MAIL_SERVER_PORT === '465', // Use `true` for port 465, `false` for all other ports
auth: {
user: env.MAIL_SERVER_USERNAME, pass: env.MAIL_SERVER_PASSWORD,
},
}

44
config/routes.ts Normal file
View File

@@ -0,0 +1,44 @@
import { locales } from '@/config/locales'
export const USER_PROFILE_URL: string = '/cabinet'
export const AUTH_LOGIN_URL: string = '/auth/login'
export const AUTH_REGISTER_URL: string = '/auth/register'
export const AUTH_ERROR_URL: string = '/auth/error'
export const AUTH_EMAIL_VERIFICATION_URL: string = '/auth/email-verification'
/**
* An array of routes that accessible to the public.
* These routes do not requite authentication.
* @type {string[]}
*/
export const publicRoutes: string[] = [
'/', '/about']
/**
* An array of routes that are used for authentication.
* These routes will redirect logged-in users to /cabinet
* @type {string[]}
*/
export const authRoutes: string[] = [
AUTH_LOGIN_URL, AUTH_REGISTER_URL, AUTH_ERROR_URL, AUTH_EMAIL_VERIFICATION_URL]
/**
* The prefix for API authentication routes.
* Routes that start with this prefix are used for API authentication purpose.
* @type {string}
*/
export const apiAuthPrefix: string = '/api/auth'
/**
* The default redirect path after logging in.
* @type {string}
*/
export const DEFAULT_LOGIN_REDIRECT: string = USER_PROFILE_URL
export const testPathnameRegex = (
pages: string[], pathName: string): boolean => {
const pattern: string = `^(/(${locales.join('|')}))?(${pages.flatMap(
(p) => (p === '/' ? ['', '/'] : p)).join('|')})/?$`
return RegExp(pattern, 'is').test(pathName)
}

2
config/validation.ts Normal file
View File

@@ -0,0 +1,2 @@
export const MIN_PASSWORD_LENGTH: number = 6
export const PASSWORD_SALT_LENGTH: number = 10