Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring

This commit is contained in:
Sofia Papacharalampous 2024-05-13 15:24:57 +03:00
commit 953f59aeb3
17 changed files with 199 additions and 67 deletions

View File

@ -53,7 +53,7 @@ public class UserAdditionalInfoBuilder extends BaseBuilder<UserAdditionalInfo, A
if (fields == null || data == null || fields.isEmpty()) if (fields == null || data == null || fields.isEmpty())
return new ArrayList<>(); return new ArrayList<>();
FieldSet referenceFields = fields.extractPrefixed(this.asPrefix(DescriptionReference._reference)); FieldSet referenceFields = fields.extractPrefixed(this.asPrefix(UserAdditionalInfo._organization));
Map<UUID, Reference> referenceItemsMap = this.collectReferences(referenceFields, data); Map<UUID, Reference> referenceItemsMap = this.collectReferences(referenceFields, data);
List<UserAdditionalInfo> models = new ArrayList<>(); List<UserAdditionalInfo> models = new ArrayList<>();

View File

@ -1,5 +1,6 @@
package org.opencdmp.model.persist; package org.opencdmp.model.persist;
import gr.cite.tools.validation.ValidatorFactory;
import org.opencdmp.commons.validation.BaseValidator; import org.opencdmp.commons.validation.BaseValidator;
import gr.cite.tools.validation.specification.Specification; import gr.cite.tools.validation.specification.Specification;
import org.opencdmp.convention.ConventionService; import org.opencdmp.convention.ConventionService;
@ -12,7 +13,6 @@ import org.springframework.stereotype.Component;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID;
public class UserAdditionalInfoPersist { public class UserAdditionalInfoPersist {
@ -32,9 +32,9 @@ public class UserAdditionalInfoPersist {
private String roleOrganization; private String roleOrganization;
private UUID organizationId; private ReferencePersist organization;
public static final String _organizationId = "organizationId"; public static final String _organization = "organization";
public String getAvatarUrl() { public String getAvatarUrl() {
return avatarUrl; return avatarUrl;
@ -76,12 +76,12 @@ public class UserAdditionalInfoPersist {
this.roleOrganization = roleOrganization; this.roleOrganization = roleOrganization;
} }
public UUID getOrganizationId() { public ReferencePersist getOrganization() {
return organizationId; return organization;
} }
public void setOrganizationId(UUID organizationId) { public void setOrganization(ReferencePersist organization) {
this.organizationId = organizationId; this.organization = organization;
} }
@Component(UserAdditionalInfoPersistValidator.ValidatorName) @Component(UserAdditionalInfoPersistValidator.ValidatorName)
@ -91,10 +91,12 @@ public class UserAdditionalInfoPersist {
public static final String ValidatorName = "UserAdditionalInfoPersistValidator"; public static final String ValidatorName = "UserAdditionalInfoPersistValidator";
private final MessageSource messageSource; private final MessageSource messageSource;
private final ValidatorFactory validatorFactory;
protected UserAdditionalInfoPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) { protected UserAdditionalInfoPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
super(conventionService, errors); super(conventionService, errors);
this.messageSource = messageSource; this.messageSource = messageSource;
this.validatorFactory = validatorFactory;
} }
@Override @Override
@ -113,7 +115,12 @@ public class UserAdditionalInfoPersist {
.failOn(UserAdditionalInfoPersist._culture).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserAdditionalInfoPersist._culture}, LocaleContextHolder.getLocale())), .failOn(UserAdditionalInfoPersist._culture).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserAdditionalInfoPersist._culture}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.must(() -> !this.isEmpty(item.getLanguage())) .must(() -> !this.isEmpty(item.getLanguage()))
.failOn(UserAdditionalInfoPersist._language).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserAdditionalInfoPersist._language}, LocaleContextHolder.getLocale())) .failOn(UserAdditionalInfoPersist._language).failWith(messageSource.getMessage("Validation_Required", new Object[]{UserAdditionalInfoPersist._language}, LocaleContextHolder.getLocale())),
this.refSpec()
.iff(() -> !this.isNull(item.getOrganization()))
.on(UserAdditionalInfoPersist._organization)
.over(item.getOrganization())
.using(() -> this.validatorFactory.validator(ReferencePersist.ReferenceWithoutTypePersistValidator.class))
); );
} }
} }

View File

