129 lines
4.2 KiB
TypeScript
129 lines
4.2 KiB
TypeScript
import { betterAuth } from 'better-auth'
|
|
import Database from 'better-sqlite3'
|
|
import { organization, jwt } from 'better-auth/plugins'
|
|
import { resend } from './mail'
|
|
import {
|
|
accessControl,
|
|
employerRole,
|
|
worksCouncilMemberRole,
|
|
employeeRole,
|
|
adminRole,
|
|
ownerRole,
|
|
ROLES,
|
|
type LegalRole
|
|
} from './permissions'
|
|
|
|
const db = new Database('./sqlite.db')
|
|
|
|
export const auth = betterAuth({
|
|
database: db,
|
|
onAPIError: { throw: true },
|
|
emailAndPassword: { enabled: true, autoSignIn: false, minPasswordLength: 1 },
|
|
trustedOrigins: ['http://localhost:3001'],
|
|
plugins: [
|
|
jwt({
|
|
jwt: {
|
|
issuer: 'http://192.168.178.114:3001',
|
|
expirationTime: '1yr',
|
|
definePayload: ({ user, session }) => {
|
|
let userRoles: string[] = []
|
|
|
|
if (session.activeOrganizationId) {
|
|
try {
|
|
const roleQuery = db.prepare(`
|
|
SELECT role
|
|
FROM member
|
|
WHERE userId = ? AND organizationId = ?
|
|
`)
|
|
const memberRole = roleQuery.get(user.id, session.activeOrganizationId) as { role: string } | undefined
|
|
|
|
if (memberRole?.role) {
|
|
userRoles = [memberRole.role]
|
|
}
|
|
} catch (error) {
|
|
console.error('Error querying user role:', error)
|
|
}
|
|
}
|
|
|
|
return {
|
|
id: user.id,
|
|
name: user.name,
|
|
roles: userRoles,
|
|
organizationId: session.activeOrganizationId
|
|
}
|
|
}
|
|
},
|
|
jwks: {
|
|
keyPairConfig: {
|
|
// Supported by NimbusJwtDecoder
|
|
alg: 'ES512'
|
|
}
|
|
}
|
|
}),
|
|
organization({
|
|
// Pass the access control instance and roles
|
|
ac: accessControl,
|
|
roles: {
|
|
[ROLES.EMPLOYER]: employerRole,
|
|
[ROLES.WORKS_COUNCIL_MEMBER]: worksCouncilMemberRole,
|
|
[ROLES.EMPLOYEE]: employeeRole,
|
|
[ROLES.ADMIN]: adminRole,
|
|
[ROLES.OWNER]: ownerRole
|
|
},
|
|
creatorRole: ROLES.ADMIN, // OWNER fixen here!
|
|
|
|
async sendInvitationEmail(data) {
|
|
console.log('Sending invitation email', data)
|
|
const inviteLink = `http://192.168.178.114:3001/accept-invitation/${data.id}`
|
|
|
|
const roleDisplayNames = {
|
|
[ROLES.EMPLOYER]: 'Arbeitgeber',
|
|
[ROLES.EMPLOYEE]: 'Arbeitnehmer',
|
|
[ROLES.WORKS_COUNCIL_MEMBER]: 'Betriebsrat',
|
|
[ROLES.ADMIN]: 'Administrator',
|
|
[ROLES.OWNER]: 'Eigentümer'
|
|
}
|
|
|
|
const roleDisplayName = roleDisplayNames[data.role as LegalRole] || data.role
|
|
|
|
try {
|
|
const result = await resend.emails.send({
|
|
from: 'Acme <onboarding@resend.dev>',
|
|
to: data.email,
|
|
subject: `Einladung als ${roleDisplayName} - ${data.organization.name}`,
|
|
html: `
|
|
<h2>Einladung zur Organisation ${data.organization.name}</h2>
|
|
<p>Sie wurden als <strong>${roleDisplayName}</strong> eingeladen.</p>
|
|
<p><a href="${inviteLink}" style="background: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 5px;">Einladung annehmen</a></p>
|
|
<p>Diese Einladung läuft ab am: ${new Date(data.invitation.expiresAt).toLocaleDateString('de-DE')}</p>
|
|
`
|
|
})
|
|
|
|
if (result.error) {
|
|
throw new Error(`Email sending failed: ${result.error.message || result.error.name || 'Unknown error'}`)
|
|
}
|
|
|
|
console.log('Email invite link:', inviteLink)
|
|
console.log('Invitation email sent successfully to:', data.email, 'with ID:', result.data?.id)
|
|
} catch (error) {
|
|
console.error('Failed to send invitation email:', error)
|
|
|
|
// Log specific error details for debugging
|
|
const errorObj = error as { response?: { status: number; data: unknown }; message?: string }
|
|
if (errorObj.response) {
|
|
console.error('HTTP Status:', errorObj.response.status)
|
|
console.error('Response data:', errorObj.response.data)
|
|
}
|
|
|
|
// Re-throw the error so BetterAuth knows the email failed
|
|
const message = errorObj.message || String(error)
|
|
throw new Error(`Email sending failed: ${message}`)
|
|
}
|
|
}
|
|
})
|
|
]
|
|
})
|
|
|
|
export { ROLES }
|
|
export type { LegalRole }
|