feat: complete Phase 5 of service refactoring
- Marked tasks in `TODO.md` as completed for moving TFS and Jira services to the `integrations` directory and correcting imports across the codebase. - Updated imports in various action files, API routes, and components to reflect the new structure. - Removed obsolete `jira-advanced-filters.ts`, `jira-analytics.ts`, `jira-analytics-cache.ts`, `jira-anomaly-detection.ts`, `jira-scheduler.ts`, `jira.ts`, and `tfs.ts` files to streamline the codebase. - Added new tasks in `TODO.md` for future cleaning and organization of service imports.
This commit is contained in:
203
src/services/integrations/jira/scheduler.ts
Normal file
203
src/services/integrations/jira/scheduler.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
import { userPreferencesService } from '../../core/user-preferences';
|
||||
import { JiraService } from './jira';
|
||||
import { addMinutes, getToday } from '@/lib/date-utils';
|
||||
|
||||
export interface JiraSchedulerConfig {
|
||||
enabled: boolean;
|
||||
interval: 'hourly' | 'daily' | 'weekly';
|
||||
}
|
||||
|
||||
export class JiraScheduler {
|
||||
private timer: NodeJS.Timeout | null = null;
|
||||
private isRunning = false;
|
||||
|
||||
/**
|
||||
* Démarre le planificateur de synchronisation Jira automatique
|
||||
*/
|
||||
async start(): Promise<void> {
|
||||
if (this.isRunning) {
|
||||
console.log('⚠️ Jira scheduler is already running');
|
||||
return;
|
||||
}
|
||||
|
||||
const config = await this.getConfig();
|
||||
|
||||
if (!config.enabled) {
|
||||
console.log('📋 Automatic Jira sync is disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier que Jira est configuré
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
if (!jiraConfig.enabled || !jiraConfig.baseUrl || !jiraConfig.email || !jiraConfig.apiToken) {
|
||||
console.log('⚠️ Jira not configured, scheduler cannot start');
|
||||
return;
|
||||
}
|
||||
|
||||
const intervalMs = this.getIntervalMs(config.interval);
|
||||
|
||||
// Première synchronisation immédiate (optionnelle)
|
||||
// this.performScheduledSync();
|
||||
|
||||
// Planifier les synchronisations suivantes
|
||||
this.timer = setInterval(() => {
|
||||
this.performScheduledSync();
|
||||
}, intervalMs);
|
||||
|
||||
this.isRunning = true;
|
||||
console.log(`✅ Jira scheduler started with ${config.interval} interval`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arrête le planificateur
|
||||
*/
|
||||
stop(): void {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
|
||||
this.isRunning = false;
|
||||
console.log('🛑 Jira scheduler stopped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redémarre le planificateur (utile lors des changements de config)
|
||||
*/
|
||||
async restart(): Promise<void> {
|
||||
this.stop();
|
||||
await this.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le planificateur fonctionne
|
||||
*/
|
||||
isActive(): boolean {
|
||||
return this.isRunning && this.timer !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectue une synchronisation planifiée
|
||||
*/
|
||||
private async performScheduledSync(): Promise<void> {
|
||||
try {
|
||||
console.log('🔄 Starting scheduled Jira sync...');
|
||||
|
||||
// Récupérer la config Jira
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
|
||||
if (!jiraConfig.enabled || !jiraConfig.baseUrl || !jiraConfig.email || !jiraConfig.apiToken) {
|
||||
console.log('⚠️ Jira config incomplete, skipping scheduled sync');
|
||||
return;
|
||||
}
|
||||
|
||||
// Créer le service Jira
|
||||
const jiraService = new JiraService({
|
||||
enabled: jiraConfig.enabled,
|
||||
baseUrl: jiraConfig.baseUrl,
|
||||
email: jiraConfig.email,
|
||||
apiToken: jiraConfig.apiToken,
|
||||
projectKey: jiraConfig.projectKey,
|
||||
ignoredProjects: jiraConfig.ignoredProjects || []
|
||||
});
|
||||
|
||||
// Tester la connexion d'abord
|
||||
const connectionOk = await jiraService.testConnection();
|
||||
if (!connectionOk) {
|
||||
console.error('❌ Scheduled Jira sync failed: connection error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Effectuer la synchronisation
|
||||
const result = await jiraService.syncTasks();
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ Scheduled Jira sync completed: ${result.stats.created} created, ${result.stats.updated} updated, ${result.stats.skipped} skipped`);
|
||||
} else {
|
||||
console.error(`❌ Scheduled Jira sync failed: ${result.errors.join(', ')}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Scheduled Jira sync error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit l'intervalle en millisecondes
|
||||
*/
|
||||
private getIntervalMs(interval: JiraSchedulerConfig['interval']): number {
|
||||
const intervals = {
|
||||
hourly: 60 * 60 * 1000, // 1 heure
|
||||
daily: 24 * 60 * 60 * 1000, // 24 heures
|
||||
weekly: 7 * 24 * 60 * 60 * 1000, // 7 jours
|
||||
};
|
||||
|
||||
return intervals[interval];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient le prochain moment de synchronisation
|
||||
*/
|
||||
async getNextSyncTime(): Promise<Date | null> {
|
||||
if (!this.isRunning || !this.timer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const config = await this.getConfig();
|
||||
const intervalMs = this.getIntervalMs(config.interval);
|
||||
|
||||
return addMinutes(getToday(), Math.floor(intervalMs / (1000 * 60)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la configuration du scheduler depuis les user preferences
|
||||
*/
|
||||
private async getConfig(): Promise<JiraSchedulerConfig> {
|
||||
try {
|
||||
const [jiraConfig, schedulerConfig] = await Promise.all([
|
||||
userPreferencesService.getJiraConfig(),
|
||||
userPreferencesService.getJiraSchedulerConfig()
|
||||
]);
|
||||
|
||||
return {
|
||||
enabled: schedulerConfig.jiraAutoSync &&
|
||||
jiraConfig.enabled &&
|
||||
!!jiraConfig.baseUrl &&
|
||||
!!jiraConfig.email &&
|
||||
!!jiraConfig.apiToken,
|
||||
interval: schedulerConfig.jiraSyncInterval
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error getting Jira scheduler config:', error);
|
||||
return {
|
||||
enabled: false,
|
||||
interval: 'daily'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient les stats du planificateur
|
||||
*/
|
||||
async getStatus() {
|
||||
const config = await this.getConfig();
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
|
||||
return {
|
||||
isRunning: this.isRunning,
|
||||
isEnabled: config.enabled,
|
||||
interval: config.interval,
|
||||
nextSync: await this.getNextSyncTime(),
|
||||
jiraConfigured: !!(jiraConfig.baseUrl && jiraConfig.email && jiraConfig.apiToken),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton
|
||||
export const jiraScheduler = new JiraScheduler();
|
||||
|
||||
// Auto-start du scheduler
|
||||
// Démarrer avec un délai pour laisser l'app s'initialiser
|
||||
setTimeout(() => {
|
||||
console.log('🚀 Auto-starting Jira scheduler...');
|
||||
jiraScheduler.start();
|
||||
}, 6000); // 6 secondes, après le backup scheduler
|
||||
Reference in New Issue
Block a user