@ -26,10 +26,7 @@ import org.opencdmp.authorization.OwnedResource;
import org.opencdmp.authorization.Permission; import org.opencdmp.authorization.Permission;
import org.opencdmp.commons.JsonHandlingService; import org.opencdmp.commons.JsonHandlingService;
import org.opencdmp.commons.XmlHandlingService; import org.opencdmp.commons.XmlHandlingService;
import org.opencdmp.commons.enums.ActionConfirmationStatus; import org.opencdmp.commons.enums.*;
import org.opencdmp.commons.enums.ActionConfirmationType;
import org.opencdmp.commons.enums.ContactInfoType;
import org.opencdmp.commons.enums.IsActive;
import org.opencdmp.commons.enums.notification.NotificationContactType; import org.opencdmp.commons.enums.notification.NotificationContactType;
import org.opencdmp.commons.notification.NotificationProperties; import org.opencdmp.commons.notification.NotificationProperties;
import org.opencdmp.commons.scope.tenant.TenantScope; import org.opencdmp.commons.scope.tenant.TenantScope;
@ -37,6 +34,7 @@ import org.opencdmp.commons.scope.user.UserScope;
import org.opencdmp.commons.types.actionconfirmation.MergeAccountConfirmationEntity; import org.opencdmp.commons.types.actionconfirmation.MergeAccountConfirmationEntity;
import org.opencdmp.commons.types.actionconfirmation.RemoveCredentialRequestEntity; import org.opencdmp.commons.types.actionconfirmation.RemoveCredentialRequestEntity;
import org.opencdmp.commons.types.notification.*; import org.opencdmp.commons.types.notification.*;
import org.opencdmp.commons.types.reference.DefinitionEntity;
import org.opencdmp.commons.types.user.AdditionalInfoEntity; import org.opencdmp.commons.types.user.AdditionalInfoEntity;
import org.opencdmp.commons.types.usercredential.UserCredentialDataEntity; import org.opencdmp.commons.types.usercredential.UserCredentialDataEntity;
import org.opencdmp.convention.ConventionService; import org.opencdmp.convention.ConventionService;
@ -54,6 +52,9 @@ import org.opencdmp.model.deleter.*;
import org.opencdmp.model.persist.*; import org.opencdmp.model.persist.*;
import org.opencdmp.model.persist.actionconfirmation.MergeAccountConfirmationPersist; import org.opencdmp.model.persist.actionconfirmation.MergeAccountConfirmationPersist;
import org.opencdmp.model.persist.actionconfirmation.RemoveCredentialRequestPersist; import org.opencdmp.model.persist.actionconfirmation.RemoveCredentialRequestPersist;
import org.opencdmp.model.persist.referencedefinition.DefinitionPersist;
import org.opencdmp.model.reference.Reference;
import org.opencdmp.model.referencetype.ReferenceType;
import org.opencdmp.model.user.User; import org.opencdmp.model.user.User;
import org.opencdmp.model.usercredential.UserCredential; import org.opencdmp.model.usercredential.UserCredential;
import org.opencdmp.query.*; import org.opencdmp.query.*;
@ -187,10 +188,13 @@ public class UserServiceImpl implements UserService {
return this.builderFactory.builder(UserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, User._id), data); return this.builderFactory.builder(UserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, User._id), data);
} }
private @NotNull AdditionalInfoEntity buildAdditionalInfoEntity(UserAdditionalInfoPersist persist){ private @NotNull AdditionalInfoEntity buildAdditionalInfoEntity(UserAdditionalInfoPersist persist) throws InvalidApplicationException {
AdditionalInfoEntity data = new AdditionalInfoEntity(); AdditionalInfoEntity data = new AdditionalInfoEntity();
if (persist == null) return data; if (persist == null) return data;
data.setOrganizationId(persist.getOrganizationId()); if (persist.getOrganization() != null) {
ReferenceEntity organization = this.buildReferenceEntity(persist.getOrganization());
data.setOrganizationId(organization != null ? organization.getId() : null);
}
data.setRoleOrganization(persist.getRoleOrganization()); data.setRoleOrganization(persist.getRoleOrganization());
data.setCulture(persist.getCulture()); data.setCulture(persist.getCulture());
data.setTimezone(persist.getTimezone()); data.setTimezone(persist.getTimezone());
@ -199,6 +203,73 @@ public class UserServiceImpl implements UserService {
return data; return data;
} }
private @NotNull ReferenceEntity buildReferenceEntity(ReferencePersist model) throws InvalidApplicationException {
ReferenceEntity referenceEntity = null;
if (this.conventionService.isValidGuid(model.getId())) {
referenceEntity = this.entityManager.find(ReferenceEntity.class, model.getId());
if (referenceEntity == null)
throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Reference.class.getSimpleName()}, LocaleContextHolder.getLocale()));
} else {
referenceEntity = this.queryFactory.query(ReferenceQuery.class).sourceTypes(model.getSourceType()).typeIds(model.getTypeId()).sources(model.getSource()).isActive(IsActive.Active).references(model.getReference()).first();
if (referenceEntity == null) {
referenceEntity = new ReferenceEntity();
referenceEntity.setId(UUID.randomUUID());
referenceEntity.setLabel(model.getLabel());
referenceEntity.setIsActive(IsActive.Active);
referenceEntity.setCreatedAt(Instant.now());
referenceEntity.setTypeId(model.getTypeId());
referenceEntity.setDefinition(this.xmlHandlingService.toXmlSafe(this.buildDefinitionEntity(model.getDefinition())));
referenceEntity.setUpdatedAt(Instant.now());
referenceEntity.setReference(model.getReference());
referenceEntity.setAbbreviation(model.getAbbreviation());
referenceEntity.setSource(model.getSource());
referenceEntity.setSourceType(model.getSourceType());
try {
ReferenceTypeEntity referenceType = this.queryFactory.query(ReferenceTypeQuery.class).ids(model.getTypeId()).firstAs(new BaseFieldSet().ensure(ReferenceType._id).ensure(ReferenceTypeEntity._tenantId));
if (referenceType == null)
throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{model.getTypeId(), ReferenceType.class.getSimpleName()}, LocaleContextHolder.getLocale()));
if (referenceEntity.getSourceType().equals(ReferenceSourceType.External) && !this.tenantScope.isDefaultTenant() && referenceType.getTenantId() == null) {
this.tenantScope.setTempTenant(this.entityManager.getEntityManager(), null, this.tenantScope.getDefaultTenantCode());
}
this.entityManager.persist(referenceEntity);
} finally {
this.tenantScope.removeTempTenant(this.entityManager.getEntityManager());
}
}
}
this.entityManager.flush();
return referenceEntity;
}
private @NotNull DefinitionEntity buildDefinitionEntity(DefinitionPersist persist) {
DefinitionEntity data = new DefinitionEntity();
if (persist == null) return data;
if (!this.conventionService.isListNullOrEmpty(persist.getFields())) {
data.setFields(new ArrayList<>());
for (org.opencdmp.model.persist.referencedefinition.FieldPersist fieldPersist : persist.getFields()) {
data.getFields().add(this.buildFieldEntity(fieldPersist));
}
}
return data;
}
private @NotNull org.opencdmp.commons.types.reference.FieldEntity buildFieldEntity(org.opencdmp.model.persist.referencedefinition.FieldPersist persist) {
org.opencdmp.commons.types.reference.FieldEntity data = new org.opencdmp.commons.types.reference.FieldEntity();
if (persist == null) return data;
data.setCode(persist.getCode());
data.setDataType(persist.getDataType());
data.setCode(persist.getCode());
return data;
}
//endregion //endregion
//region delete //region delete

View File

@ -1,7 +1,7 @@
import { RoleOrganizationType } from "@app/core/common/enum/role-organization-type"; import { RoleOrganizationType } from "@app/core/common/enum/role-organization-type";
import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model"; import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
import { Guid } from "@common/types/guid"; import { Guid } from "@common/types/guid";
import { Reference } from "../reference/reference"; import { Reference, ReferencePersist } from "../reference/reference";
import { ContactInfoType } from "@notification-service/core/enum/contact-info-type.enum"; import { ContactInfoType } from "@notification-service/core/enum/contact-info-type.enum";
export interface User extends BaseEntity { export interface User extends BaseEntity {
@ -24,7 +24,7 @@ export interface UserAdditionalInfoPersist {
culture: String; culture: String;
language: String; language: String;
roleOrganization: String; roleOrganization: String;
organizationId: Guid; organization: ReferencePersist;
} }
export interface UserAdditionalInfo { export interface UserAdditionalInfo {

View File

@ -154,6 +154,21 @@ export class ConfigurationService extends BaseComponent {
return this._authProviders; return this._authProviders;
} }
private _researcherId: any;
get researcherId(): boolean {
return this._researcherId;
}
private _grantId: any;
get grantId(): boolean {
return this._grantId;
}
private _organizationId: any;
get organizationId(): boolean {
return this._organizationId;
}
public loadConfiguration(): Promise<any> { public loadConfiguration(): Promise<any> {
return new Promise((r, e) => { return new Promise((r, e) => {
// We need to exclude all interceptors here, for the initial configuration request. // We need to exclude all interceptors here, for the initial configuration request.
@ -224,6 +239,10 @@ export class ConfigurationService extends BaseComponent {
this._newReleaseNotificationLink = config.newReleaseNotification?.link; this._newReleaseNotificationLink = config.newReleaseNotification?.link;
this._newReleaseNotificationVersionCode = config.newReleaseNotification?.versionCode; this._newReleaseNotificationVersionCode = config.newReleaseNotification?.versionCode;
this._authProviders = AuthProviders.parseValue(config.authProviders); this._authProviders = AuthProviders.parseValue(config.authProviders);
this._researcherId = config.referenceTypes.researcherId;
this._grantId = config.referenceTypes.grantId;
this._organizationId = config.referenceTypes.organizationId;
} }
} }

View File

@ -131,14 +131,14 @@ export class ReferenceTypeService {
} }
public getResearcherReferenceType(): any { public getResearcherReferenceType(): any {
return '5a2112e7-ea99-4cfe-98a1-68665e26726e'; return this.configurationService.researcherId;
} }
public getGrantReferenceType(): any { public getGrantReferenceType(): any {
return '5b9c284f-f041-4995-96cc-fad7ad13289c'; return this.configurationService.grantId;
} }
public getOrganizationReferenceType(): any { public getOrganizationReferenceType(): any {
return '7eeffb98-58fb-4921-82ec-e27f32f8e738'; return this.configurationService.organizationId;
} }
} }

View File

@ -1,6 +1,6 @@
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type'; import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type';
import { Reference } from '@app/core/model/reference/reference'; import { ReferencePersist } from '@app/core/model/reference/reference';
import { User, UserAdditionalInfo, UserAdditionalInfoPersist, UserPersist } from '@app/core/model/user/user'; import { User, UserAdditionalInfo, UserAdditionalInfoPersist, UserPersist } from '@app/core/model/user/user';
import { BaseEditorModel } from '@common/base/base-form-editor-model'; import { BaseEditorModel } from '@common/base/base-form-editor-model';
import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; import { BackendErrorValidator } from '@common/forms/validation/custom-validator';
@ -77,7 +77,7 @@ export class UserAdditionalInfoEditorModel implements UserAdditionalInfoPersist
culture: String; culture: String;
language: String; language: String;
roleOrganization: RoleOrganizationType; roleOrganization: RoleOrganizationType;
organizationId: Guid; organization: ReferencePersist;
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
@ -92,7 +92,19 @@ export class UserAdditionalInfoEditorModel implements UserAdditionalInfoPersist
this.culture = item.culture; this.culture = item.culture;
this.language = item.language; this.language = item.language;
this.roleOrganization = item.roleOrganization this.roleOrganization = item.roleOrganization
this.organizationId = item.organization?.id if (item.organization){
this.organization = {
id: item.organization.id,
label: item.organization.label,
reference: item.organization.reference,
source: item.organization.source,
typeId: item.organization.type.id,
description: item.organization.source,
definition: item.organization.definition,
abbreviation: item.organization.abbreviation,
sourceType: item.organization.sourceType
}
}
} }
return this; return this;
@ -118,7 +130,7 @@ export class UserAdditionalInfoEditorModel implements UserAdditionalInfoPersist
culture: [{ value: this.culture, disabled: disabled }, context.getValidation('culture').validators], culture: [{ value: this.culture, disabled: disabled }, context.getValidation('culture').validators],
language: [{ value: this.language ? availableLanguages.filter(x => x === this.language).pop() : '', disabled: disabled }, context.getValidation('language').validators], language: [{ value: this.language ? availableLanguages.filter(x => x === this.language).pop() : '', disabled: disabled }, context.getValidation('language').validators],
roleOrganization: [{ value: this.roleOrganization, disabled: disabled }, context.getValidation('roleOrganization').validators], roleOrganization: [{ value: this.roleOrganization, disabled: disabled }, context.getValidation('roleOrganization').validators],
organizationId: [{ value: this.organizationId, disabled: disabled }, context.getValidation('organizationId').validators], organization: [{ value: this.organization, disabled: disabled }, context.getValidation('organization').validators],
}); });
} }
@ -135,7 +147,7 @@ export class UserAdditionalInfoEditorModel implements UserAdditionalInfoPersist
baseValidationArray.push({ key: 'culture', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}culture`)] }); baseValidationArray.push({ key: 'culture', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}culture`)] });
baseValidationArray.push({ key: 'language', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}language`)] }); baseValidationArray.push({ key: 'language', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}language`)] });
baseValidationArray.push({ key: 'roleOrganization', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}roleOrganization`)] }); baseValidationArray.push({ key: 'roleOrganization', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}roleOrganization`)] });
baseValidationArray.push({ key: 'organizationId', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}organizationId`)] }); baseValidationArray.push({ key: 'organization', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}organization`)] });
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
@ -152,7 +164,7 @@ export class UserAdditionalInfoEditorModel implements UserAdditionalInfoPersist
validationErrorModel validationErrorModel
}); });
['avatarUrl', 'timezone', 'culture', 'language', 'roleOrganization', 'organizationId'].forEach(keyField => { ['avatarUrl', 'timezone', 'culture', 'language', 'roleOrganization', 'organization'].forEach(keyField => {
const control = formGroup?.get(keyField); const control = formGroup?.get(keyField);
control?.clearValidators(); control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators); control?.addValidators(context.getValidation(keyField).validators);

View File

@ -111,7 +111,7 @@
<div class="row"> <div class="row">
<div class="col organization-form"> <div class="col organization-form">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<app-single-auto-complete placeholder="{{'DMP-EDITOR.PLACEHOLDER.ORGANIZATION' | translate}}" [formControl]="this.formGroup.get('additionalInfo').get('organizationId')" [configuration]="organisationsSingleAutoCompleteConfiguration"></app-single-auto-complete> <app-single-auto-complete placeholder="{{'DMP-EDITOR.PLACEHOLDER.ORGANIZATION' | translate}}" [formControl]="this.formGroup.get('additionalInfo').get('organization')" [configuration]="organisationsSingleAutoCompleteConfiguration"></app-single-auto-complete>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>

View File

@ -6,7 +6,7 @@ import { ActivatedRoute, Params, Router } from '@angular/router';
import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type'; import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type';
import { CultureInfo } from '@app/core/model/culture-info'; import { CultureInfo } from '@app/core/model/culture-info';
import { Reference } from '@app/core/model/reference/reference'; import { Reference } from '@app/core/model/reference/reference';
import { User, UserCredential, UserPersist } from '@app/core/model/user/user'; import { User, UserAdditionalInfo, UserCredential, UserPersist } from '@app/core/model/user/user';
import { AuthService } from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { CultureService } from '@app/core/services/culture/culture-service'; import { CultureService } from '@app/core/services/culture/culture-service';
@ -37,6 +37,7 @@ import { ReferenceService } from '@app/core/services/reference/reference.service
import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service'; import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { ReferenceSourceType } from '@app/core/common/enum/reference-source-type'; import { ReferenceSourceType } from '@app/core/common/enum/reference-source-type';
import { ReferenceType } from '@app/core/model/reference-type/reference-type';
@Component({ @Component({
selector: 'app-user-profile', selector: 'app-user-profile',
@ -147,7 +148,13 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
nameof<User>(x => x.additionalInfo.language), nameof<User>(x => x.additionalInfo.language),
nameof<User>(x => x.additionalInfo.timezone), nameof<User>(x => x.additionalInfo.timezone),
nameof<User>(x => x.additionalInfo.culture), nameof<User>(x => x.additionalInfo.culture),
nameof<User>(x => x.additionalInfo.organization), [nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.id)].join('.'),
[nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.label)].join('.'),
[nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.type), nameof<ReferenceType>(x => x.id)].join('.'),
[nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.reference)].join('.'),
[nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.source)].join('.'),
[nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.sourceType)].join('.'),
[nameof<User>(x => x.additionalInfo), nameof<UserAdditionalInfo>(x => x.organization), nameof<Reference>(x => x.isActive)].join('.'),
nameof<User>(x => x.additionalInfo.roleOrganization), nameof<User>(x => x.additionalInfo.roleOrganization),
nameof<User>(x => x.createdAt), nameof<User>(x => x.createdAt),
nameof<User>(x => x.updatedAt), nameof<User>(x => x.updatedAt),
@ -242,6 +249,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
return; return;
} }
const formData = this.formService.getValue(this.formGroup.value) as UserPersist; const formData = this.formService.getValue(this.formGroup.value) as UserPersist;
formData.additionalInfo.organization.typeId = Guid.parse(this.referenceTypeService.getOrganizationReferenceType());
this.userService.persist(formData) this.userService.persist(formData)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe( .subscribe(
@ -257,9 +265,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
}); });
// .subscribe(result => window.location.reload()); // .subscribe(result => window.location.reload());
}, },
error => { error => this.onCallbackError(error));
console.log(error);
});
} }
public unlock() { public unlock() {

View File

@ -65,5 +65,10 @@
"cultures": ["en"] "cultures": ["en"]
} }
] ]
},
"referenceTypes": {
"researcherId": "5a2112e7-ea99-4cfe-98a1-68665e26726e",
"grantId": "5b9c284f-f041-4995-96cc-fad7ad13289c",
"organizationId": "7eeffb98-58fb-4921-82ec-e27f32f8e738"
} }
} }

