api/utils: add some validations for mood, user and mood/emotion components
Pedro Lucas Porcellis porcellis@eletrotupi.com · 10 months ago
06314a5b665164bc343bc1c0a38ca4a562c53b7b Browse filesParents
f850d20Changed files
2
Additions
+198
Deletions
0
/dev/null → api/src/utils/emotions.js
1 +
// Emotion types enum
2 +
export const Emotions = {
3 +
JOY: 'joy',
4 +
TRUST: 'trust',
5 +
FEAR: 'fear',
6 +
SURPRISE: 'surprise',
7 +
SAD: 'sad',
8 +
DISGUST: 'disgust',
9 +
ANGRY: 'angry',
10 +
ANXIETY: 'anxiety'
11 +
};
12 +
13 +
// Valid emotion values for validation
14 +
export const VALID_EMOTIONS = Object.values(Emotions);
15 +
16 +
// Validate emotion type
17 +
export function isValidEmotion(emotion) {
18 +
return VALID_EMOTIONS.includes(emotion?.toLowerCase());
19 +
}
20 +
21 +
// Validate intensity value
22 +
export function isValidIntensity(intensity) {
23 +
const num = Number(intensity);
24 +
return !isNaN(num) && num >= 1 && num <= 10;
25 +
}
26 +
27 +
// Validate rating value
28 +
export function isValidRating(rating) {
29 +
const num = Number(rating);
30 +
return !isNaN(num) && num >= 1 && num <= 10;
31 +
}
32 +
33 +
// Validate level values (stress, anxiety, energy)
34 +
export function isValidLevel(level) {
35 +
const num = Number(level);
36 +
return !isNaN(num) && num >= 1 && num <= 10;
37 +
}
38 +
39 +
// Validate mood components array
40 +
export function validateMoodComponents(components) {
41 +
if (!Array.isArray(components)) {
42 +
return { valid: false, error: 'Components must be an array' };
43 +
}
44 +
45 +
const emotions = new Set();
46 +
47 +
for (const component of components) {
48 +
if (!Object.hasOwn(component, 'emotion') || !Object.hasOwn(component, 'intensity')) {
49 +
return { valid: false, error: 'Each component must have emotion and intensity' };
50 +
}
51 +
52 +
const emotionLower = component.emotion.toLowerCase();
53 +
54 +
if (!isValidEmotion(emotionLower)) {
55 +
return { valid: false, error: `Invalid emotion: ${component.emotion}` };
56 +
}
57 +
58 +
if (!isValidIntensity(component.intensity)) {
59 +
return { valid: false, error: `Invalid intensity for ${component.emotion}: must be 1-10` };
60 +
}
61 +
62 +
if (emotions.has(emotionLower)) {
63 +
return { valid: false, error: `Duplicate emotion: ${component.emotion}` };
64 +
}
65 +
66 +
emotions.add(emotionLower);
67 +
}
68 +
69 +
return { valid: true };
70 +
}
71 +
72 +
// Get emotion statistics
73 +
export function calculateEmotionStats(moodComponents) {
74 +
const stats = {
75 +
dominant: null,
76 +
average: 0,
77 +
breakdown: {}
78 +
};
79 +
80 +
if (!moodComponents || moodComponents.length === 0) {
81 +
return stats;
82 +
}
83 +
84 +
let maxIntensity = 0;
85 +
let totalIntensity = 0;
86 +
87 +
moodComponents.forEach(component => {
88 +
const intensity = Number(component.intensity);
89 +
totalIntensity += intensity;
90 +
91 +
stats.breakdown[component.emotion] = intensity;
92 +
93 +
if (intensity > maxIntensity) {
94 +
maxIntensity = intensity;
95 +
stats.dominant = component.emotion;
96 +
}
97 +
});
98 +
99 +
stats.average = totalIntensity / moodComponents.length;
100 +
101 +
return stats;
102 +
}
/dev/null → api/src/utils/validators.js
1 +
// Email validation
2 +
export function isValidEmail(email) {
3 +
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4 +
return emailRegex.test(email);
5 +
}
6 +
7 +
// Password validation (minimum 6 characters)
8 +
export function isValidPassword(password) {
9 +
return password && password.length >= 6;
10 +
}
11 +
12 +
import { parseISO, isValid, isFuture, isAfter } from 'date-fns';
13 +
14 +
// Date validation
15 +
export function isValidDate(dateString) {
16 +
if (!dateString) return false;
17 +
try {
18 +
const date = parseISO(dateString);
19 +
return isValid(date);
20 +
} catch {
21 +
return false;
22 +
}
23 +
}
24 +
25 +
// Check if date is not in the future
26 +
export function isNotFutureDate(dateString) {
27 +
if (!dateString) return false;
28 +
try {
29 +
const date = parseISO(dateString);
30 +
return isValid(date) && !isFuture(date);
31 +
} catch {
32 +
return false;
33 +
}
34 +
}
35 +
36 +
// Validate date range
37 +
export function isValidDateRange(startDate, endDate) {
38 +
if (!startDate || !endDate) return false;
39 +
try {
40 +
const start = parseISO(startDate);
41 +
const end = parseISO(endDate);
42 +
43 +
if (!isValid(start) || !isValid(end)) {
44 +
return false;
45 +
}
46 +
47 +
return !isAfter(start, end);
48 +
} catch {
49 +
return false;
50 +
}
51 +
}
52 +
53 +
// Sanitize string input
54 +
export function sanitizeString(str) {
55 +
if (typeof str !== 'string') return '';
56 +
return str.trim().slice(0, 500); // Limit to 500 chars
57 +
}
58 +
59 +
// Validate required fields
60 +
export function validateRequiredFields(data, fields) {
61 +
const missing = [];
62 +
63 +
for (const field of fields) {
64 +
if (data[field] === undefined || data[field] === null || data[field] === '') {
65 +
missing.push(field);
66 +
}
67 +
}
68 +
69 +
return {
70 +
valid: missing.length === 0,
71 +
missing
72 +
};
73 +
}
74 +
75 +
// Validate number in range
76 +
export function isInRange(value, min, max) {
77 +
const num = Number(value);
78 +
return !isNaN(num) && num >= min && num <= max;
79 +
}
80 +
81 +
// Parse and validate integer
82 +
export function parseIntOrDefault(value, defaultValue = null) {
83 +
const parsed = parseInt(value, 10);
84 +
return isNaN(parsed) ? defaultValue : parsed;
85 +
}
86 +
87 +
// Validate pagination parameters
88 +
export function validatePagination(page, limit) {
89 +
const validPage = Math.max(1, parseIntOrDefault(page, 1));
90 +
const validLimit = Math.min(100, Math.max(1, parseIntOrDefault(limit, 20)));
91 +
92 +
return {
93 +
page: validPage,
94 +
limit: validLimit,
95 +
offset: (validPage - 1) * validLimit
96 +
};
97 +
}