Fix TypeScript compilation errors

- Fix conflicting Request interface declarations (auth.ts vs authorization.ts)
- Fix email field type issue in auth.ts (handle undefined)
- Fix req.params type issues (string | string[] to string) in auth.ts, roles.ts, users.ts
- Fix apiKey undefined issue in claude.ts (use tavilyApiKey)
- Fix duplicate isConfigured identifier in emailService.ts (rename to _isConfigured)
- Fix confluencePage property type issue in jiraAssetsClient.ts (add type assertion)
This commit is contained in:
2026-01-15 03:26:20 +01:00
parent 1fa424efb9
commit ff46da842f
7 changed files with 57 additions and 32 deletions

View File

@@ -5,16 +5,17 @@
*/ */
import { Request, Response, NextFunction } from 'express'; import { Request, Response, NextFunction } from 'express';
import { authService, type SessionUser } from '../services/authService.js'; import { authService, type SessionUser, type JiraUser } from '../services/authService.js';
import { roleService } from '../services/roleService.js'; import { roleService } from '../services/roleService.js';
import { logger } from '../services/logger.js'; import { logger } from '../services/logger.js';
// Extend Express Request to include user info // Extend Express Request to include user info
// Note: This matches the declaration in auth.ts
declare global { declare global {
namespace Express { namespace Express {
interface Request { interface Request {
sessionId?: string; sessionId?: string;
user?: SessionUser; user?: SessionUser | JiraUser;
accessToken?: string; accessToken?: string;
} }
} }

View File

@@ -9,6 +9,7 @@ import { getAuthDatabase } from '../services/database/migrations.js';
const router = Router(); const router = Router();
// Extend Express Request to include user info // Extend Express Request to include user info
// Note: This extends the declaration from authorization.ts
declare global { declare global {
namespace Express { namespace Express {
interface Request { interface Request {
@@ -113,12 +114,13 @@ router.get('/me', async (req: Request, res: Response) => {
let userData = session.user; let userData = session.user;
if ('id' in session.user) { if ('id' in session.user) {
// Local user - ensure proper format // Local user - ensure proper format
const email = session.user.email || session.user.emailAddress || '';
userData = { userData = {
id: session.user.id, id: session.user.id,
email: session.user.email || session.user.emailAddress, email: email,
username: session.user.username, username: session.user.username,
displayName: session.user.displayName, displayName: session.user.displayName,
emailAddress: session.user.email || session.user.emailAddress, emailAddress: email,
roles: session.user.roles || [], roles: session.user.roles || [],
permissions: session.user.permissions || [], permissions: session.user.permissions || [],
}; };
@@ -388,7 +390,7 @@ router.post('/verify-email', async (req: Request, res: Response) => {
// Get invitation token info // Get invitation token info
router.get('/invitation/:token', async (req: Request, res: Response) => { router.get('/invitation/:token', async (req: Request, res: Response) => {
const { token } = req.params; const token = Array.isArray(req.params.token) ? req.params.token[0] : req.params.token;
try { try {
const user = await userService.validateInvitationToken(token); const user = await userService.validateInvitationToken(token);

View File

@@ -37,7 +37,8 @@ router.get('/', async (req: Request, res: Response) => {
// Get role by ID // Get role by ID
router.get('/:id', async (req: Request, res: Response) => { router.get('/:id', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid role ID' }); return res.status(400).json({ error: 'Invalid role ID' });
} }
@@ -80,7 +81,8 @@ router.post('/', requireAuth, requireAdmin, async (req: Request, res: Response)
// Update role (admin only) // Update role (admin only)
router.put('/:id', requireAuth, requireAdmin, async (req: Request, res: Response) => { router.put('/:id', requireAuth, requireAdmin, async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid role ID' }); return res.status(400).json({ error: 'Invalid role ID' });
} }
@@ -99,7 +101,8 @@ router.put('/:id', requireAuth, requireAdmin, async (req: Request, res: Response
// Delete role (admin only) // Delete role (admin only)
router.delete('/:id', requireAuth, requireAdmin, async (req: Request, res: Response) => { router.delete('/:id', requireAuth, requireAdmin, async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid role ID' }); return res.status(400).json({ error: 'Invalid role ID' });
} }
@@ -120,7 +123,8 @@ router.delete('/:id', requireAuth, requireAdmin, async (req: Request, res: Respo
// Get role permissions // Get role permissions
router.get('/:id/permissions', async (req: Request, res: Response) => { router.get('/:id/permissions', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid role ID' }); return res.status(400).json({ error: 'Invalid role ID' });
} }
@@ -136,7 +140,8 @@ router.get('/:id/permissions', async (req: Request, res: Response) => {
// Assign permission to role (admin only) // Assign permission to role (admin only)
router.post('/:id/permissions', requireAuth, requireAdmin, async (req: Request, res: Response) => { router.post('/:id/permissions', requireAuth, requireAdmin, async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid role ID' }); return res.status(400).json({ error: 'Invalid role ID' });
} }
@@ -162,8 +167,10 @@ router.post('/:id/permissions', requireAuth, requireAdmin, async (req: Request,
// Remove permission from role (admin only) // Remove permission from role (admin only)
router.delete('/:id/permissions/:permissionId', requireAuth, requireAdmin, async (req: Request, res: Response) => { router.delete('/:id/permissions/:permissionId', requireAuth, requireAdmin, async (req: Request, res: Response) => {
try { try {
const roleId = parseInt(req.params.id, 10); const roleIdParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const permissionId = parseInt(req.params.permissionId, 10); const permissionIdParam = Array.isArray(req.params.permissionId) ? req.params.permissionId[0] : req.params.permissionId;
const roleId = parseInt(roleIdParam, 10);
const permissionId = parseInt(permissionIdParam, 10);
if (isNaN(roleId) || isNaN(permissionId)) { if (isNaN(roleId) || isNaN(permissionId)) {
return res.status(400).json({ error: 'Invalid role ID or permission ID' }); return res.status(400).json({ error: 'Invalid role ID or permission ID' });

View File

@@ -42,7 +42,8 @@ router.get('/', async (req: Request, res: Response) => {
// Get user by ID // Get user by ID
router.get('/:id', async (req: Request, res: Response) => { router.get('/:id', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -99,7 +100,8 @@ router.post('/', async (req: Request, res: Response) => {
// Update user // Update user
router.put('/:id', async (req: Request, res: Response) => { router.put('/:id', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -129,7 +131,8 @@ router.put('/:id', async (req: Request, res: Response) => {
// Delete user // Delete user
router.delete('/:id', async (req: Request, res: Response) => { router.delete('/:id', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -154,7 +157,8 @@ router.delete('/:id', async (req: Request, res: Response) => {
// Send invitation email // Send invitation email
router.post('/:id/invite', async (req: Request, res: Response) => { router.post('/:id/invite', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -174,7 +178,8 @@ router.post('/:id/invite', async (req: Request, res: Response) => {
// Assign role to user // Assign role to user
router.post('/:id/roles', async (req: Request, res: Response) => { router.post('/:id/roles', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -200,8 +205,10 @@ router.post('/:id/roles', async (req: Request, res: Response) => {
// Remove role from user // Remove role from user
router.delete('/:id/roles/:roleId', async (req: Request, res: Response) => { router.delete('/:id/roles/:roleId', async (req: Request, res: Response) => {
try { try {
const userId = parseInt(req.params.id, 10); const userIdParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const roleId = parseInt(req.params.roleId, 10); const roleIdParam = Array.isArray(req.params.roleId) ? req.params.roleId[0] : req.params.roleId;
const userId = parseInt(userIdParam, 10);
const roleId = parseInt(roleIdParam, 10);
if (isNaN(userId) || isNaN(roleId)) { if (isNaN(userId) || isNaN(roleId)) {
return res.status(400).json({ error: 'Invalid user ID or role ID' }); return res.status(400).json({ error: 'Invalid user ID or role ID' });
@@ -231,7 +238,8 @@ router.delete('/:id/roles/:roleId', async (req: Request, res: Response) => {
// Activate/deactivate user // Activate/deactivate user
router.put('/:id/activate', async (req: Request, res: Response) => { router.put('/:id/activate', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -257,7 +265,8 @@ router.put('/:id/activate', async (req: Request, res: Response) => {
// Manually verify email address (admin action) // Manually verify email address (admin action)
router.put('/:id/verify-email', async (req: Request, res: Response) => { router.put('/:id/verify-email', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }
@@ -282,7 +291,8 @@ router.put('/:id/verify-email', async (req: Request, res: Response) => {
// Set password for user (admin action) // Set password for user (admin action)
router.put('/:id/password', async (req: Request, res: Response) => { router.put('/:id/password', async (req: Request, res: Response) => {
try { try {
const id = parseInt(req.params.id, 10); const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) { if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid user ID' }); return res.status(400).json({ error: 'Invalid user ID' });
} }

View File

@@ -350,7 +350,7 @@ async function performWebSearch(query: string, tavilyApiKey?: string): Promise<s
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
api_key: apiKey, api_key: tavilyApiKey,
query: query, query: query,
search_depth: 'basic', search_depth: 'basic',
include_answer: true, include_answer: true,

View File

@@ -18,7 +18,7 @@ interface EmailOptions {
class EmailService { class EmailService {
private transporter: Transporter | null = null; private transporter: Transporter | null = null;
private isConfigured: boolean = false; private _isConfigured: boolean = false;
constructor() { constructor() {
this.initialize(); this.initialize();
@@ -37,7 +37,7 @@ class EmailService {
if (!smtpHost || !smtpUser || !smtpPassword) { if (!smtpHost || !smtpUser || !smtpPassword) {
logger.warn('SMTP not configured - email functionality will be disabled'); logger.warn('SMTP not configured - email functionality will be disabled');
this.isConfigured = false; this._isConfigured = false;
return; return;
} }
@@ -52,11 +52,11 @@ class EmailService {
}, },
}); });
this.isConfigured = true; this._isConfigured = true;
logger.info('Email service configured'); logger.info('Email service configured');
} catch (error) { } catch (error) {
logger.error('Failed to initialize email service:', error); logger.error('Failed to initialize email service:', error);
this.isConfigured = false; this._isConfigured = false;
} }
} }
@@ -64,7 +64,7 @@ class EmailService {
* Send an email * Send an email
*/ */
async sendEmail(options: EmailOptions): Promise<boolean> { async sendEmail(options: EmailOptions): Promise<boolean> {
if (!this.isConfigured || !this.transporter) { if (!this._isConfigured || !this.transporter) {
logger.warn('Email service not configured - email not sent:', options.to); logger.warn('Email service not configured - email not sent:', options.to);
// In development, log the email content // In development, log the email content
if (config.isDevelopment) { if (config.isDevelopment) {
@@ -282,7 +282,7 @@ class EmailService {
* Check if email service is configured * Check if email service is configured
*/ */
isConfigured(): boolean { isConfigured(): boolean {
return this.isConfigured; return this._isConfigured;
} }
} }

View File

@@ -453,14 +453,19 @@ class JiraAssetsClient {
// Generic Confluence field detection: check if any value has a confluencePage // Generic Confluence field detection: check if any value has a confluencePage
// This works for all Confluence fields regardless of their declared type (float, text, etc.) // This works for all Confluence fields regardless of their declared type (float, text, etc.)
const hasConfluencePage = values.some(v => v.confluencePage); // Type assertion needed because confluencePage is not in the type definition but exists at runtime
type AttributeValueWithConfluence = typeof values[0] & {
confluencePage?: { url?: string };
};
const valuesWithConfluence = values as AttributeValueWithConfluence[];
const hasConfluencePage = valuesWithConfluence.some(v => v.confluencePage);
if (hasConfluencePage) { if (hasConfluencePage) {
const confluencePage = values[0]?.confluencePage; const confluencePage = valuesWithConfluence[0]?.confluencePage;
if (confluencePage?.url) { if (confluencePage?.url) {
logger.info(`[Confluence Field Parse] Found Confluence URL for field "${attrDef.fieldName || 'unknown'}": ${confluencePage.url}`); logger.info(`[Confluence Field Parse] Found Confluence URL for field "${attrDef.fieldName || 'unknown'}": ${confluencePage.url}`);
// For multiple values, return array of URLs; for single, return the URL string // For multiple values, return array of URLs; for single, return the URL string
if (attrDef.isMultiple) { if (attrDef.isMultiple) {
return values return valuesWithConfluence
.filter(v => v.confluencePage?.url) .filter(v => v.confluencePage?.url)
.map(v => v.confluencePage!.url); .map(v => v.confluencePage!.url);
} }