Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions web-app/django/VIM/apps/instruments/utils/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ def validate_hbs_classification(hbs_class: str) -> bool:
Validate Hornbostel-Sachs classification format.

Valid formats:
- Two digits minimum (e.g., "11", "21")
- With optional sub-classifications (e.g., "21.2", "311.121")
- First digit must be 1-5, second digit 0-9
- At least 1 character, only digits (1-9), dot, dash, and plus permitted
- First character must be 1-5
- If there is a second character, it must be 1-5

Args:
hbs_class: Hornbostel-Sachs classification string to validate
Expand All @@ -147,16 +147,25 @@ def validate_hbs_classification(hbs_class: str) -> bool:

Example:
>>> validate_hbs_classification("11") # True
>>> validate_hbs_classification("21.2") # True
>>> validate_hbs_classification("311.121") # True
>>> validate_hbs_classification("6") # False (needs 2 digits)
>>> validate_hbs_classification("11x") # False (invalid format)
>>> validate_hbs_classification("21.2+2") # True
>>> validate_hbs_classification("6") # False (first char not 1-5)
>>> validate_hbs_classification("11x") # False (invalid char)
"""
if not hbs_class:
return False
# Pattern: one digit (1-5), followed by another digit, optionally followed by more .digits
pattern = r"^[1-5][0-9](\.[0-9]+)*$"
return bool(re.match(pattern, hbs_class)) and len(hbs_class) >= 2
# Only digits (1-9), dot, dash, plus permitted
if not re.match(r"^[1-9.\-+]+$", hbs_class):
return False
# First character must be 1-5
first_char = hbs_class[0]
if not re.match(r"[1-5]", first_char):
return False
# If there is a second character, it must be 1-5
if len(hbs_class) > 1:
second_char = hbs_class[1]
if not re.match(r"[1-5]", second_char):
return False
return True


def validate_image_file(image_file) -> Tuple[bool, str]:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { WikidataLanguage, ValidationResult, NameEntry } from '../Types';
import { DatabaseService } from './DatabaseService';
import { isValidHBSClass } from './NameValidator';

export interface CreateInstrumentData {
entries: NameEntry[];
Expand Down Expand Up @@ -41,13 +42,11 @@ export class CreateInstrumentValidator {
};
}

// Pattern: starts with 1-5, followed by another digit, optionally more .digits
const pattern = /^[1-5][0-9](\.[0-9]+)*$/;
if (!pattern.test(value.trim())) {
if (!isValidHBSClass(value.trim())) {
return {
isValid: false,
message:
'Invalid format. Enter at least 2 digits (e.g., "11", "21.2", "311.121")',
'Invalid format. Enter a valid HBS class (e.g., "11", "21.2", "311.121"). Must start with 1-5; only digits, dot, dash, and plus are permitted',
type: 'error',
};
}
Expand Down
49 changes: 49 additions & 0 deletions web-app/frontend/src/instruments/helpers/NameValidator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import { WikidataLanguage, ValidationResult } from '../Types';
import { WikidataService } from './WikidataService';

// Helper function to validate HBS class input
export function isValidHBSClass(input: string): boolean {
// Only allow digits, dot, dash, and plus
if (!/^[1-9.\-+]+$/.test(input)) return false;
// The first and second characters must be a digit between 1 and 5
if (input.length < 1) return false;
const firstChar = input.charAt(0);
if (!/[1-5]/.test(firstChar)) return false;
if (input.length > 1) {
const secondChar = input.charAt(1);
if (!/[1-5]/.test(secondChar)) return false;
}
return true;
}

export class NameValidator {
private languages: WikidataLanguage[];

Expand Down Expand Up @@ -91,6 +106,40 @@ export class NameValidator {
};
}

/**
* Validates Hornbostel-Sachs class input (for Add Class form)
*/
validateHBSClassInput(hbsClassInput: string): ValidationResult {
const input = hbsClassInput?.trim();
if (!input) {
return {
isValid: false,
message: 'Please input an HBS number.',
type: 'error',
};
}
if (input.length > 50) {
return {
isValid: false,
message: 'HBS number must be at most 50 characters.',
type: 'error',
};
}
if (!isValidHBSClass(input)) {
return {
isValid: false,
message:
'Only use digits (first two characters 1–5), and the symbols ".", "-", "+".',
type: 'error',
};
}
return {
isValid: true,
message: `Proposed Classification: ${input}`,
type: 'success',
};
}

/**
* Validates that we have a valid name ID for deletion
*/
Expand Down
Loading