Enhance ESLint configuration to include support for .mjs and .cjs file types. Update ignored files patterns to ensure proper linting of project files. Refactor Vue component templates for improved readability and maintainability, including consistent formatting and structure across various components. Update error handling in save functions to prevent silent failures.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 52s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 52s
This commit is contained in:
@@ -83,11 +83,11 @@ export default defineEventHandler(async (event) => {
|
||||
// ggf. inkonsistente Inhalte ausgeliefert (Browser meldet Partial Transfer).
|
||||
// Daher: nach erfolgreichem Schreiben alte Varianten entfernen.
|
||||
for (const ext of ['.gz', '.br']) {
|
||||
try { await fs.unlink(`${targetPath}${ext}`) } catch (_e3) {}
|
||||
try { await fs.unlink(`${targetPath}${ext}`) } catch (_e3) { /* no-op */ }
|
||||
}
|
||||
} catch (e) {
|
||||
// best-effort cleanup
|
||||
try { await fs.unlink(tmpPath) } catch (_e2) {}
|
||||
try { await fs.unlink(tmpPath) } catch (_e2) { /* no-op */ }
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
let csvPath = null
|
||||
for (const p of candidates) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
|
||||
if (await exists(p)) {
|
||||
csvPath = p
|
||||
break
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { getUserFromToken } from '../../../utils/auth.js'
|
||||
import { getServerDataPath } from '../../../utils/paths.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
@@ -14,7 +15,7 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
// Upload-Verzeichnis finden (intern)
|
||||
const uploadDir = path.join(process.cwd(), '..', 'server', 'data', 'uploads')
|
||||
const uploadDir = getServerDataPath('uploads')
|
||||
console.log('Upload-Verzeichnis:', uploadDir)
|
||||
|
||||
// Alle Dateien im Upload-Verzeichnis durchsuchen
|
||||
|
||||
@@ -6,6 +6,7 @@ import path from 'path'
|
||||
import { StandardFonts } from 'pdf-lib'
|
||||
import { getDownloadCookieOptionsWithMaxAge } from '../../utils/cookies.js'
|
||||
import { sendMembershipEmail as sendMembershipEmailUtil } from '../../utils/email-service.js'
|
||||
import { getProjectPath, getServerDataPath } from '../../utils/paths.js'
|
||||
|
||||
// const require = createRequire(import.meta.url) // Nicht verwendet
|
||||
const execAsync = promisify(exec)
|
||||
@@ -306,16 +307,8 @@ Das ausgefüllte Formular ist als Anhang verfügbar.`
|
||||
return `${filename}.txt`
|
||||
}
|
||||
|
||||
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
||||
// filename is always a hardcoded constant (e.g., 'membership-applications'), never user input
|
||||
function getDataPath(filename) {
|
||||
// Immer den absoluten Pfad zum Projekt-Root verwenden
|
||||
// In der Entwicklung: process.cwd() ist bereits das Projekt-Root
|
||||
// In der Produktion: process.cwd() ist .output, daher ein Verzeichnis zurück
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
const projectRoot = isDev ? process.cwd() : path.resolve(process.cwd(), '..')
|
||||
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
||||
return path.join(projectRoot, 'server', 'data', filename)
|
||||
return getServerDataPath(filename)
|
||||
}
|
||||
|
||||
// Use central email service
|
||||
@@ -351,8 +344,9 @@ export default defineEventHandler(async (event) => {
|
||||
const timestamp = Date.now()
|
||||
const filename = `beitrittserklärung_${timestamp}`
|
||||
|
||||
// Temp-Verzeichnis erstellen
|
||||
const tempDir = path.join(process.cwd(), '.output', 'temp', 'latex')
|
||||
// Temp-Verzeichnis erstellen (bewusst außerhalb von .output,
|
||||
// da Deploy-Artefakte dort je nach Setup schreibgeschützt sein können)
|
||||
const tempDir = getServerDataPath('tmp', 'latex')
|
||||
await fs.mkdir(tempDir, { recursive: true })
|
||||
|
||||
try {
|
||||
@@ -360,8 +354,8 @@ export default defineEventHandler(async (event) => {
|
||||
// Versuch: Original-PDF-Template herunterladen und AcroForm-Felder befüllen
|
||||
async function fillPdfTemplate(data) {
|
||||
// Priorität: neues lokales Fillable-Template in server/templates, sonst ursprüngliches Template
|
||||
const fillablePath = path.join(process.cwd(), 'server', 'templates', 'mitgliedschaft-fillable.pdf')
|
||||
const localPath = (await fs.stat(fillablePath).then(() => fillablePath).catch(() => null)) || path.join(process.cwd(), 'server', 'templates', 'Aufnahmeantrag 2025.pdf')
|
||||
const fillablePath = getProjectPath('server', 'templates', 'mitgliedschaft-fillable.pdf')
|
||||
const localPath = (await fs.stat(fillablePath).then(() => fillablePath).catch(() => null)) || getProjectPath('server', 'templates', 'Aufnahmeantrag 2025.pdf')
|
||||
let arrayBuffer
|
||||
try {
|
||||
const localExists = await fs.stat(localPath).then(() => true).catch(() => false)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import nodemailer from 'nodemailer'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { getServerDataPath } from './paths.js'
|
||||
|
||||
/**
|
||||
* Gets the correct data path for config files
|
||||
@@ -15,15 +16,7 @@ import path from 'path'
|
||||
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
||||
// filename is always a hardcoded constant (e.g., 'config.json'), never user input
|
||||
function getDataPath(filename) {
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
|
||||
if (isProduction) {
|
||||
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
||||
return path.join(process.cwd(), '..', 'server', 'data', filename)
|
||||
} else {
|
||||
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
||||
return path.join(process.cwd(), 'server', 'data', filename)
|
||||
}
|
||||
return getServerDataPath(filename)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
31
server/utils/paths.js
Normal file
31
server/utils/paths.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
function uniqueCandidates(candidates) {
|
||||
return [...new Set(candidates.filter(Boolean))]
|
||||
}
|
||||
|
||||
function hasServerDataDir(root) {
|
||||
return fs.existsSync(path.join(root, 'server', 'data'))
|
||||
}
|
||||
|
||||
export function resolveProjectRoot() {
|
||||
const envRoot = process.env.APP_ROOT ? process.env.APP_ROOT.trim() : ''
|
||||
const cwd = process.cwd()
|
||||
const parent = path.resolve(cwd, '..')
|
||||
|
||||
const candidates = uniqueCandidates([envRoot, cwd, parent])
|
||||
for (const root of candidates) {
|
||||
if (hasServerDataDir(root)) return root
|
||||
}
|
||||
|
||||
return cwd
|
||||
}
|
||||
|
||||
export function getProjectPath(...segments) {
|
||||
return path.join(resolveProjectRoot(), ...segments)
|
||||
}
|
||||
|
||||
export function getServerDataPath(...segments) {
|
||||
return getProjectPath('server', 'data', ...segments)
|
||||
}
|
||||
Reference in New Issue
Block a user