feat(Task): implement user ownership for tasks and enhance related services

- Added ownerId field to Task model to associate tasks with users.
- Updated TaskService methods to enforce user ownership in task operations.
- Enhanced API routes to include user authentication and ownership checks.
- Modified DailyService and analytics services to filter tasks by user.
- Integrated user session handling in various components for personalized task management.
This commit is contained in:
Julien Froidefond
2025-10-10 11:36:10 +02:00
parent 6bfcd1f100
commit 8cb0dcf3af
32 changed files with 617 additions and 1227 deletions

View File

@@ -44,6 +44,7 @@ export class AnalyticsService {
* Calcule les métriques de productivité pour une période donnée
*/
static async getProductivityMetrics(
userId: string,
timeRange?: TimeRange,
sources?: string[]
): Promise<ProductivityMetrics> {
@@ -56,6 +57,9 @@ export class AnalyticsService {
// Récupérer toutes les tâches depuis la base de données avec leurs tags
const dbTasks = await prisma.task.findMany({
where: {
ownerId: userId,
},
include: {
taskTags: {
include: {
@@ -83,6 +87,7 @@ export class AnalyticsService {
jiraKey: task.jiraKey || undefined,
jiraType: task.jiraType || undefined,
assignee: task.assignee || undefined,
ownerId: task.ownerId,
}));
// Filtrer par sources si spécifié

View File

@@ -34,6 +34,7 @@ export class DeadlineAnalyticsService {
* Analyse les tâches selon leurs échéances
*/
static async getDeadlineMetrics(
userId: string,
sources?: string[]
): Promise<DeadlineMetrics> {
try {
@@ -42,6 +43,7 @@ export class DeadlineAnalyticsService {
// Récupérer toutes les tâches non terminées avec échéance
const dbTasks = await prisma.task.findMany({
where: {
ownerId: userId,
dueDate: {
not: null,
},
@@ -137,9 +139,10 @@ export class DeadlineAnalyticsService {
* Retourne les tâches les plus critiques (en retard + échéance dans 48h)
*/
static async getCriticalDeadlines(
userId: string,
sources?: string[]
): Promise<DeadlineTask[]> {
const metrics = await this.getDeadlineMetrics(sources);
const metrics = await this.getDeadlineMetrics(userId, sources);
return [...metrics.overdue, ...metrics.critical].slice(0, 10); // Limite à 10 tâches les plus critiques
}

View File

@@ -87,6 +87,7 @@ export class ManagerSummaryService {
* Génère un résumé orienté manager pour les 7 derniers jours
*/
static async getManagerSummary(
userId: string,
date: Date = getToday()
): Promise<ManagerSummary> {
// Fenêtre glissante de 7 jours au lieu de semaine calendaire
@@ -96,8 +97,8 @@ export class ManagerSummaryService {
// Récupérer les données de base
const [tasks, checkboxes] = await Promise.all([
this.getCompletedTasks(weekStart, weekEnd),
this.getCompletedCheckboxes(weekStart, weekEnd),
this.getCompletedTasks(userId, weekStart, weekEnd),
this.getCompletedCheckboxes(userId, weekStart, weekEnd),
]);
// Analyser et extraire les accomplissements clés
@@ -107,7 +108,7 @@ export class ManagerSummaryService {
);
// Identifier les défis à venir
const upcomingChallenges = await this.identifyUpcomingChallenges();
const upcomingChallenges = await this.identifyUpcomingChallenges(userId);
// Calculer les métriques
const metrics = this.calculateMetrics(tasks, checkboxes);
@@ -130,9 +131,14 @@ export class ManagerSummaryService {
/**
* Récupère les tâches complétées de la semaine
*/
private static async getCompletedTasks(startDate: Date, endDate: Date) {
private static async getCompletedTasks(
userId: string,
startDate: Date,
endDate: Date
) {
const tasks = await prisma.task.findMany({
where: {
ownerId: userId,
OR: [
// Tâches avec completedAt dans la période (priorité)
{
@@ -172,14 +178,24 @@ export class ManagerSummaryService {
/**
* Récupère les checkboxes complétées de la semaine
*/
private static async getCompletedCheckboxes(startDate: Date, endDate: Date) {
private static async getCompletedCheckboxes(
userId: string,
startDate: Date,
endDate: Date
) {
const checkboxes = await prisma.dailyCheckbox.findMany({
where: {
userId: userId,
isChecked: true,
date: {
gte: startDate,
lte: endDate,
},
// S'assurer que si le todo est lié à une tâche, cette tâche appartient bien à l'utilisateur
OR: [
{ task: null }, // Todos standalone (sans tâche associée)
{ task: { ownerId: userId } }, // Todos liés à une tâche de l'utilisateur
],
},
select: {
id: true,
@@ -297,12 +313,13 @@ export class ManagerSummaryService {
/**
* Identifie les défis et enjeux à venir
*/
private static async identifyUpcomingChallenges(): Promise<
UpcomingChallenge[]
> {
private static async identifyUpcomingChallenges(
userId: string
): Promise<UpcomingChallenge[]> {
// Récupérer les tâches à venir (priorité high/medium en premier)
const upcomingTasks = await prisma.task.findMany({
where: {
ownerId: userId,
completedAt: null,
},
orderBy: [
@@ -331,18 +348,30 @@ export class ManagerSummaryService {
// Récupérer les checkboxes récurrentes non complétées (meetings + tâches prioritaires)
const upcomingCheckboxes = await prisma.dailyCheckbox.findMany({
where: {
userId: userId, // Filtrer par utilisateur
isChecked: false,
date: {
gte: getToday(),
},
OR: [
{ type: 'meeting' },
// S'assurer que si le todo est lié à une tâche, cette tâche appartient bien à l'utilisateur
AND: [
{
task: {
priority: {
in: ['high', 'medium'],
OR: [
{ task: null }, // Todos standalone (sans tâche associée)
{ task: { ownerId: userId } }, // Todos liés à une tâche de l'utilisateur
],
},
{
OR: [
{ type: 'meeting' },
{
task: {
priority: {
in: ['high', 'medium'],
},
},
},
},
],
},
],
},

View File

@@ -72,6 +72,7 @@ export class MetricsService {
* Récupère les métriques journalières des 7 derniers jours
*/
static async getWeeklyMetrics(
userId: string,
date: Date = getToday()
): Promise<WeeklyMetricsOverview> {
// Fenêtre glissante de 7 jours au lieu de semaine calendaire
@@ -84,7 +85,7 @@ export class MetricsService {
// Récupérer les données pour chaque jour
const dailyBreakdown = await Promise.all(
daysOfWeek.map((day) => this.getDailyMetrics(day))
daysOfWeek.map((day) => this.getDailyMetrics(userId, day))
);
// Calculer les métriques de résumé
@@ -114,7 +115,10 @@ export class MetricsService {
/**
* Récupère les métriques pour un jour donné
*/
private static async getDailyMetrics(date: Date): Promise<DailyMetrics> {
private static async getDailyMetrics(
userId: string,
date: Date
): Promise<DailyMetrics> {
const dayStart = startOfDay(date);
const dayEnd = endOfDay(date);
@@ -124,6 +128,7 @@ export class MetricsService {
// Tâches complétées ce jour
prisma.task.count({
where: {
ownerId: userId,
OR: [
{
completedAt: {
@@ -145,6 +150,7 @@ export class MetricsService {
// Tâches en cours (status = in_progress à ce moment)
prisma.task.count({
where: {
ownerId: userId,
status: 'in_progress',
createdAt: { lte: dayEnd },
},
@@ -153,6 +159,7 @@ export class MetricsService {
// Tâches bloquées
prisma.task.count({
where: {
ownerId: userId,
status: 'blocked',
createdAt: { lte: dayEnd },
},
@@ -161,6 +168,7 @@ export class MetricsService {
// Tâches en attente
prisma.task.count({
where: {
ownerId: userId,
status: 'pending',
createdAt: { lte: dayEnd },
},
@@ -169,6 +177,7 @@ export class MetricsService {
// Nouvelles tâches créées ce jour
prisma.task.count({
where: {
ownerId: userId,
createdAt: {
gte: dayStart,
lte: dayEnd,
@@ -179,6 +188,7 @@ export class MetricsService {
// Total des tâches existantes ce jour
prisma.task.count({
where: {
ownerId: userId,
createdAt: { lte: dayEnd },
},
}),
@@ -375,6 +385,7 @@ export class MetricsService {
* Récupère les métriques de vélocité d'équipe (pour graphiques de tendance)
*/
static async getVelocityTrends(
userId: string,
weeksBack: number = 4
): Promise<VelocityTrend[]> {
const trends = [];
@@ -388,6 +399,7 @@ export class MetricsService {
const [completed, created] = await Promise.all([
prisma.task.count({
where: {
ownerId: userId,
completedAt: {
gte: weekStart,
lte: weekEnd,
@@ -396,6 +408,7 @@ export class MetricsService {
}),
prisma.task.count({
where: {
ownerId: userId,
createdAt: {
gte: weekStart,
lte: weekEnd,

View File

@@ -47,6 +47,7 @@ export class TagAnalyticsService {
* Calcule les métriques de distribution par tags
*/
static async getTagDistributionMetrics(
userId: string,
timeRange?: TimeRange,
sources?: string[]
): Promise<TagDistributionMetrics> {
@@ -60,6 +61,7 @@ export class TagAnalyticsService {
// Récupérer toutes les tâches avec leurs tags
const dbTasks = await prisma.task.findMany({
where: {
ownerId: userId,
createdAt: {
gte: start,
lte: end,
@@ -102,6 +104,7 @@ export class TagAnalyticsService {
jiraKey: task.jiraKey || undefined,
jiraType: task.jiraType || undefined,
assignee: task.assignee || undefined,
ownerId: task.ownerId,
}));
// Filtrer par sources si spécifié