diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java index 33694f3cc4..c9f41ab38a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java @@ -374,7 +374,7 @@ public Exercise removeExerciseTeamPlayers( // region exercises @PostMapping(EXERCISE_URI) - public Exercise createExercise(@Valid @RequestBody ExerciseCreateInput input) { + public Exercise createExercise(@Valid @RequestBody ExerciseInput input) { if (input == null) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Exercise input cannot be null"); } @@ -394,7 +394,7 @@ public Exercise duplicateExercise(@PathVariable @NotBlank final String exerciseI @PreAuthorize("isExercisePlanner(#exerciseId)") @Transactional(rollbackOn = Exception.class) public Exercise updateExerciseInformation( - @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateInput input) { + @PathVariable String exerciseId, @Valid @RequestBody ExerciseInput input) { Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); exercise.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseInput.java similarity index 73% rename from openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java rename to openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseInput.java index 30a80c7161..770a648610 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseInput.java @@ -1,12 +1,12 @@ package io.openbas.rest.exercise.form; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; -import static io.openbas.config.AppConfig.NOW_FUTURE_MESSAGE; +import static io.openbas.config.AppConfig.*; import static lombok.AccessLevel.NONE; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Nullable; +import jakarta.validation.constraints.Email; import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.NotBlank; import java.time.Instant; @@ -15,9 +15,12 @@ import java.util.List; import lombok.Data; import lombok.Getter; +import lombok.Setter; +@Getter +@Setter @Data -public class ExerciseCreateInput { +public class ExerciseInput { @NotBlank(message = MANDATORY_MESSAGE) @JsonProperty("exercise_name") @@ -51,6 +54,19 @@ public class ExerciseCreateInput { @JsonProperty("exercise_tags") private List tagIds = new ArrayList<>(); + @Email(message = EMAIL_FORMAT) + @JsonProperty("exercise_mail_from") + private String from; + + @JsonProperty("exercise_mails_reply_to") + private List replyTos; + + @JsonProperty("exercise_message_header") + private String header; + + @JsonProperty("exercise_message_footer") + private String footer; + public Instant getStart() { return start != null ? start.truncatedTo(ChronoUnit.MINUTES) : null; } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java deleted file mode 100644 index 9e80752eec..0000000000 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.openbas.rest.exercise.form; - -import static io.openbas.config.AppConfig.*; - -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import java.util.ArrayList; -import java.util.List; -import lombok.Getter; -import lombok.Setter; - -@Setter -@Getter -public class ExerciseUpdateInput { - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("exercise_name") - private String name; - - @JsonProperty("exercise_subtitle") - private String subtitle; - - @JsonProperty("exercise_description") - private String description; - - @JsonProperty("exercise_category") - private String category; - - @JsonProperty("exercise_main_focus") - private String mainFocus; - - @JsonProperty("exercise_severity") - private String severity; - - @Email(message = EMAIL_FORMAT) - @JsonProperty("exercise_mail_from") - private String from; - - @JsonProperty("exercise_mails_reply_to") - private List replyTos; - - @JsonProperty("exercise_message_header") - private String header; - - @JsonProperty("exercise_message_footer") - private String footer; - - @JsonProperty("exercise_tags") - private List tagIds = new ArrayList<>(); -} diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java b/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java index f65cf2f15d..7b0736ef5c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java @@ -158,4 +158,11 @@ public Map> getPlatformBannerByLevel() { @NotNull @JsonProperty("expectation_manual_default_score_value") private int expectationDefaultScoreValue; + + // EMAIL CONFIG + @JsonProperty("default_mailer") + private String defaultMailer; + + @JsonProperty("default_reply_to") + private String defaultReplyTo; } diff --git a/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java b/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java index 51051cb457..bc614e2013 100644 --- a/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java +++ b/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java @@ -180,6 +180,8 @@ public PlatformSettings findSettings() { ofNullable(dbSettings.get(DEFAULT_LANG.key())) .map(Setting::getValue) .orElse(DEFAULT_LANG.defaultValue())); + platformSettings.setDefaultMailer(openBASConfig.getDefaultMailer()); + platformSettings.setDefaultReplyTo(openBASConfig.getDefaultReplyTo()); // Build authenticated user settings OpenBASPrincipal user = currentUser(); diff --git a/openbas-front/src/admin/components/common/injects/Injects.tsx b/openbas-front/src/admin/components/common/injects/Injects.tsx index 5f5acfca9e..a62cf02445 100644 --- a/openbas-front/src/admin/components/common/injects/Injects.tsx +++ b/openbas-front/src/admin/components/common/injects/Injects.tsx @@ -578,8 +578,7 @@ const Injects: FunctionComponent = ({ edge="start" checked={ (selectAll && !(inject.inject_id - in (deSelectedElements || {}))) - || inject.inject_id in (selectedElements || {}) + in (deSelectedElements || {}))) || inject.inject_id in (selectedElements || {}) } disableRipple /> diff --git a/openbas-front/src/admin/components/settings/data_ingestion/xls_mapper/RulesContractContent.tsx b/openbas-front/src/admin/components/settings/data_ingestion/xls_mapper/RulesContractContent.tsx index 89402490c9..637e11b402 100644 --- a/openbas-front/src/admin/components/settings/data_ingestion/xls_mapper/RulesContractContent.tsx +++ b/openbas-front/src/admin/components/settings/data_ingestion/xls_mapper/RulesContractContent.tsx @@ -140,7 +140,9 @@ const RulesContractContent: React.FC = ({ }, []); const onChangeInjectorContractId = () => { - directFetchInjectorContract(methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_injector_contract`)).then((result: { data: InjectorContractConverted }) => { + directFetchInjectorContract(methods.getValues(`import_mapper_inject_importers.${index}.inject_importer_injector_contract`)).then((result: { + data: InjectorContractConverted; + }) => { const injectorContract = result.data; setInjectorContractLabel(tPick(injectorContract.injector_contract_labels)); const tmp = injectorContract?.convertedContent?.fields @@ -244,8 +246,7 @@ const RulesContractContent: React.FC = ({ @@ -257,8 +258,7 @@ const RulesContractContent: React.FC = ({ diff --git a/openbas-front/src/admin/components/simulations/simulation/ExerciseCreation.tsx b/openbas-front/src/admin/components/simulations/simulation/ExerciseCreation.tsx index b0716a8fb6..4c031545dc 100644 --- a/openbas-front/src/admin/components/simulations/simulation/ExerciseCreation.tsx +++ b/openbas-front/src/admin/components/simulations/simulation/ExerciseCreation.tsx @@ -3,12 +3,14 @@ import { useNavigate } from 'react-router-dom'; import { addExercise } from '../../../../actions/Exercise'; import type { ExerciseStore } from '../../../../actions/exercises/Exercise'; +import type { LoggedHelper } from '../../../../actions/helper'; import ButtonCreate from '../../../../components/common/ButtonCreate'; import Drawer from '../../../../components/common/Drawer'; import { useFormatter } from '../../../../components/i18n'; -import type { ExerciseCreateInput } from '../../../../utils/api-types'; +import { useHelper } from '../../../../store'; +import type { ExerciseInput, PlatformSettings } from '../../../../utils/api-types'; import { useAppDispatch } from '../../../../utils/hooks'; -import ExerciseCreationForm from './ExerciseCreationForm'; +import ExerciseForm from './ExerciseForm'; const ExerciseCreation = () => { // Standard hooks @@ -16,12 +18,33 @@ const ExerciseCreation = () => { const { t } = useFormatter(); const navigate = useNavigate(); const dispatch = useAppDispatch(); - const onSubmit = (data: ExerciseCreateInput) => { + const onSubmit = (data: ExerciseInput) => { dispatch(addExercise(data)).then((result: { result: string; entities: { scenarios: Record } }) => { setOpen(false); navigate(`/admin/exercises/${result.result}`); }); }; + + const { settings }: { settings: PlatformSettings } = useHelper((helper: LoggedHelper) => ({ + settings: helper.getPlatformSettings(), + })); + + // Form + const initialValues: ExerciseInput = { + exercise_name: '', + exercise_subtitle: '', + exercise_description: '', + exercise_category: 'attack-scenario', + exercise_main_focus: 'incident-response', + exercise_severity: 'high', + exercise_tags: [], + exercise_start_date: null, + exercise_mail_from: settings.default_mailer, + exercise_mails_reply_to: [settings.default_reply_to ? settings.default_reply_to : ''], + exercise_message_header: t('SIMULATION HEADER'), + exercise_message_footer: t('SIMULATION FOOTER'), + }; + return ( <> setOpen(true)} /> @@ -30,9 +53,11 @@ const ExerciseCreation = () => { handleClose={() => setOpen(false)} title={t('Create a new simulation')} > - setOpen(false)} + initialValues={initialValues} + edit={false} /> diff --git a/openbas-front/src/admin/components/simulations/simulation/ExerciseCreationForm.tsx b/openbas-front/src/admin/components/simulations/simulation/ExerciseCreationForm.tsx deleted file mode 100644 index 6bb00421cc..0000000000 --- a/openbas-front/src/admin/components/simulations/simulation/ExerciseCreationForm.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { zodResolver } from '@hookform/resolvers/zod'; -import { Button, MenuItem } from '@mui/material'; -import { DateTimePicker as MuiDateTimePicker } from '@mui/x-date-pickers'; -import { FunctionComponent } from 'react'; -import { Controller, SubmitHandler, useForm } from 'react-hook-form'; -import { z } from 'zod'; - -import SelectField from '../../../../components/fields/SelectField'; -import TagField from '../../../../components/fields/TagField'; -import TextField from '../../../../components/fields/TextField'; -import { useFormatter } from '../../../../components/i18n'; -import type { ExerciseCreateInput } from '../../../../utils/api-types'; -import { zodImplement } from '../../../../utils/Zod'; -import { scenarioCategories } from '../../scenarios/constants'; - -interface Props { - onSubmit: SubmitHandler; - handleClose: () => void; - initialValues?: ExerciseCreateInput; -} - -const ExerciseCreationForm: FunctionComponent = ({ - onSubmit, - handleClose, - initialValues = { - exercise_name: '', - exercise_category: 'attack-scenario', - exercise_main_focus: 'incident-response', - exercise_severity: 'high', - exercise_subtitle: '', - exercise_description: '', - exercise_start_date: null, - exercise_tags: [], - }, -}) => { - // Standard hooks - const { t } = useFormatter(); - - const { - register, - control, - handleSubmit, - formState: { errors, isDirty, isSubmitting }, - setValue, - } = useForm({ - mode: 'onTouched', - resolver: zodResolver( - zodImplement().with({ - exercise_name: z.string().min(1, { message: t('Should not be empty') }), - exercise_subtitle: z.string().optional(), - exercise_category: z.string().optional(), - exercise_main_focus: z.string().optional(), - exercise_severity: z.string().optional(), - exercise_description: z.string().optional(), - exercise_start_date: z.string().datetime().optional().nullable(), - exercise_tags: z.string().array().optional(), - }), - ), - defaultValues: initialValues, - }); - - return ( -
- - - {Array.from(scenarioCategories).map(([key, value]) => ( - - {t(value)} - - ))} - - - - {t('Endpoint Protection')} - - - {t('Web Filtering')} - - - {t('Incident Response')} - - - {t('Standard Operating Procedures')} - - - {t('Crisis Communication')} - - - {t('Strategic Reaction')} - - - - - {t('Low')} - - - {t('Medium')} - - - {t('High')} - - - {t('Critical')} - - - - ( - field.onChange(date?.toISOString())} - ampm={false} - format="yyyy-MM-dd HH:mm:ss" - /> - )} - /> - ( - - )} - /> - -
- - -
- - ); -}; - -export default ExerciseCreationForm; diff --git a/openbas-front/src/admin/components/simulations/simulation/ExerciseForm.tsx b/openbas-front/src/admin/components/simulations/simulation/ExerciseForm.tsx new file mode 100644 index 0000000000..3c94ac00bd --- /dev/null +++ b/openbas-front/src/admin/components/simulations/simulation/ExerciseForm.tsx @@ -0,0 +1,349 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import { Alert, AlertTitle, Autocomplete, Button, Chip, Grid, MenuItem, TextField as MuiTextField, Typography } from '@mui/material'; +import { DateTimePicker as MuiDateTimePicker } from '@mui/x-date-pickers'; +import { FunctionComponent, useState } from 'react'; +import { Controller, SubmitHandler, useForm } from 'react-hook-form'; +import { z } from 'zod'; + +import SelectField from '../../../../components/fields/SelectField'; +import TagField from '../../../../components/fields/TagField'; +import TextField from '../../../../components/fields/TextField'; +import { useFormatter } from '../../../../components/i18n'; +import type { ExerciseInput } from '../../../../utils/api-types'; +import { zodImplement } from '../../../../utils/Zod'; +import { scenarioCategories } from '../../scenarios/constants'; + +interface Props { + onSubmit: SubmitHandler; + handleClose: () => void; + initialValues?: ExerciseInput; + disabled?: boolean; + edit: boolean; +} + +const ExerciseForm: FunctionComponent = ({ + onSubmit, + handleClose, + disabled, + edit, + initialValues = { + exercise_name: '', + exercise_subtitle: '', + exercise_description: '', + exercise_category: 'attack-scenario', + exercise_main_focus: 'incident-response', + exercise_severity: 'high', + exercise_tags: [], + exercise_mail_from: '', + exercise_mails_reply_to: [], + exercise_message_header: '', + exercise_message_footer: '', + }, +}) => { + // Standard hooks + const { t } = useFormatter(); + const [inputValue, setInputValue] = useState(''); + + const { + register, + control, + handleSubmit, + formState: { errors, isDirty, isSubmitting }, + setValue, + } = useForm({ + mode: 'onTouched', + resolver: zodResolver( + zodImplement().with({ + exercise_name: z.string().min(1, { message: t('Should not be empty') }), + exercise_subtitle: z.string().optional(), + exercise_category: z.string().optional(), + exercise_main_focus: z.string().optional(), + exercise_severity: z.string().optional(), + exercise_description: z.string().optional(), + exercise_start_date: z.string().datetime().optional().nullable(), + exercise_tags: z.string().array().optional(), + exercise_mail_from: z.string().email(t('Should be a valid email address')).optional(), + exercise_mails_reply_to: z.array(z.string().email(t('Should be a valid email address'))).optional(), + exercise_message_header: z.string().optional(), + exercise_message_footer: z.string().optional(), + }), + ), + defaultValues: initialValues, + }); + + return ( +
+ + {t('General')} + + + + + + + {Array.from(scenarioCategories).map(([key, value]) => ( + + {t(value)} + + ))} + + + + + + {t('Endpoint Protection')} + + + {t('Web Filtering')} + + + {t('Incident Response')} + + + {t('Standard Operating Procedures')} + + + {t('Crisis Communication')} + + + {t('Strategic Reaction')} + + + + + + + + {t('Low')} + + + {t('Medium')} + + + {t('High')} + + + {t('Critical')} + + + + ( + field.onChange(date?.toISOString())} + ampm={false} + format="yyyy-MM-dd HH:mm:ss" + /> + )} + /> + + ( + + )} + /> + + + {t('Emails and SMS')} + + + + + { + return ( + { + if (undefined !== field.value && inputValue !== '' && !field.value.includes(inputValue)) { + field.onChange([...(field.value || []), inputValue.trim()]); + } + }} + onBlur={field.onBlur} + inputValue={inputValue} + onInputChange={(_event, newInputValue) => { + setInputValue(newInputValue); + }} + disableClearable={true} + renderTags={(tags: string[], getTagProps) => tags.map((email: string, index: number) => { + return ( + { + const newValue = [...(field.value || [])]; + newValue.splice(index, 1); + field.onChange(newValue); + }} + /> + ); + })} + renderInput={params => ( + value != null)?.message ?? '' : ''} + /> + )} + /> + ); + }} + /> + + + {t('If you remove the default email address, the email reception for this simulation / scenario will be disabled.')} + + + + + +
+ + +
+ + ); +}; + +export default ExerciseForm; diff --git a/openbas-front/src/admin/components/simulations/simulation/ExercisePopover.tsx b/openbas-front/src/admin/components/simulations/simulation/ExercisePopover.tsx index 180909b1a4..9f05fb24b7 100644 --- a/openbas-front/src/admin/components/simulations/simulation/ExercisePopover.tsx +++ b/openbas-front/src/admin/components/simulations/simulation/ExercisePopover.tsx @@ -1,22 +1,18 @@ import { - Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, - Tab, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, - Tabs, } from '@mui/material'; import { FunctionComponent, useState } from 'react'; -import * as React from 'react'; import { useNavigate } from 'react-router-dom'; import { deleteExercise, duplicateExercise, updateExercise } from '../../../../actions/Exercise'; @@ -29,11 +25,10 @@ import Drawer from '../../../../components/common/Drawer'; import Transition from '../../../../components/common/Transition'; import { useFormatter } from '../../../../components/i18n'; import { useHelper } from '../../../../store'; -import type { ExerciseUpdateInput } from '../../../../utils/api-types'; +import type { ExerciseInput } from '../../../../utils/api-types'; import { usePermissions } from '../../../../utils/Exercise'; import { useAppDispatch } from '../../../../utils/hooks'; -import EmailParametersForm, { SettingUpdateInput } from '../../common/simulate/EmailParametersForm'; -import ExerciseUpdateForm from './ExerciseUpdateForm'; +import ExerciseForm from './ExerciseForm'; import ExerciseReports from './reports/ExerciseReports'; export type ExerciseActionPopover = 'Duplicate' | 'Update' | 'Delete' | 'Export' | 'Access reports'; @@ -61,7 +56,7 @@ const ExercisePopover: FunctionComponent = ({ const handleOpenEdit = () => setOpenEdit(true); const handleCloseEdit = () => setOpenEdit(false); - const onSubmitEdit = (data: ExerciseUpdateInput) => { + const onSubmit = (data: ExerciseInput) => { const input = { exercise_name: data.exercise_name, exercise_subtitle: data.exercise_subtitle, @@ -70,6 +65,7 @@ const ExercisePopover: FunctionComponent = ({ exercise_description: data.exercise_description, exercise_main_focus: data.exercise_main_focus, exercise_tags: data.exercise_tags, + exercise_start_date: data.exercise_start_date, exercise_mails_reply_to: exercise.exercise_mails_reply_to, exercise_mail_from: exercise.exercise_mail_from, exercise_message_header: exercise.exercise_message_header, @@ -77,21 +73,6 @@ const ExercisePopover: FunctionComponent = ({ }; return dispatch(updateExercise(exercise.exercise_id, input)).then(() => handleCloseEdit()); }; - const submitUpdateEmailParameters = (data: SettingUpdateInput) => { - const exerciseInformationInput: ExerciseUpdateInput = { - exercise_name: exercise.exercise_name, - exercise_subtitle: exercise.exercise_subtitle, - exercise_severity: exercise.exercise_severity, - exercise_category: exercise.exercise_category, - exercise_description: exercise.exercise_description, - exercise_main_focus: exercise.exercise_main_focus, - exercise_mail_from: data.setting_mail_from || '', - exercise_mails_reply_to: data.setting_mails_reply_to, - exercise_message_header: data.setting_message_header, - exercise_message_footer: exercise.exercise_message_footer, - }; - dispatch(updateExercise(exercise.exercise_id, exerciseInformationInput)).then(() => handleCloseEdit()); - }; // Delete const [openDelete, setOpenDelete] = useState(false); @@ -130,11 +111,6 @@ const ExercisePopover: FunctionComponent = ({ const handleOpenReports = () => setOpenReports(true); const handleCloseReports = () => setOpenReports(false); - // Tab - const [currentTab, setCurrentTab] = useState(0); - - const handleChangeTab = (_: React.SyntheticEvent, value: number) => setCurrentTab(value); - const submitExport = () => { const link = document.createElement('a'); link.href = `/api/exercises/${exercise.exercise_id}/export?isWithTeams=${exportTeams}&isWithPlayers=${exportPlayers}&isWithVariableValues=${exportVariableValues}`; @@ -147,7 +123,7 @@ const ExercisePopover: FunctionComponent = ({ const handleToggleExportVariableValues = () => setExportVariableValues(!exportVariableValues); // Form - const initialValues: ExerciseUpdateInput = { + const initialValues: ExerciseInput = { exercise_name: exercise.exercise_name, exercise_subtitle: exercise.exercise_subtitle ?? '', exercise_description: exercise.exercise_description, @@ -155,12 +131,10 @@ const ExercisePopover: FunctionComponent = ({ exercise_main_focus: exercise.exercise_main_focus ?? 'incident-response', exercise_severity: exercise.exercise_severity ?? 'high', exercise_tags: exercise.exercise_tags ?? [], - }; - const initialValuesEmailParameters = { - setting_mail_from: exercise.exercise_mail_from, - setting_mails_reply_to: exercise.exercise_mails_reply_to, - setting_message_header: exercise.exercise_message_header, - setting_message_footer: exercise.exercise_message_footer, + exercise_mail_from: exercise.exercise_mail_from ?? '', + exercise_mails_reply_to: exercise.exercise_mails_reply_to ?? '', + exercise_message_header: exercise.exercise_message_header ?? '', + exercise_message_footer: exercise.exercise_message_footer ?? '', }; const permissions = usePermissions(exercise.exercise_id); @@ -183,30 +157,16 @@ const ExercisePopover: FunctionComponent = ({ - <> - - - - - - - {currentTab === 0 && ( - - )} - {currentTab === 1 && ( - - )} - + + ; - handleClose: () => void; - initialValues?: ExerciseUpdateInput; -} - -const ExerciseUpdateForm: FunctionComponent = ({ - onSubmit, - handleClose, - initialValues = { - exercise_name: '', - exercise_subtitle: '', - exercise_description: '', - exercise_category: 'attack-scenario', - exercise_main_focus: 'incident-response', - exercise_severity: 'high', - exercise_tags: [], - }, -}) => { - // Standard hooks - const { t } = useFormatter(); - const { - register, - control, - handleSubmit, - formState: { errors, isDirty, isSubmitting }, - setValue, - } = useForm({ - mode: 'onTouched', - resolver: zodResolver( - zodImplement>().with({ - exercise_name: z.string().min(1, { message: t('Should not be empty') }), - exercise_subtitle: z.string().optional(), - exercise_category: z.string().optional(), - exercise_main_focus: z.string().optional(), - exercise_severity: z.string().optional(), - exercise_description: z.string().optional(), - exercise_tags: z.string().array().optional(), - }), - ), - defaultValues: initialValues, - }); - - return ( -
- - - {Array.from(scenarioCategories).map(([key, value]) => ( - - {t(value)} - - ))} - - - - {t('Endpoint Protection')} - - - {t('Web Filtering')} - - - {t('Incident Response')} - - - {t('Standard Operating Procedures')} - - - {t('Crisis Communication')} - - - {t('Strategic Reaction')} - - - - - {t('Low')} - - - {t('Medium')} - - - {t('High')} - - - {t('Critical')} - - - - - ( - - )} - /> -
- - -
- - ); -}; - -export default ExerciseUpdateForm; diff --git a/openbas-front/src/utils/Localization.js b/openbas-front/src/utils/Localization.js index b3fbdb5a7e..29da7428ae 100644 --- a/openbas-front/src/utils/Localization.js +++ b/openbas-front/src/utils/Localization.js @@ -270,7 +270,7 @@ const i18n = { 'Create a new inject': 'Créer un nouveau stimuli', 'Remove from the team': 'Retirer de l\'équipe', 'Update the team': 'Modifier l\'équipe', - 'Update the simulation': 'Modifier la simulation', + 'Update simulation': 'Modifier la simulation', 'Update the scenario': 'Modifier le scenario', 'Update the inject': 'Modifier le stimuli', 'Update simulation start date and time': 'Mettre à jour la date et l\'heure de début de la simulation', @@ -768,6 +768,7 @@ const i18n = { 'Percent of reached score': 'Pourcentage du score atteint', 'Pause': 'Pause', 'Resume': 'Reprendre', + 'Emails and SMS': 'Emails et SMS', 'injects': 'injects', 'Paused': 'En pause', 'Canceled': 'Annulé', @@ -782,6 +783,7 @@ const i18n = { 'Questionnaire': 'Questionnaire', 'User': 'Utilisateur', 'Modules': 'Modules', + 'General': 'Général', 'Access reports': 'Accéder aux rapports', 'General information': 'Informations générales', 'There is no report for this simulation yet': 'Il n\'y a pas encore de rapport pour cette simulation', @@ -1149,7 +1151,6 @@ const i18n = { 'Simulations Results': 'Résultats des simulations', 'Simulate Now': 'Simuler maintenant', 'Human Response': 'Réponse humaine', - 'Mail configuration': 'Configuration du courrier', 'Not planned': 'Non prévu', 'Endpoint Protection': 'Protection des points de terminaison', 'Web Filtering': 'Filtrage web', @@ -1403,6 +1404,7 @@ const i18n = { 'Add condition': 'Ajouter une condition', 'is': 'est', 'undefined': 'non défini', + 'Mail configuration': 'Configuration email', }, zh: { 'Email address': 'email地址', @@ -1430,10 +1432,12 @@ const i18n = { 'Settings': '设置', 'Profile': '配置', 'Logout': '登出', + 'Mail configuration': '电子邮件配置', 'Firstname': '名', 'Lastname': '姓', 'Organization': '组织', 'Language': '语言', + 'Emails and SMS': '电子邮件和短信', 'Injects': '注入', 'Messages': '信息', 'Mails': '邮件', @@ -1673,7 +1677,7 @@ const i18n = { 'Create a new inject': '创建新注入', 'Remove from the team': '从团队移除', 'Update the team': '更新团队', - 'Update the simulation': '更新模拟', + 'Update simulation': '更新模拟', 'Update the scenario': '更新场景', 'Update the inject': '更新注入', 'Update simulation start date and time': '更新模拟开始日期和时间', @@ -2163,6 +2167,7 @@ const i18n = { 'Modules': '模块', 'Access reports': '访问报告', 'General information': '通用信息', + 'General': '常规', 'Do you want to delete this report ?': '您想删除此报告吗?', 'There is no report for this simulation yet': '目前还没有关于此模拟的报告', 'Player surveys': '玩家调查', @@ -2516,7 +2521,6 @@ const i18n = { 'Simulations Results': '模拟结果', 'Simulate Now': '现在模拟', 'Human Response': '人工响应', - 'Mail configuration': '邮件配置', 'Not planned': '未计划', 'Endpoint Protection': '终端防护', 'Web Filtering': 'web过滤', diff --git a/openbas-front/src/utils/api-types.d.ts b/openbas-front/src/utils/api-types.d.ts index 67577fee1f..fb918f8420 100644 --- a/openbas-front/src/utils/api-types.d.ts +++ b/openbas-front/src/utils/api-types.d.ts @@ -759,18 +759,6 @@ export interface Exercise { listened?: boolean; } -export interface ExerciseCreateInput { - exercise_category?: string; - exercise_description?: string; - exercise_main_focus?: string; - exercise_name: string; - exercise_severity?: string; - /** @format date-time */ - exercise_start_date?: string | null; - exercise_subtitle?: string; - exercise_tags?: string[]; -} - export interface ExerciseDetails { /** @format int64 */ exercise_all_users_number?: number; @@ -836,6 +824,22 @@ export interface ExerciseDetails { exercise_users_number?: number; } +export interface ExerciseInput { + exercise_category?: string; + exercise_description?: string; + exercise_mail_from?: string; + exercise_mails_reply_to?: string[]; + exercise_main_focus?: string; + exercise_message_footer?: string; + exercise_message_header?: string; + exercise_name: string; + exercise_severity?: string; + /** @format date-time */ + exercise_start_date?: string | null; + exercise_subtitle?: string; + exercise_tags?: string[]; +} + export interface ExerciseSimple { exercise_category?: string; exercise_global_score?: ExpectationResultsByType[]; @@ -862,20 +866,6 @@ export interface ExerciseTeamUser { user_id?: User; } -export interface ExerciseUpdateInput { - exercise_category?: string; - exercise_description?: string; - exercise_mail_from?: string; - exercise_mails_reply_to?: string[]; - exercise_main_focus?: string; - exercise_message_footer?: string; - exercise_message_header?: string; - exercise_name: string; - exercise_severity?: string; - exercise_subtitle?: string; - exercise_tags?: string[]; -} - export interface ExerciseUpdateLogoInput { exercise_logo_dark?: string; exercise_logo_light?: string; @@ -2481,7 +2471,7 @@ export interface PayloadUpsertInput { payload_elevation_required?: boolean; payload_external_id: string; payload_name: string; - payload_platforms?: string[]; + payload_platforms?: ("Linux" | "Windows" | "MacOS" | "Container" | "Service" | "Generic" | "Internal" | "Unknown")[]; payload_prerequisites?: PayloadPrerequisite[]; payload_source: "COMMUNITY" | "FILIGRAN" | "MANUAL"; payload_status: "UNVERIFIED" | "VERIFIED"; @@ -2494,6 +2484,8 @@ export interface PlatformSettings { platform_saml2_providers?: OAuthProvider[]; auth_local_enable?: boolean; auth_openid_enable?: boolean; + default_mailer?: string; + default_reply_to?: string; disabled_dev_features?: string[]; executor_caldera_enable?: boolean; executor_caldera_public_url?: string; diff --git a/openbas-model/src/main/java/io/openbas/database/model/Exercise.java b/openbas-model/src/main/java/io/openbas/database/model/Exercise.java index 4d942b2cb3..e2a2f050b2 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Exercise.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Exercise.java @@ -99,12 +99,12 @@ public class Exercise implements Base { @Getter @Column(name = "exercise_message_header") @JsonProperty("exercise_message_header") - private String header = "EXERCISE - EXERCISE - EXERCISE"; + private String header = "SIMULATION HEADER"; @Getter @Column(name = "exercise_message_footer") @JsonProperty("exercise_message_footer") - private String footer = "EXERCISE - EXERCISE - EXERCISE"; + private String footer = "SIMULATION Footer"; @Getter @Column(name = "exercise_mail_from")