View File

@ -167,7 +167,7 @@ public class DatasetMigrationService {
private List<DmpDescriptionTemplateEntity> getOrCreateDmpDescriptionTemplateEntity(Dataset item, UUID sectionId, List<DmpDescriptionTemplateEntity> dmpDescriptionTemplateEntities){ private List<DmpDescriptionTemplateEntity> getOrCreateDmpDescriptionTemplateEntity(Dataset item, UUID sectionId, List<DmpDescriptionTemplateEntity> dmpDescriptionTemplateEntities){
List<DmpDescriptionTemplateEntity> itemDescriptionTemplates = dmpDescriptionTemplateEntities.stream().filter(x-> x.getDescriptionTemplateGroupId().equals(item.getProfile().getGroupId()) && x.getDmpId().equals(item.getDmp().getId()) && x.getSectionId().equals(sectionId)).toList(); List<DmpDescriptionTemplateEntity> itemDescriptionTemplates = dmpDescriptionTemplateEntities.stream().filter(x-> x.getDescriptionTemplateGroupId().equals(item.getProfile().getGroupId()) && x.getDmpId().equals(item.getDmp().getId()) && x.getSectionId().equals(sectionId)).toList();
if (itemDescriptionTemplates.isEmpty()) { if (itemDescriptionTemplates.isEmpty()) {
logger.warn("Migrate Dataset " + item.getId() + " cannot found DmpDescriptionTemplateEntity for section " + item.getDmpSectionIndex()); if (!item.getStatus().equals(Dataset.Status.DELETED.getValue())) logger.warn("Migrate Dataset " + item.getId() + " cannot found DmpDescriptionTemplateEntity for section " + item.getDmpSectionIndex());
if (dmpDescriptionTemplateEntities.stream().anyMatch(x -> x.getDmpId().equals(item.getDmp().getId()) && x.getSectionId().equals(sectionId))) { if (dmpDescriptionTemplateEntities.stream().anyMatch(x -> x.getDmpId().equals(item.getDmp().getId()) && x.getSectionId().equals(sectionId))) {
DmpDescriptionTemplateEntity dmpDescriptionTemplateEntity = new DmpDescriptionTemplateEntity(); DmpDescriptionTemplateEntity dmpDescriptionTemplateEntity = new DmpDescriptionTemplateEntity();
dmpDescriptionTemplateEntity.setId(UUID.randomUUID()); dmpDescriptionTemplateEntity.setId(UUID.randomUUID());
@ -176,7 +176,7 @@ public class DatasetMigrationService {
dmpDescriptionTemplateEntity.setCreatedAt(item.getCreated() != null ? item.getCreated().toInstant() : Instant.now()); dmpDescriptionTemplateEntity.setCreatedAt(item.getCreated() != null ? item.getCreated().toInstant() : Instant.now());
dmpDescriptionTemplateEntity.setUpdatedAt(item.getModified() != null ? item.getModified().toInstant() : Instant.now()); dmpDescriptionTemplateEntity.setUpdatedAt(item.getModified() != null ? item.getModified().toInstant() : Instant.now());
dmpDescriptionTemplateEntity.setSectionId(sectionId); dmpDescriptionTemplateEntity.setSectionId(sectionId);
dmpDescriptionTemplateEntity.setIsActive(IsActive.Active); dmpDescriptionTemplateEntity.setIsActive(!item.getStatus().equals(Dataset.Status.DELETED.getValue()) ? IsActive.Active : IsActive.Inactive);
this.entityManager.persist(dmpDescriptionTemplateEntity); this.entityManager.persist(dmpDescriptionTemplateEntity);
itemDescriptionTemplates = List.of(dmpDescriptionTemplateEntity); itemDescriptionTemplates = List.of(dmpDescriptionTemplateEntity);
} else { } else {
@ -189,8 +189,9 @@ public class DatasetMigrationService {
private PropertyDefinitionEntity buildPropertyDefinitionEntity(Dataset item, org.opencdmp.commons.types.descriptiontemplate.DefinitionEntity descriptionTemplateDefinitionEntity, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap) { private PropertyDefinitionEntity buildPropertyDefinitionEntity(Dataset item, org.opencdmp.commons.types.descriptiontemplate.DefinitionEntity descriptionTemplateDefinitionEntity, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap) {
if (this.conventionService.isNullOrEmpty(item.getProperties())) return null; if (this.conventionService.isNullOrEmpty(item.getProperties())) return null;
JSONObject jObject = new JSONObject(item.getProperties()); JSONObject jObject = new JSONObject(item.getProperties());
Map<String, Object> properties = jObject.toMap(); Map<String, Object> properties = new HashMap<>();
for (Map.Entry<String, Object> entry : jObject.toMap().entrySet()) properties.put(entry.getKey().trim(), entry.getValue());
PropertyDefinitionEntity propertyDefinitionEntity = new PropertyDefinitionEntity(); PropertyDefinitionEntity propertyDefinitionEntity = new PropertyDefinitionEntity();
propertyDefinitionEntity.setFieldSets(new HashMap<>()); propertyDefinitionEntity.setFieldSets(new HashMap<>());
@ -225,7 +226,7 @@ public class DatasetMigrationService {
continue; continue;
} }
this.addSimpleField(item, propertyDefinitionEntity, currentFieldSet, currentField, properties, referenceTypeDefinitionEntityMap, referenceMap); this.addSimpleField(item, propertyDefinitionEntity, currentFieldSet, currentField, properties.get(key), referenceTypeDefinitionEntityMap, referenceMap);
} }
} }
} }
@ -315,13 +316,13 @@ public class DatasetMigrationService {
if (ordinal == SimpleFieldSetOrdinal) throw new MyApplicationException("Fieldset has migration simple fieldset ordinal " + SimpleFieldSetOrdinal); if (ordinal == SimpleFieldSetOrdinal) throw new MyApplicationException("Fieldset has migration simple fieldset ordinal " + SimpleFieldSetOrdinal);
this.addMultipleField(item, propertyDefinitionFieldSetEntity, ordinal, currentField, properties, referenceTypeDefinitionEntityMap, referenceMap); this.addMultipleField(item, propertyDefinitionFieldSetEntity, ordinal, currentField, properties.get(key), referenceTypeDefinitionEntityMap, referenceMap);
} }
} }
} }
private void addMultipleField(Dataset item, PropertyDefinitionFieldSetEntity propertyDefinitionFieldSetEntity, int ordinal, org.opencdmp.commons.types.descriptiontemplate.FieldEntity currentField, Map<String, Object> properties, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap){ private void addMultipleField(Dataset item, PropertyDefinitionFieldSetEntity propertyDefinitionFieldSetEntity, int ordinal, org.opencdmp.commons.types.descriptiontemplate.FieldEntity currentField, Object propertyValue, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap){
PropertyDefinitionFieldSetItemEntity propertyDefinitionFieldSetItemEntity = propertyDefinitionFieldSetEntity.getItems().stream().filter(x-> x.getOrdinal() == ordinal).findFirst().orElse(null); PropertyDefinitionFieldSetItemEntity propertyDefinitionFieldSetItemEntity = propertyDefinitionFieldSetEntity.getItems().stream().filter(x-> x.getOrdinal() == ordinal).findFirst().orElse(null);
if (propertyDefinitionFieldSetItemEntity == null){ if (propertyDefinitionFieldSetItemEntity == null){
@ -331,10 +332,10 @@ public class DatasetMigrationService {
propertyDefinitionFieldSetEntity.getItems().add(propertyDefinitionFieldSetItemEntity); propertyDefinitionFieldSetEntity.getItems().add(propertyDefinitionFieldSetItemEntity);
} }
propertyDefinitionFieldSetItemEntity.getFields().put(currentField.getId().trim(), this.buildField(item, currentField, properties, referenceTypeDefinitionEntityMap, referenceMap)); propertyDefinitionFieldSetItemEntity.getFields().put(currentField.getId().trim(), this.buildField(item, currentField, propertyValue, referenceTypeDefinitionEntityMap, referenceMap));
} }
private void addSimpleField(Dataset item, PropertyDefinitionEntity propertyDefinitionEntity, FieldSetEntity currentFieldSet, org.opencdmp.commons.types.descriptiontemplate.FieldEntity currentField, Map<String, Object> properties, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap){ private void addSimpleField(Dataset item, PropertyDefinitionEntity propertyDefinitionEntity, FieldSetEntity currentFieldSet, org.opencdmp.commons.types.descriptiontemplate.FieldEntity currentField, Object propertyValue, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap){
PropertyDefinitionFieldSetEntity propertyDefinitionFieldSetEntity = propertyDefinitionEntity.getFieldSets().getOrDefault(currentFieldSet.getId().trim(), null); PropertyDefinitionFieldSetEntity propertyDefinitionFieldSetEntity = propertyDefinitionEntity.getFieldSets().getOrDefault(currentFieldSet.getId().trim(), null);
if (propertyDefinitionFieldSetEntity == null) { if (propertyDefinitionFieldSetEntity == null) {
propertyDefinitionFieldSetEntity = new PropertyDefinitionFieldSetEntity(); propertyDefinitionFieldSetEntity = new PropertyDefinitionFieldSetEntity();
@ -352,7 +353,7 @@ public class DatasetMigrationService {
propertyDefinitionFieldSetItemEntity = propertyDefinitionFieldSetEntity.getItems().getFirst(); propertyDefinitionFieldSetItemEntity = propertyDefinitionFieldSetEntity.getItems().getFirst();
} }
propertyDefinitionFieldSetItemEntity.getFields().put(currentField.getId().trim(), this.buildField(item, currentField, properties, referenceTypeDefinitionEntityMap, referenceMap)); propertyDefinitionFieldSetItemEntity.getFields().put(currentField.getId().trim(), this.buildField(item, currentField, propertyValue, referenceTypeDefinitionEntityMap, referenceMap));
} }
@ -377,9 +378,9 @@ public class DatasetMigrationService {
propertyDefinitionFieldSetItemEntity.setComment(comment); propertyDefinitionFieldSetItemEntity.setComment(comment);
} }
private FieldEntity buildField(Dataset item, org.opencdmp.commons.types.descriptiontemplate.FieldEntity currentField, Map<String, Object> properties, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap){ private FieldEntity buildField(Dataset item, org.opencdmp.commons.types.descriptiontemplate.FieldEntity currentField, Object propertyValue, Map<UUID, ReferenceTypeDefinitionEntity> referenceTypeDefinitionEntityMap, Map<ReferenceKey, ReferenceEntity> referenceMap){
FieldEntity fieldEntity = new FieldEntity(); FieldEntity fieldEntity = new FieldEntity();
String textValue = properties.get(currentField.getId()) != null ? properties.get(currentField.getId()).toString() : null; String textValue = propertyValue != null ? propertyValue.toString() : null;
if (textValue == null || textValue.isEmpty()) return fieldEntity; if (textValue == null || textValue.isEmpty()) return fieldEntity;
switch (currentField.getData().getFieldType()){ switch (currentField.getData().getFieldType()){
case FREE_TEXT, TEXT_AREA, RICH_TEXT_AREA, RADIO_BOX -> fieldEntity.setTextValue(textValue.trim()); case FREE_TEXT, TEXT_AREA, RICH_TEXT_AREA, RADIO_BOX -> fieldEntity.setTextValue(textValue.trim());
@ -416,7 +417,7 @@ public class DatasetMigrationService {
if(!this.conventionService.isNullOrEmpty(textValue)) { if(!this.conventionService.isNullOrEmpty(textValue)) {
Map<String, String> valuesParsed = migrationTools.tryParseJsonAsObjectString(Map.class, textValue); Map<String, String> valuesParsed = migrationTools.tryParseJsonAsObjectString(Map.class, textValue);
if (valuesParsed == null) { if (valuesParsed == null) {
valuesParsed = (Map<String, String>) properties.get(currentField.getId()); valuesParsed = (Map<String, String>) propertyValue;
} }
if (valuesParsed == null) throw new MyApplicationException("Could not parse upload : " + textValue); if (valuesParsed == null) throw new MyApplicationException("Could not parse upload : " + textValue);
String id = valuesParsed.getOrDefault("id", null); String id = valuesParsed.getOrDefault("id", null);
@ -999,7 +1000,7 @@ public class DatasetMigrationService {
data.setSourceType(ReferenceSourceType.Internal); data.setSourceType(ReferenceSourceType.Internal);
data.setSource("Internal"); data.setSource("Internal");
if (dataset.getCreator() != null) data.setCreatedById(dataset.getCreator().getId()); if (dataset.getCreator() != null) data.setCreatedById(dataset.getCreator().getId());
logger.warn("Migrate Dataset " + dataset.getId() + " " + dataset.getLabel() + " reference auto created as internal " + referenceTypeDataEntity.getReferenceTypeId() + " for value " + this.jsonHandlingService.toJsonSafe(item)); //logger.warn("Migrate Dataset " + dataset.getId() + " " + dataset.getLabel() + " reference auto created as internal " + referenceTypeDataEntity.getReferenceTypeId() + " for value " + this.jsonHandlingService.toJsonSafe(item));
} }
ReferenceEntity existingEntity = referenceMap.getOrDefault(new ReferenceKey(data), null); ReferenceEntity existingEntity = referenceMap.getOrDefault(new ReferenceKey(data), null);

View File

@ -63,9 +63,8 @@ public class StorageFileMigrationService {
logger.debug("Migrate FileUpload " + page * PageSize + " of " + total); logger.debug("Migrate FileUpload " + page * PageSize + " of " + total);
for (FileUpload item : items) { for (FileUpload item : items) {
entityManager.detach(item); entityManager.detach(item);
// File file = new File(this.environment.getProperty("file.storage") + item.getId().toString()); File file = new File(this.environment.getProperty("file.migration-storage") + item.getId().toString());
// if (!file.exists()) file = new File(this.environment.getProperty("temp.temp") + item.getId().toString()); if (!file.exists()) throw new MyApplicationException("Storage file not exist " + item.getId().toString());
// if (!file.exists()) throw new MyApplicationException("Storage file not exist " + item.getId().toString());
StorageFileEntity data = new StorageFileEntity(); StorageFileEntity data = new StorageFileEntity();
data.setId(item.getId()); data.setId(item.getId());
@ -80,11 +79,11 @@ public class StorageFileMigrationService {
data.setPurgedAt(null); data.setPurgedAt(null);
if (item.getCreator() == null) data.setOwnerId(item.getCreator().getId()); if (item.getCreator() == null) data.setOwnerId(item.getCreator().getId());
// File destinationFile = new File(Paths.get(this.environment.getProperty("file.mainstorage"), data.getFileRef()).toString()); File destinationFile = new File(Paths.get(this.environment.getProperty("file.migrated-storage"), data.getFileRef()).toString());
// boolean fileCopied = FileCopyUtils.copy(file, destinationFile) > 0; boolean fileCopied = FileCopyUtils.copy(file, destinationFile) > 0;
// if (!fileCopied) throw new MyApplicationException("Storage file not copied " + data.getId().toString()); if (!fileCopied) throw new MyApplicationException("Storage file not copied " + data.getId().toString());
// //
// filesToDelete.add(file); filesToDelete.add(file);
this.entityManager.persist(data); this.entityManager.persist(data);
} }

View File

@ -113,12 +113,12 @@ public class MigrationController {
// this.dmpMigrationService.migrate(); // this.dmpMigrationService.migrate();
// this.dmpDatasetProfileMigrationService.migrate(); // this.dmpDatasetProfileMigrationService.migrate();
// this.dmpUserMigrationService.migrate(); // this.dmpUserMigrationService.migrate();
//
//Description
this.datasetMigrationService.migrate();
this.datasetReferenceMigrationService.migrateDatasetReferences();
this.tagMigrationService.migrate();
// //Description
// this.datasetMigrationService.migrate();
// this.datasetReferenceMigrationService.migrateDatasetReferences();
// this.tagMigrationService.migrate();
//
this.storageFileMigrationService.migrate(); this.storageFileMigrationService.migrate();
// throw new RuntimeException(""); // throw new RuntimeException("");

View File

@ -5,4 +5,18 @@ description: View details about the conditional questions
# Conditional Questions # Conditional Questions
TODO: thgiannos You can set a question to be hidden by default and only show up if a certain condition is met. When you press `Make Conditional Question` on a question, you make it the source of the condition. Then, you must select the question you want to hide *(in the `then show Question` control)* and a value *(in the `If Value is` control)* for the answer that will satisfy the condition.
There can be more than one conditions set. In that case, all of them must be met. Also, it is possible to make specific question fields conditional by selecting them in the `then show Question` dropdown. All the options are grouped as `Questions` and `Inputs` respectively.
:::tip
It is recommended to specify placeholder texts for all the added inputs because they are also used in the question dropdown. Otherwise, they will be listed as '*\<Untitled\>*', making the selection of the ones you want to hide difficult.
:::
:::info
All the questions that expect text, selection list, checkbox and radio box based answers can be used as a condition, as long as they are not system specific like [references](/docs/documentation/administration/reference-types).
:::

View File

@ -79,9 +79,6 @@ public class NotifyIntegrationEventHandlerImpl implements NotifyIntegrationEvent
NotifyIntegrationEvent event = this.jsonHandlingService.fromJsonSafe(NotifyIntegrationEvent.class, message); NotifyIntegrationEvent event = this.jsonHandlingService.fromJsonSafe(NotifyIntegrationEvent.class, message);
if (event == null) if (event == null)
return EventProcessingStatus.Error; return EventProcessingStatus.Error;
if (event.getUserId() == null) {
throw new MyValidationException(this.errors.getModelValidation().getCode(), "userId", messageSource.getMessage("Validation_Required", new Object[]{"userId"}, LocaleContextHolder.getLocale()));
}
logger.debug("Handling {}", NotifyIntegrationEvent.class.getSimpleName()); logger.debug("Handling {}", NotifyIntegrationEvent.class.getSimpleName());
NotificationPersist model = new NotificationPersist(); NotificationPersist model = new NotificationPersist();
@ -125,7 +122,7 @@ public class NotifyIntegrationEventHandlerImpl implements NotifyIntegrationEvent
notificationService.persist(model, new BaseFieldSet()); notificationService.persist(model, new BaseFieldSet());
auditService.track(AuditableAction.Notification_Persist, Map.ofEntries( auditService.track(AuditableAction.Notification_Persist, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId()) new AbstractMap.SimpleEntry<String, Object>("id", event.getUserId() != null ? event.getUserId() : event.getContactHint())
)); ));
} catch (Exception ex) { } catch (Exception ex) {
status = EventProcessingStatus.Error; status = EventProcessingStatus.Error;

View File

@ -120,7 +120,7 @@ public class NotificationBuilder extends BaseBuilder<Notification, NotificationE
Map<UUID, User> itemMap; Map<UUID, User> itemMap;
if (!fields.hasOtherField(this.asIndexer(User._id))) { if (!fields.hasOtherField(this.asIndexer(User._id))) {
itemMap = this.asEmpty( itemMap = this.asEmpty(
data.stream().map(NotificationEntity::getUserId).distinct().collect(Collectors.toList()), data.stream().map(NotificationEntity::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList()),
x -> { x -> {
User item = new User(); User item = new User();
item.setId(x); item.setId(x);
@ -129,7 +129,7 @@ public class NotificationBuilder extends BaseBuilder<Notification, NotificationE
User::getId); User::getId);
} else { } else {
FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(User._id); FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(User._id);
UserQuery q = this.queryFactory.query(UserQuery.class).authorize(this.authorize).ids(data.stream().map(NotificationEntity::getUserId).distinct().collect(Collectors.toList())); UserQuery q = this.queryFactory.query(UserQuery.class).authorize(this.authorize).ids(data.stream().map(NotificationEntity::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList()));
itemMap = this.builderFactory.builder(UserBuilder.class).authorize(this.authorize).asForeignKey(q, clone, User::getId); itemMap = this.builderFactory.builder(UserBuilder.class).authorize(this.authorize).asForeignKey(q, clone, User::getId);
} }
if (!fields.hasField(User._id)) { if (!fields.hasField(User._id)) {

View File

@ -158,6 +158,7 @@ public class NotificationServiceImpl implements NotificationService {
} }
private List<NotificationContactType> orderContactTypesFromPreferences(NotificationEntity notification) { private List<NotificationContactType> orderContactTypesFromPreferences(NotificationEntity notification) {
if (notification.getUserId() == null) return null;
Ordering ordering = new Ordering(); Ordering ordering = new Ordering();
ordering.addAscending(UserNotificationPreference._ordinal); ordering.addAscending(UserNotificationPreference._ordinal);
UserNotificationPreferenceQuery query = this.queryFactory.query(UserNotificationPreferenceQuery.class).userId(notification.getUserId()).type(notification.getType()).isActives(IsActive.Active); UserNotificationPreferenceQuery query = this.queryFactory.query(UserNotificationPreferenceQuery.class).userId(notification.getUserId()).type(notification.getType()).isActives(IsActive.Active);
@ -175,7 +176,7 @@ public class NotificationServiceImpl implements NotificationService {
} }
private List<NotificationContactType> orderContactTypes(NotificationEntity notification) { private List<NotificationContactType> orderContactTypes(NotificationEntity notification) {
List<NotificationContactType> contactTypes = this.channelResolutionService.resolve(notification.getType(), notification.getUserId()); List<NotificationContactType> contactTypes = notification.getUserId() == null ? this.channelResolutionService.resolve(notification.getType()): this.channelResolutionService.resolve(notification.getType(), notification.getUserId());
if (notification.getContactTypeHint() == null) return contactTypes; if (notification.getContactTypeHint() == null) return contactTypes;
List<NotificationContactType> ordered = new ArrayList<>(Collections.singleton(notification.getContactTypeHint())); List<NotificationContactType> ordered = new ArrayList<>(Collections.singleton(notification.getContactTypeHint()));