diff --git a/backend/core/migrations/0032_vulnerability_applied_controls_filteringlabel_and_more.py b/backend/core/migrations/0032_vulnerability_applied_controls_filteringlabel_and_more.py index 9bff22b32..53282c19f 100644 --- a/backend/core/migrations/0032_vulnerability_applied_controls_filteringlabel_and_more.py +++ b/backend/core/migrations/0032_vulnerability_applied_controls_filteringlabel_and_more.py @@ -4,6 +4,7 @@ import iam.models import uuid from django.db import migrations, models +import django.core.validators class Migration(migrations.Migration): @@ -47,7 +48,20 @@ class Migration(migrations.Migration): "is_published", models.BooleanField(default=False, verbose_name="published"), ), - ("label", models.CharField(max_length=100, verbose_name="Label")), + ( + "label", + models.CharField( + max_length=100, + verbose_name="Label", + validators=[ + django.core.validators.RegexValidator( + code="invalid_label", + message="invalidLabel", + regex="^[\\w-]{1,36}$", + ) + ], + ), + ), ( "folder", models.ForeignKey( diff --git a/backend/core/models.py b/backend/core/models.py index 4dbb96886..af6ba788d 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -10,7 +10,7 @@ from django.contrib.auth import get_user_model from django.core import serializers from django.core.exceptions import ValidationError -from django.core.validators import MaxValueValidator +from django.core.validators import MaxValueValidator, RegexValidator from django.db import models, transaction from django.db.models import Q from django.forms.models import model_to_dict @@ -173,7 +173,17 @@ class Meta: class FilteringLabel(FolderMixin, AbstractBaseModel, PublishInRootFolderMixin): - label = models.CharField(max_length=100, verbose_name=_("Label")) + label = models.CharField( + max_length=100, + verbose_name=_("Label"), + validators=[ + RegexValidator( + regex=r"^[\w-]{1,36}$", + message="invalidLabel", + code="invalid_label", + ) + ], + ) def __str__(self) -> str: return self.label diff --git a/backend/core/views.py b/backend/core/views.py index 845a90bef..f55daab1c 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -423,6 +423,34 @@ class VulnerabilityViewSet(BaseModelViewSet): def status(self, request): return Response(dict(Vulnerability.Status.choices)) + def _process_labels(self, labels): + """ + Creates a FilteringLabel and replaces the value with the ID of the newly created label. + """ + new_labels = [] + for label in labels: + try: + uuid.UUID(label, version=4) + new_labels.append(label) + except ValueError: + new_label = FilteringLabel(label=label) + new_label.full_clean() + new_label.save() + new_labels.append(str(new_label.id)) + return new_labels + + def update(self, request: Request, *args, **kwargs) -> Response: + request.data["filtering_labels"] = self._process_labels( + request.data["filtering_labels"] + ) + return super().update(request, *args, **kwargs) + + def create(self, request: Request, *args, **kwargs) -> Response: + request.data["filtering_labels"] = self._process_labels( + request.data["filtering_labels"] + ) + return super().create(request, *args, **kwargs) + class FilteringLabelViewSet(BaseModelViewSet): """ diff --git a/frontend/messages/ar.json b/frontend/messages/ar.json index d312f1811..93bb40c41 100644 --- a/frontend/messages/ar.json +++ b/frontend/messages/ar.json @@ -811,6 +811,12 @@ "exploitable": "قابلة للاستغلال", "mitigated": "مخفف", "fixed": "مُثَبَّت", + "labels": "العلامات", + "addLabel": "إضافة تسمية", + "labelsHelpText": "يتم استخدام العلامات لتصنيف العناصر وتصفيتها.", + "filteringLabel": "ملصق", + "filteringLabels": "العلامات", + "invalidLabel": "يجب أن تكون العلامة أبجدية رقمية وتحتوي على 36 حرفًا على الأكثر", "tags": "العلامات", "addTag": "إضافة علامة", "tagsHelpText": "تُستخدم العلامات لتصنيف العناصر وتصفيتها. يمكنك إضافة علامات في قسم \"إضافي\"" diff --git a/frontend/messages/de.json b/frontend/messages/de.json index af88d836a..904b4ad1a 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -811,6 +811,12 @@ "exploitable": "Ausnutzbar", "mitigated": "Mildernd", "fixed": "Behoben", + "labels": "Labels", + "addLabel": "Etikett hinzufügen", + "labelsHelpText": "Etiketten dienen zum Kategorisieren und Filtern der Elemente.", + "filteringLabel": "Etikett", + "filteringLabels": "Labels", + "invalidLabel": "Das Etikett muss alphanumerisch sein und darf höchstens 36 Zeichen enthalten", "tags": "Schlagwörter", "addTag": "Tag hinzufügen", "tagsHelpText": "Tags werden zum Kategorisieren und Filtern der Elemente verwendet. Sie können Tags im Abschnitt Extra hinzufügen" diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 5e43383a3..732cc63f2 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -813,7 +813,8 @@ "fixed": "Fixed", "labels": "Labels", "addLabel": "Add label", - "labelsHelpText": "Labels are used to categorize and filter the items. You can add labels in the Extra section", + "labelsHelpText": "Labels are used to categorize and filter the items.", "filteringLabel": "Label", - "filteringLabels": "Labels" + "filteringLabels": "Labels", + "invalidLabel": "Label must be alphanumeric and contain at most 36 characters" } diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 37c6b7283..f1c20b4b3 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -811,6 +811,12 @@ "exploitable": "Explotable", "mitigated": "Mitigada", "fixed": "Fija", + "labels": "Etiquetas", + "addLabel": "Agregar etiqueta", + "labelsHelpText": "Las etiquetas se utilizan para categorizar y filtrar los elementos.", + "filteringLabel": "Etiqueta", + "filteringLabels": "Etiquetas", + "invalidLabel": "La etiqueta debe ser alfanumérica y contener como máximo 36 caracteres.", "tags": "Etiquetas", "addTag": "Agregar etiqueta", "tagsHelpText": "Las etiquetas se utilizan para categorizar y filtrar los elementos. Puedes agregar etiquetas en la sección Extra" diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index 46636e935..46cc8b0e7 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -811,6 +811,12 @@ "exploitable": "Exploitable", "mitigated": "Atténuée", "fixed": "Fixée", + "labels": "Étiquettes", + "addLabel": "Ajouter une étiquette", + "labelsHelpText": "Les étiquettes sont utilisées pour catégoriser et filtrer les éléments.", + "filteringLabel": "Étiquette", + "filteringLabels": "Étiquettes", + "invalidLabel": "L'étiquette doit être alphanumérique et contenir au maximum 36 caractères", "tags": "Étiquettes", "addTag": "Ajouter une étiquette", "tagsHelpText": "Les étiquettes sont utilisées pour classer et filtrer les éléments. Vous pouvez ajouter des étiquettes dans la section Extra" diff --git a/frontend/messages/hi.json b/frontend/messages/hi.json index c873834f2..f009ef80e 100644 --- a/frontend/messages/hi.json +++ b/frontend/messages/hi.json @@ -811,6 +811,12 @@ "exploitable": "दोहन", "mitigated": "कम", "fixed": "तय", + "labels": "लेबल", + "addLabel": "लेबल जोड़ें", + "labelsHelpText": "लेबल का उपयोग वस्तुओं को वर्गीकृत और फ़िल्टर करने के लिए किया जाता है।", + "filteringLabel": "लेबल", + "filteringLabels": "लेबल", + "invalidLabel": "लेबल अल्फ़ान्यूमेरिक होना चाहिए और उसमें अधिकतम 36 अक्षर होने चाहिए", "tags": "टैग", "addTag": "टैग जोड़ें", "tagsHelpText": "टैग का उपयोग आइटम को वर्गीकृत और फ़िल्टर करने के लिए किया जाता है। आप अतिरिक्त अनुभाग में टैग जोड़ सकते हैं" diff --git a/frontend/messages/it.json b/frontend/messages/it.json index 02886b974..67626045b 100644 --- a/frontend/messages/it.json +++ b/frontend/messages/it.json @@ -811,6 +811,12 @@ "exploitable": "Sfruttabile", "mitigated": "Mitigata", "fixed": "Fissa", + "labels": "Etichette", + "addLabel": "Aggiungi etichetta", + "labelsHelpText": "Le etichette vengono utilizzate per categorizzare e filtrare gli elementi.", + "filteringLabel": "Etichetta", + "filteringLabels": "Etichette", + "invalidLabel": "L'etichetta deve essere alfanumerica e contenere al massimo 36 caratteri", "tags": "Etichette", "addTag": "Aggiungi tag", "tagsHelpText": "I tag vengono utilizzati per categorizzare e filtrare gli elementi. Puoi aggiungere tag nella sezione Extra" diff --git a/frontend/messages/nl.json b/frontend/messages/nl.json index 9d1148da4..10890c4e8 100644 --- a/frontend/messages/nl.json +++ b/frontend/messages/nl.json @@ -811,6 +811,12 @@ "exploitable": "Exploiteerbaar", "mitigated": "Verzacht", "fixed": "Vast", + "labels": "Etiketten", + "addLabel": "Label toevoegen", + "labelsHelpText": "Labels worden gebruikt om items te categoriseren en te filteren.", + "filteringLabel": "Label", + "filteringLabels": "Etiketten", + "invalidLabel": "Het label moet alfanumeriek zijn en maximaal 36 tekens bevatten", "tags": "Labels", "addTag": "Tag toevoegen", "tagsHelpText": "Tags worden gebruikt om de items te categoriseren en te filteren. U kunt tags toevoegen in de sectie Extra" diff --git a/frontend/messages/pl.json b/frontend/messages/pl.json index 2b15781df..1654c0692 100644 --- a/frontend/messages/pl.json +++ b/frontend/messages/pl.json @@ -811,6 +811,12 @@ "exploitable": "Wykorzystywany", "mitigated": "Złagodzony", "fixed": "Naprawił", + "labels": "Etykiety", + "addLabel": "Dodaj etykietę", + "labelsHelpText": "Etykiety służą do kategoryzowania i filtrowania elementów.", + "filteringLabel": "Etykieta", + "filteringLabels": "Etykiety", + "invalidLabel": "Etykieta musi być alfanumeryczna i zawierać maksymalnie 36 znaków", "tags": "Tagi", "addTag": "Dodaj tag", "tagsHelpText": "Tagi służą do kategoryzowania i filtrowania elementów. Możesz dodać tagi w sekcji Extra" diff --git a/frontend/messages/pt.json b/frontend/messages/pt.json index 55a34d529..5c544c786 100644 --- a/frontend/messages/pt.json +++ b/frontend/messages/pt.json @@ -811,6 +811,12 @@ "exploitable": "Explorável", "mitigated": "Mitigado", "fixed": "Fixo", + "labels": "Etiquetas", + "addLabel": "Adicionar rótulo", + "labelsHelpText": "Os rótulos são usados para categorizar e filtrar os itens.", + "filteringLabel": "Rótulo", + "filteringLabels": "Etiquetas", + "invalidLabel": "O rótulo deve ser alfanumérico e conter no máximo 36 caracteres", "tags": "Etiquetas", "addTag": "Adicionar etiqueta", "tagsHelpText": "As tags são usadas para categorizar e filtrar os itens. Você pode adicionar tags na seção Extra" diff --git a/frontend/messages/ro.json b/frontend/messages/ro.json index aecb12e93..7ab9793a0 100644 --- a/frontend/messages/ro.json +++ b/frontend/messages/ro.json @@ -811,6 +811,12 @@ "exploitable": "Exploatabil", "mitigated": "Atenuat", "fixed": "Fix", + "labels": "Etichete", + "addLabel": "Adăugați o etichetă", + "labelsHelpText": "Etichetele sunt folosite pentru a clasifica și filtra articolele.", + "filteringLabel": "Eticheta", + "filteringLabels": "Etichete", + "invalidLabel": "Eticheta trebuie să fie alfanumerice și să conțină cel mult 36 de caractere", "tags": "Etichete", "addTag": "Adăugați etichetă", "tagsHelpText": "Etichetele sunt folosite pentru a clasifica și filtra articolele. Puteți adăuga etichete în secțiunea Extra" diff --git a/frontend/messages/ur.json b/frontend/messages/ur.json index d0a523765..62979a338 100644 --- a/frontend/messages/ur.json +++ b/frontend/messages/ur.json @@ -811,6 +811,12 @@ "exploitable": "استحصال کے قابل", "mitigated": "تخفیف", "fixed": "فکسڈ", + "labels": "لیبلز", + "addLabel": "لیبل شامل کریں۔", + "labelsHelpText": "لیبلز کا استعمال اشیاء کی درجہ بندی اور فلٹر کرنے کے لیے کیا جاتا ہے۔", + "filteringLabel": "لیبل", + "filteringLabels": "لیبلز", + "invalidLabel": "لیبل حروف عددی ہونا چاہیے اور زیادہ سے زیادہ 36 حروف پر مشتمل ہونا چاہیے۔", "tags": "ٹیگز", "addTag": "ٹیگ شامل کریں۔", "tagsHelpText": "ٹیگز اشیاء کی درجہ بندی اور فلٹر کرنے کے لیے استعمال ہوتے ہیں۔ آپ اضافی سیکشن میں ٹیگ شامل کر سکتے ہیں۔" diff --git a/frontend/src/lib/components/Forms/AutocompleteSelect.svelte b/frontend/src/lib/components/Forms/AutocompleteSelect.svelte index d8d5a234e..7fba5c8c9 100644 --- a/frontend/src/lib/components/Forms/AutocompleteSelect.svelte +++ b/frontend/src/lib/components/Forms/AutocompleteSelect.svelte @@ -26,6 +26,7 @@ resolve: (x) => x }; export let cachedValue: any[] | undefined = undefined; + export let createFromSelection = false; const { value, errors, constraints } = formFieldProxy(form, field); @@ -81,6 +82,18 @@ dispatch('change', $value); dispatch('cache', selected); } + + function addOption(event) { + if (event.key === 'Enter') { + const newOption = { + label: event.target.value, + value: event.target.value + }; + options = event.target.value !== '' ? [...options, newOption] : options; + selected = event.target.value !== '' ? [...selected, newOption] : selected; + event.target.value = ''; + } + }
@@ -108,7 +121,27 @@ {/if}
- {#if options.length > 0} + {#if createFromSelection} + addOption(event)} + > + {#if option.suggested} + {option.label} + (suggested) + {:else if translateOptions} + {safeTranslate(option.label)} + {:else} + {option.label} + {/if} + + {:else if options.length > 0} = await response.json(); console.error(res); + if (res.label) { + res['filtering_labels'] = res.label; + } if (res.warning) { setFlash({ type: 'warning', message: res.warning }, event); return { form }; @@ -75,7 +78,7 @@ export async function handleErrorResponse({ return { form }; } Object.entries(res).forEach(([key, value]) => { - setError(form, key, value); + setError(form, key, safeTranslate(value)); }); return fail(400, { form }); } diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts index 7f0e6bb0b..aac616d61 100644 --- a/frontend/src/lib/utils/schemas.ts +++ b/frontend/src/lib/utils/schemas.ts @@ -338,7 +338,7 @@ export const vulnerabilitySchema = baseNamedObject({ status: z.string().default('--'), severity: z.number().default(-1), applied_controls: z.string().uuid().optional().array().optional(), - filtering_labels: z.string().uuid().optional().array().optional() + filtering_labels: z.string().optional().array().optional() }); const SCHEMA_MAP: Record = {