apps/recallassess/recallassess-api/src/api/client/participant/participant-activity.service.ts
Service to track and update participant last activity timestamps This keeps Participant.last_login field updated based on various actions
Properties |
|
Methods |
|
| Async getInactiveParticipants | ||||||||||||
getInactiveParticipants(companyId: number, inactiveDays: number)
|
||||||||||||
|
Get participants who haven't been active for a specified number of days Useful for sending inactivity alerts
Parameters :
Returns :
Promise<number[]>
Array of inactive participant IDs |
| Private Async logActivity | ||||||||||||||||||||
logActivity(participantId: number, activityType: ParticipantActivityType, metadata: Record<string | unknown> | undefined, timestamp: Date)
|
||||||||||||||||||||
|
Future enhancement: Log activity to a separate ActivityLog table This would enable analytics, reporting, and audit trails
Parameters :
Returns :
Promise<void>
|
| Async updateLastActivity | ||||||||||||||||
updateLastActivity(participantId: number, activityType: ParticipantActivityType | string, metadata?: Record<string | unknown>)
|
||||||||||||||||
|
Update participant's last_login timestamp This is the primary method to call when a participant performs any action
Parameters :
Returns :
Promise<void>
|
| Async updateLastActivityOnLogin | ||||||||||||||||
updateLastActivityOnLogin(participantId: number, ipAddress?: string, userAgent?: string)
|
||||||||||||||||
|
Update last activity on login Special handler for login events
Parameters :
Returns :
Promise<void>
|
| Protected buildCompanyWhere | ||||||||||||
buildCompanyWhere(companyId: number, additionalWhere?: Record
|
||||||||||||
|
Inherited from
CLBaseService
|
||||||||||||
|
Defined in
CLBaseService:82
|
||||||||||||
|
Build base WHERE clause with company scope Ensures all queries are scoped to the user's company
Parameters :
Returns :
Record<string, any>
Complete where clause object |
| Protected buildSearchWhere | ||||||||||||
buildSearchWhere(searchFields: string[], searchQuery?: string)
|
||||||||||||
|
Inherited from
CLBaseService
|
||||||||||||
|
Defined in
CLBaseService:64
|
||||||||||||
|
Build a WHERE clause for search functionality Creates OR conditions for multiple fields
Parameters :
Returns :
[] | undefined
Array of search conditions or undefined if no query |
| Protected Async findByIdWithCompanyScope | ||||||||||||||||
findByIdWithCompanyScope(entityName: string, entityId: number, companyId: number)
|
||||||||||||||||
|
Inherited from
CLBaseService
|
||||||||||||||||
|
Defined in
CLBaseService:111
|
||||||||||||||||
|
Find entity by ID with company scope verification Common pattern: get entity and ensure it belongs to the company
Parameters :
Returns :
Promise<any | null>
Entity if found and belongs to company, null otherwise |
| Protected getRepo | ||||||||
getRepo(repoName: string)
|
||||||||
|
Inherited from
CLBaseService
|
||||||||
|
Defined in
CLBaseService:96
|
||||||||
|
Get a Prisma repository (table) dynamically Useful for generic operations across different entities
Parameters :
Returns :
any
The Prisma repository instance |
| Protected toDto | ||||||||||||
toDto(entity: any, dtoClass: unknown)
|
||||||||||||
|
Inherited from
CLBaseService
|
||||||||||||
|
Defined in
CLBaseService:20
|
||||||||||||
Type parameters :
|
||||||||||||
|
Transform database entity to DTO using class-transformer
Parameters :
Returns :
TDto
Transformed DTO instance |
| Protected toDtoArray | ||||||||||||
toDtoArray(entities: any[], dtoClass: unknown)
|
||||||||||||
|
Inherited from
CLBaseService
|
||||||||||||
|
Defined in
CLBaseService:30
|
||||||||||||
Type parameters :
|
||||||||||||
|
Transform array of database entities to DTOs
Parameters :
Returns :
TDto[]
Array of transformed DTO instances |
| Protected Async verifyCompanyOwnership | ||||||||||||||||
verifyCompanyOwnership(entityName: string, entityId: number, companyId: number)
|
||||||||||||||||
|
Inherited from
CLBaseService
|
||||||||||||||||
|
Defined in
CLBaseService:42
|
||||||||||||||||
|
Verify that an entity belongs to a specific company Common security check to prevent cross-company data access
Parameters :
Returns :
Promise<boolean>
True if entity belongs to company, false otherwise |
| Protected Readonly prisma |
Type : BNestPrismaService
|
Decorators :
@Inject()
|
|
Inherited from
CLBaseService
|
|
Defined in
CLBaseService:12
|
import { CLBaseService } from "@api/shared/services";
import { Injectable } from "@nestjs/common";
/**
* Enum for different types of participant activities
* Used to track when participants perform various actions in the system
*/
export enum ParticipantActivityType {
// Invitation & Onboarding
INVITATION_ACCEPTED = "invitation_accepted",
ACCOUNT_ACTIVATED = "account_activated",
PASSWORD_SET = "password_set",
// E-Learning Activities
COURSE_STARTED = "course_started",
COURSE_MODULE_STARTED = "course_module_started",
COURSE_MODULE_PAGE_VIEWED = "course_module_page_viewed",
COURSE_MODULE_COMPLETED = "course_module_completed",
COURSE_COMPLETED = "course_completed",
// Assessment Activities
PRE_BAT_STARTED = "pre_bat_started",
PRE_BAT_QUESTION_ANSWERED = "pre_bat_question_answered",
PRE_BAT_COMPLETED = "pre_bat_completed",
POST_BAT_STARTED = "post_bat_started",
POST_BAT_QUESTION_ANSWERED = "post_bat_question_answered",
POST_BAT_COMPLETED = "post_bat_completed",
// Knowledge Review Activities
KNOWLEDGE_REVIEW_STARTED = "knowledge_review_started",
KNOWLEDGE_REVIEW_ANSWERED = "knowledge_review_answered",
KNOWLEDGE_REVIEW_COMPLETED = "knowledge_review_completed",
// Report Activities
REPORT_VIEWED = "report_viewed",
REPORT_DOWNLOADED = "report_downloaded",
// Profile & Settings
PROFILE_UPDATED = "profile_updated",
SETTINGS_UPDATED = "settings_updated",
// Authentication
LOGIN = "login",
LOGOUT = "logout",
// General Activity
SESSION_ACTIVE = "session_active", // For periodic pings to show user is active
}
/**
* Service to track and update participant last activity timestamps
* This keeps Participant.last_login field updated based on various actions
*/
@Injectable()
export class CLParticipantActivityService extends CLBaseService {
/**
* Update participant's last_login timestamp
* This is the primary method to call when a participant performs any action
*
* @param participantId - Participant ID
* @param activityType - Type of activity being performed (string or enum)
* @param metadata - Optional metadata about the activity (for future logging/analytics)
*/
async updateLastActivity(
participantId: number,
activityType: ParticipantActivityType | string,
metadata?: Record<string, unknown>,
): Promise<void> {
const now = new Date();
// Update the participant's last_login field
await this.prisma.client.participant.update({
where: { id: participantId },
data: {
last_login: now,
},
});
// TODO: Future enhancement - Log activity to ActivityLog table for analytics
// await this.logActivity(participantId, activityType, metadata, now);
}
/**
* Bulk update last activity for multiple participants
* Useful for batch operations or session refresh
*
* @param participantIds - Array of participant IDs
*/
async updateLastActivityBulk(participantIds: number[]): Promise<void> {
const now = new Date();
await this.prisma.client.participant.updateMany({
where: {
id: {
in: participantIds,
},
},
data: {
last_login: now,
},
});
}
/**
* Get participants who haven't been active for a specified number of days
* Useful for sending inactivity alerts
*
* @param companyId - Company ID to filter by
* @param inactiveDays - Number of days of inactivity
* @returns Array of inactive participant IDs
*/
async getInactiveParticipants(companyId: number, inactiveDays: number): Promise<number[]> {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - inactiveDays);
const inactiveParticipants = await this.prisma.client.participant.findMany({
where: {
company_id: companyId,
is_active: true,
last_login: {
lt: cutoffDate,
},
},
select: {
id: true,
},
});
return inactiveParticipants.map((p) => p.id);
}
/**
* Update last activity on login
* Special handler for login events
*
* @param participantId - Participant ID
* @param ipAddress - Optional IP address for security tracking
* @param userAgent - Optional user agent string
*/
async updateLastActivityOnLogin(participantId: number, ipAddress?: string, userAgent?: string): Promise<void> {
await this.updateLastActivity(participantId, ParticipantActivityType.LOGIN, {
ip_address: ipAddress,
user_agent: userAgent,
});
}
/**
* Future enhancement: Log activity to a separate ActivityLog table
* This would enable analytics, reporting, and audit trails
*
* @param participantId - Participant ID
* @param activityType - Type of activity
* @param metadata - Additional activity data
* @param timestamp - Activity timestamp
*/
private async logActivity(
participantId: number,
activityType: ParticipantActivityType,
metadata: Record<string, unknown> | undefined,
timestamp: Date,
): Promise<void> {
// TODO: Implement when ActivityLog table is created
// await this.prisma.client.activityLog.create({
// data: {
// participant_id: participantId,
// activity_type: activityType,
// metadata: metadata ? JSON.stringify(metadata) : null,
// created_at: timestamp,
// },
// });
}
}