feat: enhance user preferences management with userId integration
- Added `userId` field to `UserPreferences` model in Prisma schema for user-specific preferences. - Implemented migration to populate existing preferences with the first user. - Updated user preferences service methods to handle user-specific data retrieval and updates. - Modified API routes and components to ensure user authentication and fetch preferences based on the authenticated user. - Enhanced session management in various components to load user preferences accordingly.
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
import { JiraAnalyticsService } from '@/services/integrations/jira/analytics';
|
||||
import { userPreferencesService } from '@/services/core/user-preferences';
|
||||
import { JiraAnalytics } from '@/lib/types';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
|
||||
export type JiraAnalyticsResult = {
|
||||
success: boolean;
|
||||
@@ -15,8 +17,13 @@ export type JiraAnalyticsResult = {
|
||||
*/
|
||||
export async function getJiraAnalytics(forceRefresh = false): Promise<JiraAnalyticsResult> {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
// Récupérer la config Jira depuis la base de données
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig(session.user.id);
|
||||
|
||||
if (!jiraConfig.enabled || !jiraConfig.baseUrl || !jiraConfig.email || !jiraConfig.apiToken) {
|
||||
return {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import { jiraAnomalyDetection, JiraAnomaly, AnomalyDetectionConfig } from '@/services/integrations/jira/anomaly-detection';
|
||||
import { JiraAnalyticsService, JiraAnalyticsConfig } from '@/services/integrations/jira/analytics';
|
||||
import { userPreferencesService } from '@/services/core/user-preferences';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
|
||||
export interface AnomalyDetectionResult {
|
||||
success: boolean;
|
||||
@@ -15,8 +17,13 @@ export interface AnomalyDetectionResult {
|
||||
*/
|
||||
export async function detectJiraAnomalies(forceRefresh = false): Promise<AnomalyDetectionResult> {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
// Récupérer la config Jira
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig(session.user.id);
|
||||
|
||||
if (!jiraConfig?.baseUrl || !jiraConfig?.email || !jiraConfig?.apiToken || !jiraConfig?.projectKey) {
|
||||
return {
|
||||
|
||||
@@ -4,6 +4,8 @@ import { JiraAnalyticsService, JiraAnalyticsConfig } from '@/services/integratio
|
||||
import { JiraAdvancedFiltersService } from '@/services/integrations/jira/advanced-filters';
|
||||
import { userPreferencesService } from '@/services/core/user-preferences';
|
||||
import { AvailableFilters, JiraAnalyticsFilters, JiraAnalytics } from '@/lib/types';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
|
||||
export interface FiltersResult {
|
||||
success: boolean;
|
||||
@@ -22,8 +24,13 @@ export interface FilteredAnalyticsResult {
|
||||
*/
|
||||
export async function getAvailableJiraFilters(): Promise<FiltersResult> {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
// Récupérer la config Jira
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig(session.user.id);
|
||||
|
||||
if (!jiraConfig?.baseUrl || !jiraConfig?.email || !jiraConfig?.apiToken || !jiraConfig?.projectKey) {
|
||||
return {
|
||||
@@ -63,8 +70,13 @@ export async function getAvailableJiraFilters(): Promise<FiltersResult> {
|
||||
*/
|
||||
export async function getFilteredJiraAnalytics(filters: Partial<JiraAnalyticsFilters>): Promise<FilteredAnalyticsResult> {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
// Récupérer la config Jira
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig(session.user.id);
|
||||
|
||||
if (!jiraConfig?.baseUrl || !jiraConfig?.email || !jiraConfig?.apiToken || !jiraConfig?.projectKey) {
|
||||
return {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { userPreferencesService } from '@/services/core/user-preferences';
|
||||
import { SprintDetails } from '@/components/jira/SprintDetailModal';
|
||||
import { JiraTask, AssigneeDistribution, StatusDistribution, SprintVelocity } from '@/lib/types';
|
||||
import { parseDate } from '@/lib/date-utils';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
|
||||
export interface SprintDetailsResult {
|
||||
success: boolean;
|
||||
@@ -17,8 +19,13 @@ export interface SprintDetailsResult {
|
||||
*/
|
||||
export async function getSprintDetails(sprintName: string): Promise<SprintDetailsResult> {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
// Récupérer la config Jira
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig();
|
||||
const jiraConfig = await userPreferencesService.getJiraConfig(session.user.id);
|
||||
|
||||
if (!jiraConfig?.baseUrl || !jiraConfig?.email || !jiraConfig?.apiToken || !jiraConfig?.projectKey) {
|
||||
return {
|
||||
|
||||
@@ -4,6 +4,8 @@ import { userPreferencesService } from '@/services/core/user-preferences';
|
||||
import { KanbanFilters, ViewPreferences, ColumnVisibility, TaskStatus } from '@/lib/types';
|
||||
import { Theme } from '@/lib/theme-config';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
|
||||
/**
|
||||
* Met à jour les préférences de vue
|
||||
@@ -13,7 +15,12 @@ export async function updateViewPreferences(updates: Partial<ViewPreferences>):
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
await userPreferencesService.updateViewPreferences(updates);
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
await userPreferencesService.updateViewPreferences(session.user.id, updates);
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -33,7 +40,12 @@ export async function updateKanbanFilters(updates: Partial<KanbanFilters>): Prom
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
await userPreferencesService.updateKanbanFilters(updates);
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
await userPreferencesService.updateKanbanFilters(session.user.id, updates);
|
||||
revalidatePath('/kanban');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -53,13 +65,18 @@ export async function updateColumnVisibility(updates: Partial<ColumnVisibility>)
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const preferences = await userPreferencesService.getAllPreferences(session.user.id);
|
||||
const newColumnVisibility: ColumnVisibility = {
|
||||
...preferences.columnVisibility,
|
||||
...updates
|
||||
};
|
||||
|
||||
await userPreferencesService.saveColumnVisibility(newColumnVisibility);
|
||||
await userPreferencesService.saveColumnVisibility(session.user.id, newColumnVisibility);
|
||||
revalidatePath('/kanban');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -79,10 +96,15 @@ export async function toggleObjectivesVisibility(): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const preferences = await userPreferencesService.getAllPreferences(session.user.id);
|
||||
const showObjectives = !preferences.viewPreferences.showObjectives;
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ showObjectives });
|
||||
await userPreferencesService.updateViewPreferences(session.user.id, { showObjectives });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -102,10 +124,15 @@ export async function toggleObjectivesCollapse(): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const preferences = await userPreferencesService.getAllPreferences(session.user.id);
|
||||
const collapseObjectives = !preferences.viewPreferences.collapseObjectives;
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ collapseObjectives });
|
||||
await userPreferencesService.updateViewPreferences(session.user.id, { collapseObjectives });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -125,7 +152,12 @@ export async function setTheme(theme: Theme): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
await userPreferencesService.updateViewPreferences({ theme });
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
await userPreferencesService.updateViewPreferences(session.user.id, { theme });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -145,10 +177,15 @@ export async function toggleTheme(): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const preferences = await userPreferencesService.getAllPreferences(session.user.id);
|
||||
const newTheme = preferences.viewPreferences.theme === 'dark' ? 'light' : 'dark';
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ theme: newTheme });
|
||||
await userPreferencesService.updateViewPreferences(session.user.id, { theme: newTheme });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -168,13 +205,18 @@ export async function toggleFontSize(): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const preferences = await userPreferencesService.getAllPreferences(session.user.id);
|
||||
const fontSizes: ('small' | 'medium' | 'large')[] = ['small', 'medium', 'large'];
|
||||
const currentIndex = fontSizes.indexOf(preferences.viewPreferences.fontSize);
|
||||
const nextIndex = (currentIndex + 1) % fontSizes.length;
|
||||
const newFontSize = fontSizes[nextIndex];
|
||||
|
||||
await userPreferencesService.updateViewPreferences({ fontSize: newFontSize });
|
||||
await userPreferencesService.updateViewPreferences(session.user.id, { fontSize: newFontSize });
|
||||
revalidatePath('/');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
@@ -194,7 +236,12 @@ export async function toggleColumnVisibility(status: TaskStatus): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const preferences = await userPreferencesService.getAllPreferences();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const preferences = await userPreferencesService.getAllPreferences(session.user.id);
|
||||
const hiddenStatuses = new Set(preferences.columnVisibility.hiddenStatuses);
|
||||
|
||||
if (hiddenStatuses.has(status)) {
|
||||
@@ -203,7 +250,7 @@ export async function toggleColumnVisibility(status: TaskStatus): Promise<{
|
||||
hiddenStatuses.add(status);
|
||||
}
|
||||
|
||||
await userPreferencesService.saveColumnVisibility({
|
||||
await userPreferencesService.saveColumnVisibility(session.user.id, {
|
||||
hiddenStatuses: Array.from(hiddenStatuses)
|
||||
});
|
||||
|
||||
|
||||
@@ -3,13 +3,20 @@
|
||||
import { userPreferencesService } from '@/services/core/user-preferences';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { tfsService, TfsConfig } from '@/services/integrations/tfs';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
|
||||
/**
|
||||
* Sauvegarde la configuration TFS
|
||||
*/
|
||||
export async function saveTfsConfig(config: TfsConfig) {
|
||||
try {
|
||||
await userPreferencesService.saveTfsConfig(config);
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
await userPreferencesService.saveTfsConfig(session.user.id, config);
|
||||
|
||||
// Réinitialiser le service pour prendre en compte la nouvelle config
|
||||
tfsService.reset();
|
||||
@@ -34,7 +41,12 @@ export async function saveTfsConfig(config: TfsConfig) {
|
||||
*/
|
||||
export async function getTfsConfig() {
|
||||
try {
|
||||
const config = await userPreferencesService.getTfsConfig();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
const config = await userPreferencesService.getTfsConfig(session.user.id);
|
||||
return { success: true, data: config };
|
||||
} catch (error) {
|
||||
console.error('Erreur récupération config TFS:', error);
|
||||
@@ -64,7 +76,13 @@ export async function saveTfsSchedulerConfig(
|
||||
tfsSyncInterval: 'hourly' | 'daily' | 'weekly'
|
||||
) {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non authentifié' };
|
||||
}
|
||||
|
||||
await userPreferencesService.saveTfsSchedulerConfig(
|
||||
session.user.id,
|
||||
tfsAutoSync,
|
||||
tfsSyncInterval
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user