Datenbank bereinigt / Gitea-Integration gefixt
Dieser Commit ist enthalten in:
committet von
Server Deploy
Ursprung
395598c2b0
Commit
c21be47428
643
backend/routes/coding.js
Normale Datei
643
backend/routes/coding.js
Normale Datei
@ -0,0 +1,643 @@
|
||||
/**
|
||||
* TASKMATE - Coding Routes
|
||||
* ========================
|
||||
* Verwaltung von Server-Anwendungen mit Claude/Codex Integration
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { getDb } = require('../database');
|
||||
const logger = require('../utils/logger');
|
||||
const gitService = require('../services/gitService');
|
||||
|
||||
/**
|
||||
* Prüft ob ein Pfad ein Server-Pfad (Linux) ist
|
||||
*/
|
||||
function isServerPath(localPath) {
|
||||
return localPath && localPath.startsWith('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Schreibt CLAUDE.md in ein Verzeichnis
|
||||
*/
|
||||
function writeCLAUDEmd(directoryPath, content) {
|
||||
if (!content || !directoryPath) return false;
|
||||
|
||||
try {
|
||||
const claudePath = path.join(directoryPath, 'CLAUDE.md');
|
||||
fs.writeFileSync(claudePath, content, 'utf8');
|
||||
logger.info(`CLAUDE.md geschrieben: ${claudePath}`);
|
||||
return true;
|
||||
} catch (e) {
|
||||
logger.error('CLAUDE.md schreiben fehlgeschlagen:', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest CLAUDE.md aus einem Verzeichnis
|
||||
*/
|
||||
function readCLAUDEmd(directoryPath) {
|
||||
if (!directoryPath) {
|
||||
logger.info('readCLAUDEmd: No directoryPath provided');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const claudePath = path.join(directoryPath, 'CLAUDE.md');
|
||||
logger.info(`readCLAUDEmd: Checking path ${claudePath}`);
|
||||
|
||||
if (fs.existsSync(claudePath)) {
|
||||
const content = fs.readFileSync(claudePath, 'utf8');
|
||||
logger.info(`readCLAUDEmd: Successfully read ${content.length} characters from ${claudePath}`);
|
||||
return content;
|
||||
} else {
|
||||
logger.info(`readCLAUDEmd: File does not exist: ${claudePath}`);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('CLAUDE.md lesen fehlgeschlagen:', e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/coding/directories
|
||||
* Alle Coding-Verzeichnisse abrufen
|
||||
*/
|
||||
router.get('/directories', (req, res) => {
|
||||
try {
|
||||
const db = getDb();
|
||||
const directories = db.prepare(`
|
||||
SELECT cd.*, u.display_name as creator_name
|
||||
FROM coding_directories cd
|
||||
LEFT JOIN users u ON cd.created_by = u.id
|
||||
ORDER BY cd.position ASC, cd.name ASC
|
||||
`).all();
|
||||
|
||||
res.json(directories.map(dir => {
|
||||
// CLAUDE.md aus dem Dateisystem lesen falls vorhanden
|
||||
let claudeMdFromDisk = null;
|
||||
if (isServerPath(dir.local_path)) {
|
||||
claudeMdFromDisk = readCLAUDEmd(dir.local_path);
|
||||
// Fallback: Wenn Pfad /home/claude-dev/TaskMate ist, versuche /app/taskmate-source
|
||||
if (!claudeMdFromDisk && dir.local_path === '/home/claude-dev/TaskMate') {
|
||||
logger.info('Trying fallback path for TaskMate: /app/taskmate-source');
|
||||
claudeMdFromDisk = readCLAUDEmd('/app/taskmate-source');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: dir.id,
|
||||
name: dir.name,
|
||||
localPath: dir.local_path,
|
||||
description: dir.description,
|
||||
color: dir.color,
|
||||
claudeInstructions: dir.claude_instructions,
|
||||
claudeMdFromDisk: claudeMdFromDisk,
|
||||
hasCLAUDEmd: !!claudeMdFromDisk,
|
||||
giteaRepoUrl: dir.gitea_repo_url,
|
||||
giteaRepoOwner: dir.gitea_repo_owner,
|
||||
giteaRepoName: dir.gitea_repo_name,
|
||||
defaultBranch: dir.default_branch,
|
||||
lastSync: dir.last_sync,
|
||||
position: dir.position,
|
||||
createdAt: dir.created_at,
|
||||
createdBy: dir.created_by,
|
||||
creatorName: dir.creator_name
|
||||
};
|
||||
}));
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Abrufen der Coding-Verzeichnisse:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/directories
|
||||
* Neues Coding-Verzeichnis erstellen
|
||||
*/
|
||||
router.post('/directories', (req, res) => {
|
||||
try {
|
||||
const { name, localPath, description, color, claudeInstructions, giteaRepoUrl, giteaRepoOwner, giteaRepoName, defaultBranch } = req.body;
|
||||
|
||||
if (!name || !localPath) {
|
||||
return res.status(400).json({ error: 'Name und Server-Pfad sind erforderlich' });
|
||||
}
|
||||
|
||||
const db = getDb();
|
||||
|
||||
// Prüfe ob Pfad bereits existiert
|
||||
const existing = db.prepare('SELECT id FROM coding_directories WHERE local_path = ?').get(localPath);
|
||||
if (existing) {
|
||||
return res.status(400).json({ error: 'Diese Anwendung ist bereits registriert' });
|
||||
}
|
||||
|
||||
// Höchste Position ermitteln
|
||||
const maxPos = db.prepare('SELECT COALESCE(MAX(position), -1) as max FROM coding_directories').get().max;
|
||||
|
||||
const result = db.prepare(`
|
||||
INSERT INTO coding_directories (name, local_path, description, color, claude_instructions, gitea_repo_url, gitea_repo_owner, gitea_repo_name, default_branch, position, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
name,
|
||||
localPath,
|
||||
description || null,
|
||||
color || '#4F46E5',
|
||||
null, // claudeInstructions wird nicht mehr gespeichert
|
||||
giteaRepoUrl || null,
|
||||
giteaRepoOwner || null,
|
||||
giteaRepoName || null,
|
||||
defaultBranch || 'main',
|
||||
maxPos + 1,
|
||||
req.user.id
|
||||
);
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(result.lastInsertRowid);
|
||||
|
||||
// Ordner erstellen falls nicht vorhanden
|
||||
let directoryCreated = false;
|
||||
if (isServerPath(localPath) && !fs.existsSync(localPath)) {
|
||||
try {
|
||||
fs.mkdirSync(localPath, { recursive: true });
|
||||
directoryCreated = true;
|
||||
logger.info(`Anwendungsordner erstellt: ${localPath}`);
|
||||
} catch (e) {
|
||||
logger.error('Ordner erstellen fehlgeschlagen:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// CLAUDE.md wird nicht mehr geschrieben - nur readonly
|
||||
let claudeMdWritten = false;
|
||||
|
||||
logger.info(`Coding-Anwendung erstellt: ${name} (${localPath})`);
|
||||
|
||||
// CLAUDE.md aus dem Dateisystem lesen für aktuelle Anzeige
|
||||
const claudeMdFromDisk = isServerPath(directory.local_path) ? readCLAUDEmd(directory.local_path) : null;
|
||||
|
||||
res.status(201).json({
|
||||
id: directory.id,
|
||||
name: directory.name,
|
||||
localPath: directory.local_path,
|
||||
description: directory.description,
|
||||
color: directory.color,
|
||||
claudeInstructions: directory.claude_instructions,
|
||||
claudeMdFromDisk: claudeMdFromDisk,
|
||||
hasCLAUDEmd: !!claudeMdFromDisk,
|
||||
giteaRepoUrl: directory.gitea_repo_url,
|
||||
giteaRepoOwner: directory.gitea_repo_owner,
|
||||
giteaRepoName: directory.gitea_repo_name,
|
||||
defaultBranch: directory.default_branch,
|
||||
position: directory.position,
|
||||
createdAt: directory.created_at,
|
||||
directoryCreated,
|
||||
claudeMdWritten
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Erstellen der Coding-Anwendung:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PUT /api/coding/directories/:id
|
||||
* Coding-Anwendung aktualisieren
|
||||
*/
|
||||
router.put('/directories/:id', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, localPath, description, color, claudeInstructions, giteaRepoUrl, giteaRepoOwner, giteaRepoName, defaultBranch, position } = req.body;
|
||||
|
||||
const db = getDb();
|
||||
|
||||
const existing = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!existing) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
// Prüfe ob neuer Pfad bereits von anderem Eintrag verwendet wird
|
||||
if (localPath && localPath !== existing.local_path) {
|
||||
const pathExists = db.prepare('SELECT id FROM coding_directories WHERE local_path = ? AND id != ?').get(localPath, id);
|
||||
if (pathExists) {
|
||||
return res.status(400).json({ error: 'Dieser Server-Pfad ist bereits registriert' });
|
||||
}
|
||||
}
|
||||
|
||||
db.prepare(`
|
||||
UPDATE coding_directories SET
|
||||
name = COALESCE(?, name),
|
||||
local_path = COALESCE(?, local_path),
|
||||
description = ?,
|
||||
color = COALESCE(?, color),
|
||||
claude_instructions = ?,
|
||||
gitea_repo_url = ?,
|
||||
gitea_repo_owner = ?,
|
||||
gitea_repo_name = ?,
|
||||
default_branch = COALESCE(?, default_branch),
|
||||
position = COALESCE(?, position)
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
name || null,
|
||||
localPath || null,
|
||||
description !== undefined ? description : existing.description,
|
||||
color || null,
|
||||
null, // claudeInstructions wird nicht mehr aktualisiert
|
||||
giteaRepoUrl !== undefined ? giteaRepoUrl : existing.gitea_repo_url,
|
||||
giteaRepoOwner !== undefined ? giteaRepoOwner : existing.gitea_repo_owner,
|
||||
giteaRepoName !== undefined ? giteaRepoName : existing.gitea_repo_name,
|
||||
defaultBranch || null,
|
||||
position !== undefined ? position : null,
|
||||
id
|
||||
);
|
||||
|
||||
const updated = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
const finalPath = updated.local_path;
|
||||
|
||||
// Ordner erstellen falls nicht vorhanden
|
||||
let directoryCreated = false;
|
||||
if (isServerPath(finalPath) && !fs.existsSync(finalPath)) {
|
||||
try {
|
||||
fs.mkdirSync(finalPath, { recursive: true });
|
||||
directoryCreated = true;
|
||||
logger.info(`Anwendungsordner erstellt: ${finalPath}`);
|
||||
} catch (e) {
|
||||
logger.error('Ordner erstellen fehlgeschlagen:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// CLAUDE.md wird nicht mehr geschrieben - nur readonly
|
||||
let claudeMdWritten = false;
|
||||
|
||||
logger.info(`Coding-Anwendung aktualisiert: ${updated.name}`);
|
||||
|
||||
// CLAUDE.md aus dem Dateisystem lesen für aktuelle Anzeige
|
||||
const claudeMdFromDisk = isServerPath(updated.local_path) ? readCLAUDEmd(updated.local_path) : null;
|
||||
|
||||
res.json({
|
||||
id: updated.id,
|
||||
name: updated.name,
|
||||
localPath: updated.local_path,
|
||||
description: updated.description,
|
||||
color: updated.color,
|
||||
claudeInstructions: updated.claude_instructions,
|
||||
claudeMdFromDisk: claudeMdFromDisk,
|
||||
hasCLAUDEmd: !!claudeMdFromDisk,
|
||||
giteaRepoUrl: updated.gitea_repo_url,
|
||||
giteaRepoOwner: updated.gitea_repo_owner,
|
||||
giteaRepoName: updated.gitea_repo_name,
|
||||
defaultBranch: updated.default_branch,
|
||||
position: updated.position,
|
||||
createdAt: updated.created_at,
|
||||
directoryCreated,
|
||||
claudeMdWritten
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Aktualisieren der Coding-Anwendung:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* DELETE /api/coding/directories/:id
|
||||
* Coding-Anwendung löschen
|
||||
*/
|
||||
router.delete('/directories/:id', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const db = getDb();
|
||||
|
||||
const existing = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!existing) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
db.prepare('DELETE FROM coding_directories WHERE id = ?').run(id);
|
||||
|
||||
logger.info(`Coding-Anwendung gelöscht: ${existing.name}`);
|
||||
|
||||
res.json({ message: 'Anwendung gelöscht' });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Löschen der Coding-Anwendung:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/coding/directories/:id/status
|
||||
* Git-Status eines Verzeichnisses abrufen
|
||||
*/
|
||||
router.get('/directories/:id/status', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const db = getDb();
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const localPath = directory.local_path;
|
||||
|
||||
// Prüfe ob es ein Git-Repository ist
|
||||
if (!gitService.isGitRepository(localPath)) {
|
||||
return res.json({
|
||||
isGitRepo: false,
|
||||
message: 'Kein Git-Repository'
|
||||
});
|
||||
}
|
||||
|
||||
const status = gitService.getStatus(localPath);
|
||||
|
||||
if (!status.success) {
|
||||
return res.status(500).json({ error: status.error });
|
||||
}
|
||||
|
||||
res.json({
|
||||
isGitRepo: true,
|
||||
branch: status.branch,
|
||||
hasChanges: status.hasChanges,
|
||||
changes: status.changes,
|
||||
ahead: status.ahead,
|
||||
behind: status.behind,
|
||||
isClean: status.isClean
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Abrufen des Git-Status:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/directories/:id/fetch
|
||||
* Git Fetch ausführen
|
||||
*/
|
||||
router.post('/directories/:id/fetch', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const db = getDb();
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const result = gitService.fetchRemote(directory.local_path);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
// Last sync aktualisieren
|
||||
db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);
|
||||
|
||||
logger.info(`Git fetch ausgeführt für: ${directory.name}`);
|
||||
|
||||
res.json({ success: true, message: 'Fetch erfolgreich' });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Git Fetch:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/directories/:id/pull
|
||||
* Git Pull ausführen
|
||||
*/
|
||||
router.post('/directories/:id/pull', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const db = getDb();
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const result = gitService.pullChanges(directory.local_path, { branch: directory.default_branch });
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
// Last sync aktualisieren
|
||||
db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);
|
||||
|
||||
logger.info(`Git pull ausgeführt für: ${directory.name}`);
|
||||
|
||||
res.json({ success: true, message: 'Pull erfolgreich', output: result.output });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Git Pull:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/directories/:id/push
|
||||
* Git Push ausführen
|
||||
*/
|
||||
router.post('/directories/:id/push', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { force } = req.body;
|
||||
const db = getDb();
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const result = gitService.pushWithUpstream(directory.local_path, directory.default_branch, 'origin', force);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
// Last sync aktualisieren
|
||||
db.prepare('UPDATE coding_directories SET last_sync = CURRENT_TIMESTAMP WHERE id = ?').run(id);
|
||||
|
||||
logger.info(`Git push ausgeführt für: ${directory.name}`);
|
||||
|
||||
res.json({ success: true, message: 'Push erfolgreich', output: result.output });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Git Push:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/directories/:id/commit
|
||||
* Git Commit ausführen
|
||||
*/
|
||||
router.post('/directories/:id/commit', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { message } = req.body;
|
||||
const db = getDb();
|
||||
|
||||
if (!message || message.trim() === '') {
|
||||
return res.status(400).json({ error: 'Commit-Nachricht erforderlich' });
|
||||
}
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
// Stage all changes
|
||||
const stageResult = gitService.stageAll(directory.local_path);
|
||||
if (!stageResult.success) {
|
||||
return res.status(500).json({ error: stageResult.error });
|
||||
}
|
||||
|
||||
// Commit with author info
|
||||
const author = {
|
||||
name: req.user.display_name || req.user.username,
|
||||
email: req.user.email || `${req.user.username}@taskmate.local`
|
||||
};
|
||||
|
||||
const result = gitService.commit(directory.local_path, message, author);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
logger.info(`Git commit ausgeführt für: ${directory.name} - "${message}"`);
|
||||
|
||||
res.json({ success: true, message: 'Commit erfolgreich', output: result.output });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Git Commit:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/coding/directories/:id/branches
|
||||
* Branches abrufen
|
||||
*/
|
||||
router.get('/directories/:id/branches', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const db = getDb();
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const result = gitService.getBranches(directory.local_path);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
res.json({ branches: result.branches });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Abrufen der Branches:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/directories/:id/checkout
|
||||
* Branch wechseln
|
||||
*/
|
||||
router.post('/directories/:id/checkout', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { branch } = req.body;
|
||||
const db = getDb();
|
||||
|
||||
if (!branch) {
|
||||
return res.status(400).json({ error: 'Branch erforderlich' });
|
||||
}
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const result = gitService.checkoutBranch(directory.local_path, branch);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
logger.info(`Branch gewechselt für ${directory.name}: ${branch}`);
|
||||
|
||||
res.json({ success: true, message: `Gewechselt zu Branch: ${branch}` });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Branch-Wechsel:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/coding/validate-path
|
||||
* Pfad validieren
|
||||
*/
|
||||
router.post('/validate-path', (req, res) => {
|
||||
try {
|
||||
const { path: localPath } = req.body;
|
||||
|
||||
if (!localPath) {
|
||||
return res.status(400).json({ error: 'Pfad erforderlich' });
|
||||
}
|
||||
|
||||
// Nur Server-Pfade können validiert werden
|
||||
if (isServerPath(localPath)) {
|
||||
const containerPath = gitService.windowsToContainerPath(localPath);
|
||||
const exists = fs.existsSync(containerPath);
|
||||
const isGitRepo = exists && gitService.isGitRepository(localPath);
|
||||
|
||||
res.json({
|
||||
valid: true,
|
||||
exists,
|
||||
isGitRepo,
|
||||
isServerPath: true
|
||||
});
|
||||
} else {
|
||||
// Windows-Pfad kann nicht serverseitig validiert werden
|
||||
res.json({
|
||||
valid: true,
|
||||
exists: null,
|
||||
isGitRepo: null,
|
||||
isServerPath: false,
|
||||
message: 'Windows-Pfade können nicht serverseitig validiert werden'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Fehler bei der Pfad-Validierung:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/coding/directories/:id/commits
|
||||
* Commit-Historie abrufen
|
||||
*/
|
||||
router.get('/directories/:id/commits', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const limit = parseInt(req.query.limit) || 20;
|
||||
const db = getDb();
|
||||
|
||||
const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id);
|
||||
if (!directory) {
|
||||
return res.status(404).json({ error: 'Anwendung nicht gefunden' });
|
||||
}
|
||||
|
||||
const result = gitService.getCommitHistory(directory.local_path, limit);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: result.error });
|
||||
}
|
||||
|
||||
res.json({ commits: result.commits });
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Abrufen der Commit-Historie:', error);
|
||||
res.status(500).json({ error: 'Interner Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren