Add audit system, invite links, and usage analytics (#4749)

# Description of Changes

New Features
Audit System: Complete audit logging with dashboard, event tracking, and
export capabilities

Invite Links: Secure invite system with email notifications and
expiration

Usage Analytics: Endpoint usage statistics and visualization

License Management: User counting with grandfathering and license
enforcement
## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: James Brunton <[email protected]>
This commit is contained in:
Anthony Stirling
2025-11-06 17:29:34 +00:00
committed by GitHub
co-authored by James Brunton
parent f5c67a3239
commit ac3e10eb99
64 changed files with 5269 additions and 461 deletions
+115
View File
@@ -0,0 +1,115 @@
import apiClient from '@app/services/apiClient';
export interface AuditSystemStatus {
enabled: boolean;
level: string;
retentionDays: number;
totalEvents: number;
}
export interface AuditEvent {
id: string;
timestamp: string;
eventType: string;
username: string;
ipAddress: string;
details: Record<string, any>;
}
export interface AuditEventsResponse {
events: AuditEvent[];
totalEvents: number;
page: number;
pageSize: number;
totalPages: number;
}
export interface ChartData {
labels: string[];
values: number[];
}
export interface AuditChartsData {
eventsByType: ChartData;
eventsByUser: ChartData;
eventsOverTime: ChartData;
}
export interface AuditFilters {
eventType?: string;
username?: string;
startDate?: string;
endDate?: string;
page?: number;
pageSize?: number;
}
const auditService = {
/**
* Get audit system status
*/
async getSystemStatus(): Promise<AuditSystemStatus> {
const response = await apiClient.get<any>('/api/v1/proprietary/ui-data/audit-dashboard');
const data = response.data;
// Map V1 response to expected format
return {
enabled: data.auditEnabled,
level: data.auditLevel,
retentionDays: data.retentionDays,
totalEvents: 0, // Will be fetched separately
};
},
/**
* Get audit events with pagination and filters
*/
async getEvents(filters: AuditFilters = {}): Promise<AuditEventsResponse> {
const response = await apiClient.get<AuditEventsResponse>('/api/v1/proprietary/ui-data/audit-events', {
params: filters,
});
return response.data;
},
/**
* Get chart data for dashboard
*/
async getChartsData(timePeriod: 'day' | 'week' | 'month' = 'week'): Promise<AuditChartsData> {
const response = await apiClient.get<AuditChartsData>('/api/v1/proprietary/ui-data/audit-charts', {
params: { period: timePeriod },
});
return response.data;
},
/**
* Export audit data
*/
async exportData(
format: 'csv' | 'json',
filters: AuditFilters = {}
): Promise<Blob> {
const response = await apiClient.get('/api/v1/proprietary/ui-data/audit-export', {
params: { format, ...filters },
responseType: 'blob',
});
return response.data;
},
/**
* Get available event types for filtering
*/
async getEventTypes(): Promise<string[]> {
const response = await apiClient.get<string[]>('/api/v1/proprietary/ui-data/audit-event-types');
return response.data;
},
/**
* Get list of users for filtering
*/
async getUsers(): Promise<string[]> {
const response = await apiClient.get<string[]>('/api/v1/proprietary/ui-data/audit-users');
return response.data;
},
};
export default auditService;