diff --git a/Core.Abstractions/Core.Abstractions.csproj b/Core.Abstractions/Core.Abstractions.csproj
index 0ac860d89e..064d970b75 100644
--- a/Core.Abstractions/Core.Abstractions.csproj
+++ b/Core.Abstractions/Core.Abstractions.csproj
@@ -49,6 +49,7 @@
+
diff --git a/Core.Abstractions/Extensions/ObjectExtensions.cs b/Core.Abstractions/Extensions/ObjectExtensions.cs
index 5c7c9e2306..6b33073616 100644
--- a/Core.Abstractions/Extensions/ObjectExtensions.cs
+++ b/Core.Abstractions/Extensions/ObjectExtensions.cs
@@ -11,6 +11,11 @@ public static Maybe FromNullable(this T src)
return src == null ? Maybe.None : Maybe.Some(src);
}
+ public static Maybe FromNullableValueType(this T? src) where T:struct
+ {
+ return src == null ? Maybe.None : Maybe.Some(src.Value);
+ }
+
public static Maybe FromString(this string src)
{
return string.IsNullOrEmpty(src) ? Maybe.None : src;
diff --git a/Core.Abstractions/Types/DetailedOperationError.cs b/Core.Abstractions/Types/DetailedOperationError.cs
new file mode 100644
index 0000000000..e321d85c36
--- /dev/null
+++ b/Core.Abstractions/Types/DetailedOperationError.cs
@@ -0,0 +1,13 @@
+namespace Core.Abstractions.Types
+{
+ public class DetailedOperationError : OperationError
+ {
+ public DetailedOperationError(OperationFailure failureType, TDetail detail, string message = null)
+ : base(message, failureType)
+ {
+ Detail = detail;
+ }
+
+ public TDetail Detail { get; }
+ }
+}
diff --git a/Core.ApplicationServices/AdviceService.cs b/Core.ApplicationServices/AdviceService.cs
index 603ac3401d..722ff34c57 100644
--- a/Core.ApplicationServices/AdviceService.cs
+++ b/Core.ApplicationServices/AdviceService.cs
@@ -170,10 +170,10 @@ private bool DispatchEmails(Advice advice)
case RecieverType.RECIEVER:
switch (r.RecpientType)
{
- case RecieverType.USER:
+ case RecipientType.USER:
AddRecipientByName(r, message.To);
break;
- case RecieverType.ROLE:
+ case RecipientType.ROLE:
AddRecipientByRole(advice, r, message.To);
break;
}
@@ -181,10 +181,10 @@ private bool DispatchEmails(Advice advice)
case RecieverType.CC:
switch (r.RecpientType)
{
- case RecieverType.USER:
+ case RecipientType.USER:
AddRecipientByName(r, message.CC);
break;
- case RecieverType.ROLE:
+ case RecipientType.ROLE:
AddRecipientByRole(advice, r, message.CC);
break;
}
@@ -223,9 +223,9 @@ private bool DispatchEmails(Advice advice)
private static void AddRecipientByName(AdviceUserRelation r, MailAddressCollection mailAddressCollection)
{
- if (!string.IsNullOrEmpty(r.Name))
+ if (!string.IsNullOrEmpty(r.Email))
{
- mailAddressCollection.Add(r.Name);
+ mailAddressCollection.Add(r.Email);
}
}
@@ -234,20 +234,21 @@ private void AddRecipientByRole(Advice advice, AdviceUserRelation r, MailAddress
switch (advice.Type)
{
case RelatedEntityType.itContract:
-
var itContractRoles = _itContractRights.AsQueryable().Where(I => I.ObjectId == advice.RelationId
- && I.Role.Name == r.Name);
+ && I.RoleId == r.ItContractRoleId);
foreach (var t in itContractRoles)
{
+ if(t.User.Deleted) continue;
mailAddressCollection.Add(t.User.Email);
}
break;
case RelatedEntityType.itProject:
var projectRoles = _itProjectRights.AsQueryable().Where(I => I.ObjectId == advice.RelationId
- && I.Role.Name == r.Name);
+ && I.RoleId == r.ItProjectRoleId);
foreach (var t in projectRoles)
{
+ if(t.User.Deleted) continue;
mailAddressCollection.Add(t.User.Email);
}
@@ -255,9 +256,10 @@ private void AddRecipientByRole(Advice advice, AdviceUserRelation r, MailAddress
case RelatedEntityType.itSystemUsage:
var systemRoles = _itSystemRights.AsQueryable().Where(I => I.ObjectId == advice.RelationId
- && I.Role.Name == r.Name);
+ && I.RoleId == r.ItSystemRoleId);
foreach (var t in systemRoles)
{
+ if(t.User.Deleted) continue;
mailAddressCollection.Add(t.User.Email);
}
@@ -266,9 +268,10 @@ private void AddRecipientByRole(Advice advice, AdviceUserRelation r, MailAddress
var dpaRoles = _dataProcessingRegistrationRights.AsQueryable().Where(I =>
I.ObjectId == advice.RelationId
- && I.Role.Name == r.Name);
+ && I.RoleId == r.DataProcessingRegistrationRoleId);
foreach (var t in dpaRoles)
{
+ if(t.User.Deleted) continue;
mailAddressCollection.Add(t.User.Email);
}
@@ -403,7 +406,7 @@ public void UpdateSchedule(Advice advice)
public void CreateOrUpdateJob(int adviceId)
{
var advice = _adviceRepository.GetByKey(adviceId);
- if (advice == null || advice.Scheduling == null || advice.AlarmDate == null)
+ if (advice?.Scheduling == null || advice.AlarmDate == null)
{
throw new ArgumentException(nameof(adviceId) + " does not point to a valid id or points to an advice without alarm date or scheduling");
}
diff --git a/Core.ApplicationServices/Authorization/IPermissionVisitor.cs b/Core.ApplicationServices/Authorization/IPermissionVisitor.cs
index 558b2814ed..cd04912d71 100644
--- a/Core.ApplicationServices/Authorization/IPermissionVisitor.cs
+++ b/Core.ApplicationServices/Authorization/IPermissionVisitor.cs
@@ -13,5 +13,6 @@ public interface IPermissionVisitor
bool Visit(ViewBrokenExternalReferencesReportPermission permission);
bool Visit(TriggerBrokenReferencesReportPermission permission);
bool Visit(AdministerGlobalPermission permission);
+ bool Visit(ImportHierarchyFromStsOrganizationPermission permission);
}
}
diff --git a/Core.ApplicationServices/Authorization/OrganizationAuthorizationContext.cs b/Core.ApplicationServices/Authorization/OrganizationAuthorizationContext.cs
index 620038810c..54fe1ee84f 100644
--- a/Core.ApplicationServices/Authorization/OrganizationAuthorizationContext.cs
+++ b/Core.ApplicationServices/Authorization/OrganizationAuthorizationContext.cs
@@ -236,7 +236,7 @@ public bool AllowDelete(IEntity entity)
{
result = entity switch
{
- Organization _ => IsGlobalAdmin(),
+ User user => IsGlobalAdmin() && EntityEqualsActiveUser(user) == false,
ItInterface itInterface =>
//Even rightsholders are not allowed to delete interfaces
IsGlobalAdmin() || IsLocalAdmin(itInterface.OrganizationId),
@@ -369,10 +369,10 @@ bool IPermissionVisitor.Visit(VisibilityControlPermission permission)
return target switch
{
- IContractModule _ => IsGlobalAdmin() ||
+ IContractModule _ => IsGlobalAdmin() ||
IsLocalAdmin(ownedByOrganization.OrganizationId) ||
IsContractModuleAdmin(ownedByOrganization.OrganizationId),
- IOrganizationModule _ => IsGlobalAdmin() ||
+ IOrganizationModule _ => IsGlobalAdmin() ||
IsLocalAdmin(ownedByOrganization.OrganizationId),
_ => IsGlobalAdmin()
};
@@ -458,6 +458,14 @@ public bool Visit(AdministerGlobalPermission permission)
};
}
+ public bool Visit(ImportHierarchyFromStsOrganizationPermission permission)
+ {
+ var organizationId = permission.Organization.Id;
+ return IsGlobalAdmin() ||
+ IsLocalAdmin(organizationId) ||
+ IsOrganizationModuleAdmin(organizationId);
+ }
+
#endregion PERMISSIONS
}
}
\ No newline at end of file
diff --git a/Core.ApplicationServices/Authorization/Permissions/ImportHierarchyFromStsOrganizationPermission.cs b/Core.ApplicationServices/Authorization/Permissions/ImportHierarchyFromStsOrganizationPermission.cs
new file mode 100644
index 0000000000..1cce3c4f9a
--- /dev/null
+++ b/Core.ApplicationServices/Authorization/Permissions/ImportHierarchyFromStsOrganizationPermission.cs
@@ -0,0 +1,19 @@
+using Core.DomainModel.Organization;
+
+namespace Core.ApplicationServices.Authorization.Permissions
+{
+ public class ImportHierarchyFromStsOrganizationPermission : Permission
+ {
+ public Organization Organization { get; }
+
+ public ImportHierarchyFromStsOrganizationPermission(Organization organization)
+ {
+ Organization = organization;
+ }
+
+ public override bool Accept(IPermissionVisitor permissionVisitor)
+ {
+ return permissionVisitor.Visit(this);
+ }
+ }
+}
diff --git a/Core.ApplicationServices/Contract/IItContractService.cs b/Core.ApplicationServices/Contract/IItContractService.cs
index f87f32438b..69faedd006 100644
--- a/Core.ApplicationServices/Contract/IItContractService.cs
+++ b/Core.ApplicationServices/Contract/IItContractService.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Core.Abstractions.Types;
+using Core.ApplicationServices.Model.Contracts;
using Core.DomainModel.GDPR;
using Core.DomainModel.ItContract;
using Core.DomainServices.Queries;
@@ -12,7 +13,7 @@ namespace Core.ApplicationServices.Contract
public interface IItContractService
{
Result Create(int organizationId, string name);
- IQueryable GetAllByOrganization(int orgId, string optionalNameSearch = null);
+ Result,OperationError> GetAllByOrganization(int orgId, string optionalNameSearch = null);
Result Delete(int id);
Result AssignDataProcessingRegistration(int id, int dataProcessingRegistrationId);
@@ -23,5 +24,7 @@ public interface IItContractService
Result CanCreateNewContractWithName(string name, int organizationId);
Maybe ValidateNewName(int contractId, string name);
IQueryable Query(params IDomainQuery[] conditions);
+ Result GetAssignableContractOptions(int organizationId);
+ Result,OperationError> GetAppliedProcurementPlans(int organizationId);
}
}
diff --git a/Core.ApplicationServices/Contract/ItContractService.cs b/Core.ApplicationServices/Contract/ItContractService.cs
index b53456fb89..674848a8c4 100644
--- a/Core.ApplicationServices/Contract/ItContractService.cs
+++ b/Core.ApplicationServices/Contract/ItContractService.cs
@@ -4,6 +4,7 @@
using Core.Abstractions.Extensions;
using Core.Abstractions.Types;
using Core.ApplicationServices.Authorization;
+using Core.ApplicationServices.Model.Contracts;
using Core.ApplicationServices.References;
using Core.DomainModel.Events;
using Core.DomainModel.GDPR;
@@ -12,6 +13,7 @@
using Core.DomainServices.Authorization;
using Core.DomainServices.Contract;
using Core.DomainServices.Extensions;
+using Core.DomainServices.Options;
using Core.DomainServices.Queries;
using Core.DomainServices.Repositories.Contract;
using Infrastructure.Services.DataAccess;
@@ -31,6 +33,15 @@ public class ItContractService : IItContractService
private readonly ILogger _logger;
private readonly IContractDataProcessingRegistrationAssignmentService _contractDataProcessingRegistrationAssignmentService;
private readonly IOrganizationalUserContext _userContext;
+ private readonly IOptionsService _criticalityOptionsService;
+ private readonly IOptionsService _contractTypeOptionsService;
+ private readonly IOptionsService _contractTemplateOptionsService;
+ private readonly IOptionsService _purchaseFormOptionsService;
+ private readonly IOptionsService _procurementStrategyOptionsService;
+ private readonly IOptionsService _paymentModelOptionsService;
+ private readonly IOptionsService _paymentFrequencyOptionsService;
+ private readonly IOptionsService _optionExtendOptionsService;
+ private readonly IOptionsService _terminationDeadlineOptionsService;
public ItContractService(
IItContractRepository repository,
@@ -40,8 +51,17 @@ public ItContractService(
IDomainEvents domainEvents,
IAuthorizationContext authorizationContext,
ILogger logger,
- IContractDataProcessingRegistrationAssignmentService contractDataProcessingRegistrationAssignmentService,
- IOrganizationalUserContext userContext)
+ IContractDataProcessingRegistrationAssignmentService contractDataProcessingRegistrationAssignmentService,
+ IOrganizationalUserContext userContext,
+ IOptionsService criticalityOptionsService,
+ IOptionsService contractTypeOptionsService,
+ IOptionsService contractTemplateOptionsService,
+ IOptionsService purchaseFormOptionsService,
+ IOptionsService procurementStrategyOptionsService,
+ IOptionsService paymentModelOptionsService,
+ IOptionsService paymentFrequencyOptionsService,
+ IOptionsService optionExtendOptionsService,
+ IOptionsService terminationDeadlineOptionsService)
{
_repository = repository;
_economyStreamRepository = economyStreamRepository;
@@ -52,6 +72,15 @@ public ItContractService(
_logger = logger;
_contractDataProcessingRegistrationAssignmentService = contractDataProcessingRegistrationAssignmentService;
_userContext = userContext;
+ _criticalityOptionsService = criticalityOptionsService;
+ _contractTypeOptionsService = contractTypeOptionsService;
+ _contractTemplateOptionsService = contractTemplateOptionsService;
+ _purchaseFormOptionsService = purchaseFormOptionsService;
+ _procurementStrategyOptionsService = procurementStrategyOptionsService;
+ _paymentModelOptionsService = paymentModelOptionsService;
+ _paymentFrequencyOptionsService = paymentFrequencyOptionsService;
+ _optionExtendOptionsService = optionExtendOptionsService;
+ _terminationDeadlineOptionsService = terminationDeadlineOptionsService;
}
public Result Create(int organizationId, string name)
@@ -76,8 +105,12 @@ public Result Create(int organizationId, string name
return itContract;
}
- public IQueryable GetAllByOrganization(int orgId, string optionalNameSearch = null)
+ public Result, OperationError> GetAllByOrganization(int orgId, string optionalNameSearch = null)
{
+ if (_authorizationContext.GetOrganizationReadAccessLevel(orgId) != OrganizationDataReadAccessLevel.All)
+ {
+ return new OperationError(OperationFailure.Forbidden);
+ }
var contracts = _repository.GetContractsInOrganization(orgId);
if (!string.IsNullOrWhiteSpace(optionalNameSearch))
@@ -85,7 +118,7 @@ public IQueryable GetAllByOrganization(int orgId, string optionalNam
contracts = contracts.ByPartOfName(optionalNameSearch);
}
- return contracts;
+ return Result, OperationError>.Success(contracts);
}
public Result Delete(int id)
@@ -219,6 +252,45 @@ public Maybe ValidateNewName(int contractId, string name)
);
}
+ public Result GetAssignableContractOptions(int organizationId)
+ {
+ return WithOrganizationReadAccess(organizationId,
+ () => new ContractOptions(
+ _criticalityOptionsService.GetAllOptionsDetails(organizationId),
+ _contractTypeOptionsService.GetAllOptionsDetails(organizationId),
+ _contractTemplateOptionsService.GetAllOptionsDetails(organizationId),
+ _purchaseFormOptionsService.GetAllOptionsDetails(organizationId),
+ _procurementStrategyOptionsService.GetAllOptionsDetails(organizationId),
+ _paymentModelOptionsService.GetAllOptionsDetails(organizationId),
+ _paymentFrequencyOptionsService.GetAllOptionsDetails(organizationId),
+ _optionExtendOptionsService.GetAllOptionsDetails(organizationId),
+ _terminationDeadlineOptionsService.GetAllOptionsDetails(organizationId)));
+ }
+
+ public Result, OperationError> GetAppliedProcurementPlans(int organizationId)
+ {
+ return GetAllByOrganization(organizationId)
+ .Select>(contracts => contracts
+ .Where(contract => contract.ProcurementPlanYear != null && contract.ProcurementPlanQuarter != null)
+ .Select(c => new { c.ProcurementPlanYear, c.ProcurementPlanQuarter })
+ .Distinct()
+ .OrderBy(x => x.ProcurementPlanYear)
+ .ThenBy(x => x.ProcurementPlanQuarter)
+ .ToList()
+ .Select(x => (x.ProcurementPlanYear.GetValueOrDefault(), x.ProcurementPlanQuarter.GetValueOrDefault()))
+ .ToList()
+ );
+ }
+
+ private Result WithOrganizationReadAccess(int organizationId, Func> authorizedAction)
+ {
+ var readAccessLevel = _authorizationContext.GetOrganizationReadAccessLevel(organizationId);
+
+ return readAccessLevel < OrganizationDataReadAccessLevel.All
+ ? new OperationError(OperationFailure.Forbidden)
+ : authorizedAction();
+ }
+
private IQueryable SearchByName(int organizationId, string name)
{
return _repository.GetContractsInOrganization(organizationId).ByNameExact(name);
diff --git a/Core.ApplicationServices/Contract/Write/ItContractWriteService.cs b/Core.ApplicationServices/Contract/Write/ItContractWriteService.cs
index 2a99fb28a9..0589b8c39d 100644
--- a/Core.ApplicationServices/Contract/Write/ItContractWriteService.cs
+++ b/Core.ApplicationServices/Contract/Write/ItContractWriteService.cs
@@ -19,6 +19,7 @@
using Core.DomainModel.ItContract;
using Core.DomainModel.Organization;
using Core.DomainModel.References;
+using Core.DomainModel.Shared;
using Core.DomainServices;
using Core.DomainServices.Generic;
using Core.DomainServices.Role;
@@ -37,13 +38,11 @@ public class ItContractWriteService : IItContractWriteService
private readonly IGenericRepository _itContractAgreementElementTypesRepository;
private readonly IAuthorizationContext _authorizationContext;
private readonly IOrganizationService _organizationService;
- private readonly IGenericRepository _handoverTrialRepository;
private readonly IReferenceService _referenceService;
private readonly IAssignmentUpdateService _assignmentUpdateService;
private readonly IItSystemUsageService _usageService;
private readonly IRoleAssignmentService _roleAssignmentService;
private readonly IDataProcessingRegistrationApplicationService _dataProcessingRegistrationApplicationService;
- private readonly IGenericRepository _paymentMilestoneRepository;
private readonly IGenericRepository _economyStreamRepository;
public ItContractWriteService(
@@ -56,13 +55,11 @@ public ItContractWriteService(
IGenericRepository itContractAgreementElementTypesRepository,
IAuthorizationContext authorizationContext,
IOrganizationService organizationService,
- IGenericRepository handoverTrialRepository,
IReferenceService referenceService,
IAssignmentUpdateService assignmentUpdateService,
IItSystemUsageService usageService,
IRoleAssignmentService roleAssignmentService,
IDataProcessingRegistrationApplicationService dataProcessingRegistrationApplicationService,
- IGenericRepository paymentMilestoneRepository,
IGenericRepository economyStreamRepository)
{
_contractService = contractService;
@@ -74,13 +71,11 @@ public ItContractWriteService(
_itContractAgreementElementTypesRepository = itContractAgreementElementTypesRepository;
_authorizationContext = authorizationContext;
_organizationService = organizationService;
- _handoverTrialRepository = handoverTrialRepository;
_referenceService = referenceService;
_assignmentUpdateService = assignmentUpdateService;
_usageService = usageService;
_roleAssignmentService = roleAssignmentService;
_dataProcessingRegistrationApplicationService = dataProcessingRegistrationApplicationService;
- _paymentMilestoneRepository = paymentMilestoneRepository;
_economyStreamRepository = economyStreamRepository;
}
@@ -158,7 +153,6 @@ private Result ApplyUpdates(ItContract contract, ItC
.Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Supplier, UpdateSupplierData))
.Bind(updateContract => updateContract.WithOptionalUpdate(parameters.DataProcessingRegistrationUuids, UpdateDataProcessingRegistrations))
.Bind(updateContract => updateContract.WithOptionalUpdate(parameters.SystemUsageUuids, UpdateSystemAssignments))
- .Bind(updateContract => updateContract.WithOptionalUpdate(parameters.HandoverTrials, UpdateHandOverTrials))
.Bind(updateContract => updateContract.WithOptionalUpdate(parameters.PaymentModel, UpdatePaymentModelParameters))
.Bind(updateContract => updateContract.WithOptionalUpdate(parameters.ExternalReferences, UpdateExternalReferences))
.Bind(updateContract => updateContract.WithOptionalUpdate(parameters.Roles, UpdateRoles))
@@ -286,37 +280,6 @@ private Maybe UpdateExternalReferences(ItContract contract, IEnu
.Select(error => new OperationError($"Failed to update references with error message: {error.Message.GetValueOrEmptyString()}", error.FailureType));
}
- private Maybe UpdateHandOverTrials(ItContract contract, IEnumerable parameters)
- {
- var handoverTrialTypes = new Dictionary();
- var updates = parameters.ToList();
- foreach (var uuid in updates.Select(x => x.HandoverTrialTypeUuid).Distinct().ToList())
- {
- var optionType = _optionResolver.GetOptionType(contract.Organization.Uuid, uuid);
- if (optionType.Failed)
- return new OperationError($"Failed to fetch option with uuid:{uuid}. Message:{optionType.Error.Message.GetValueOrEmptyString()}", optionType.Error.FailureType);
-
- if (!optionType.Value.available && contract.HandoverTrials.Any(x => x.HandoverTrialType.Uuid == uuid) == false)
- return new OperationError($"Cannot take new handover trial ({uuid}) into use which is not available in the organization", OperationFailure.BadInput);
-
- handoverTrialTypes[uuid] = optionType.Value.option;
- }
-
- //Replace existing trials (duplicates are allowed so we cannot derive any meaningful unique identity)
- var handoverTrials = contract.HandoverTrials.ToList();
- handoverTrials.ForEach(_handoverTrialRepository.Delete);
- contract.ResetHandoverTrials();
-
- foreach (var newHandoverTrial in updates)
- {
- var error = contract.AddHandoverTrial(handoverTrialTypes[newHandoverTrial.HandoverTrialTypeUuid], newHandoverTrial.ExpectedAt, newHandoverTrial.ApprovedAt);
- if (error.HasValue)
- return new OperationError("Failed adding handover trial:" + error.Value.Message.GetValueOrEmptyString(), error.Value.FailureType);
- }
-
- return Maybe.None;
- }
-
private Result UpdateSupplierData(ItContract contract, ItContractSupplierModificationParameters parameters)
{
return contract
@@ -385,28 +348,7 @@ private Result UpdatePaymentModelParameters(ItContra
.WithOptionalUpdate(parameters.OperationsRemunerationStartedAt, (c, newValue) => c.OperationRemunerationBegun = newValue.Match(val => val, () => (DateTime?)null))
.Bind(itContract => itContract.WithOptionalUpdate(parameters.PaymentFrequencyUuid, UpdatePaymentFrequency))
.Bind(itContract => itContract.WithOptionalUpdate(parameters.PaymentModelUuid, UpdatePaymentModel))
- .Bind(itContract => itContract.WithOptionalUpdate(parameters.PriceRegulationUuid, UpdatePriceRegulation))
- .Bind(itContract => itContract.WithOptionalUpdate(parameters.PaymentMileStones, UpdatePaymentMileStones));
- }
-
- private Maybe UpdatePaymentMileStones(ItContract contract, Maybe> milestones)
- {
- //Replace existing milestones (duplicates are allowed so we cannot derive any meaningful unique identity)
- var paymentMilestones = contract.PaymentMilestones.ToList();
- contract.ResetPaymentMilestones();
- paymentMilestones.ForEach(_paymentMilestoneRepository.Delete);
-
- if (milestones.IsNone)
- return Maybe.None;
-
- foreach (var newMilestone in milestones.Value)
- {
- var error = contract.AddPaymentMilestone(newMilestone.Title, newMilestone.Expected, newMilestone.Approved);
- if (error.HasValue)
- return new OperationError($"Failed adding payment milestone: {error.Value.Message.GetValueOrEmptyString()}", error.Value.FailureType);
- }
-
- return Maybe.None;
+ .Bind(itContract => itContract.WithOptionalUpdate(parameters.PriceRegulationUuid, UpdatePriceRegulation));
}
private Maybe UpdatePriceRegulation(ItContract contract, Guid? priceRegulationUuid)
@@ -468,7 +410,8 @@ private Result UpdateGeneralData(ItContract contract
.Bind(itContract => itContract.WithOptionalUpdate(generalData.Notes, (c, newValue) => c.Note = newValue))
.Bind(itContract => itContract.WithOptionalUpdate(generalData.EnforceValid, (c, newValue) => c.Active = newValue.GetValueOrFallback(false)))
.Bind(itContract => UpdateValidityPeriod(itContract, generalData).Match>(error => error, () => itContract))
- .Bind(itContract => itContract.WithOptionalUpdate(generalData.AgreementElementUuids, UpdateAgreementElements));
+ .Bind(itContract => itContract.WithOptionalUpdate(generalData.AgreementElementUuids, UpdateAgreementElements))
+ .Bind(itContract => itContract.WithOptionalUpdate(generalData.CriticalityUuid, UpdateContractCriticality));
}
private Maybe UpdateAgreementElements(ItContract contract, IEnumerable agreementElements)
@@ -540,8 +483,12 @@ private Result UpdateProcurement(ItContract contract
{
return contract
.WithOptionalUpdate(procurementParameters.ProcurementStrategyUuid, UpdateProcurementStrategy)
- .Bind(itContract => itContract.WithOptionalUpdate(procurementParameters.PurchaseTypeUuid, UpdatePurchaseType))
- .Bind(itContract => itContract.WithOptionalUpdate(procurementParameters.ProcurementPlan, UpdateProcurementPlan));
+ .Bind(itContract =>
+ itContract.WithOptionalUpdate(procurementParameters.PurchaseTypeUuid, UpdatePurchaseType))
+ .Bind(itContract =>
+ itContract.WithOptionalUpdate(procurementParameters.ProcurementPlan, UpdateProcurementPlan))
+ .Bind(itContract => itContract.WithOptionalUpdate(procurementParameters.ProcurementInitiated,
+ (c, newValue) => c.ProcurementInitiated = newValue.GetValueOrFallback(YesNoUndecidedOption.Undecided)));
}
private static Maybe UpdateProcurementPlan(ItContract contract, Maybe<(byte half, int year)> plan)
@@ -611,6 +558,17 @@ private Maybe UpdateName(ItContract contract, string newName)
contract.Name = newName;
return Maybe.None;
}
+ private Maybe UpdateContractCriticality(ItContract contract, Guid? criticalityUuid)
+ {
+ return _assignmentUpdateService.UpdateIndependentOptionTypeAssignment
+ (
+ contract,
+ criticalityUuid,
+ c => c.ResetCriticality(),
+ c => c.Criticality,
+ (c, newValue) => c.Criticality = newValue
+ );
+ }
public Maybe Delete(Guid itContractUuid)
{
diff --git a/Core.ApplicationServices/Core.ApplicationServices.csproj b/Core.ApplicationServices/Core.ApplicationServices.csproj
index 04bf99f728..5a86bf2e62 100644
--- a/Core.ApplicationServices/Core.ApplicationServices.csproj
+++ b/Core.ApplicationServices/Core.ApplicationServices.csproj
@@ -46,8 +46,8 @@
..\packages\Microsoft.Owin.4.1.0\lib\net45\Microsoft.Owin.dll
-
- ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+
+ ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
..\packages\Owin.1.0\lib\net40\Owin.dll
@@ -83,6 +83,7 @@
+
@@ -120,15 +121,15 @@
+
+
-
-
@@ -162,6 +163,8 @@
+
+
@@ -174,6 +177,8 @@
+
+
@@ -186,7 +191,7 @@
-
+
@@ -264,6 +269,7 @@
+
diff --git a/Core.ApplicationServices/Helpers/NamedEntityMappingHelper.cs b/Core.ApplicationServices/Helpers/NamedEntityMappingHelper.cs
new file mode 100644
index 0000000000..e4489e19a2
--- /dev/null
+++ b/Core.ApplicationServices/Helpers/NamedEntityMappingHelper.cs
@@ -0,0 +1,13 @@
+using Core.ApplicationServices.Model.Shared;
+using Core.DomainModel;
+
+namespace Core.ApplicationServices.Helpers
+{
+ public static class NamedEntityMappingHelper
+ {
+ public static NamedEntity ToNamedEntity(this T entity) where T : IHasId, IHasName
+ {
+ return new NamedEntity(entity.Id, entity.Name);
+ }
+ }
+}
diff --git a/Core.ApplicationServices/IUserService.cs b/Core.ApplicationServices/IUserService.cs
index d4e0e0460d..f95a6e648b 100644
--- a/Core.ApplicationServices/IUserService.cs
+++ b/Core.ApplicationServices/IUserService.cs
@@ -18,5 +18,7 @@ public interface IUserService : IDisposable
Result, OperationError> GetUsersWithRoleAssignedInAnyOrganization(OrganizationRole role);
Result, OperationError> GetUsersInOrganization(Guid organizationUuid, params IDomainQuery[] queries);
Result GetUserInOrganization(Guid organizationUuid, Guid userUuid);
+ Maybe DeleteUserFromKitos(Guid userUuid);
+ Result, OperationError> SearchAllKitosUsers(params IDomainQuery[] queries);
}
}
\ No newline at end of file
diff --git a/Core.ApplicationServices/Model/Contracts/ContractOptions.cs b/Core.ApplicationServices/Model/Contracts/ContractOptions.cs
new file mode 100644
index 0000000000..548757aa82
--- /dev/null
+++ b/Core.ApplicationServices/Model/Contracts/ContractOptions.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using System.Linq;
+using Core.DomainModel.ItContract;
+using Core.DomainServices.Model.Options;
+
+namespace Core.ApplicationServices.Model.Contracts
+{
+ public class ContractOptions
+ {
+ public IReadOnlyList<(OptionDescriptor option, bool available)> CriticalityOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> ContractTypeOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> ContractTemplateOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> PurchaseFormOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> ProcurementStrategyOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> PaymentModelOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> PaymentFrequencyOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> OptionExtendOptions { get; }
+ public IReadOnlyList<(OptionDescriptor option, bool available)> TerminationDeadlineOptions { get; }
+
+ public ContractOptions(
+ IEnumerable<(OptionDescriptor option, bool available)> criticalityOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> contractTypeOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> contractTemplateOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> purchaseFormOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> procurementStrategyOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> paymentModelOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> paymentFrequencyOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> optionExtendOptions,
+ IEnumerable<(OptionDescriptor option, bool available)> terminationDeadlineOptions)
+ {
+ CriticalityOptions = criticalityOptions.ToList();
+ ContractTypeOptions = contractTypeOptions.ToList();
+ ContractTemplateOptions = contractTemplateOptions.ToList();
+ PurchaseFormOptions = purchaseFormOptions.ToList();
+ ProcurementStrategyOptions = procurementStrategyOptions.ToList();
+ PaymentModelOptions = paymentModelOptions.ToList();
+ PaymentFrequencyOptions = paymentFrequencyOptions.ToList();
+ OptionExtendOptions = optionExtendOptions.ToList();
+ TerminationDeadlineOptions = terminationDeadlineOptions.ToList();
+ }
+ }
+}
diff --git a/Core.ApplicationServices/Model/Contracts/Write/ItContractGeneralDataModificationParameters.cs b/Core.ApplicationServices/Model/Contracts/Write/ItContractGeneralDataModificationParameters.cs
index b36761973c..1e3d1f0723 100644
--- a/Core.ApplicationServices/Model/Contracts/Write/ItContractGeneralDataModificationParameters.cs
+++ b/Core.ApplicationServices/Model/Contracts/Write/ItContractGeneralDataModificationParameters.cs
@@ -15,5 +15,6 @@ public class ItContractGeneralDataModificationParameters
public OptionalValueChange> EnforceValid { get; set; } = OptionalValueChange>.None;
public OptionalValueChange> ValidFrom { get; set; } = OptionalValueChange>.None;
public OptionalValueChange> ValidTo { get; set; } = OptionalValueChange>.None;
+ public OptionalValueChange CriticalityUuid { get; set; } = OptionalValueChange.None;
}
}
diff --git a/Core.ApplicationServices/Model/Contracts/Write/ItContractHandoverTrialUpdate.cs b/Core.ApplicationServices/Model/Contracts/Write/ItContractHandoverTrialUpdate.cs
deleted file mode 100644
index 1ad8f6eba7..0000000000
--- a/Core.ApplicationServices/Model/Contracts/Write/ItContractHandoverTrialUpdate.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Core.ApplicationServices.Model.Contracts.Write
-{
- public class ItContractHandoverTrialUpdate
- {
- public Guid HandoverTrialTypeUuid { get; set; }
- public DateTime? ExpectedAt { get; set; }
- public DateTime? ApprovedAt { get; set; }
- }
-}
diff --git a/Core.ApplicationServices/Model/Contracts/Write/ItContractModificationParameters.cs b/Core.ApplicationServices/Model/Contracts/Write/ItContractModificationParameters.cs
index 2ac92ea81d..8b11807825 100644
--- a/Core.ApplicationServices/Model/Contracts/Write/ItContractModificationParameters.cs
+++ b/Core.ApplicationServices/Model/Contracts/Write/ItContractModificationParameters.cs
@@ -14,7 +14,6 @@ public class ItContractModificationParameters
public Maybe Procurement { get; set; } = Maybe.None;
public Maybe Responsible { get; set; } = Maybe.None;
public Maybe Supplier { get; set; } = Maybe.None;
- public Maybe> HandoverTrials { get; set; } = Maybe>.None;
public Maybe> ExternalReferences { get; set; } = Maybe>.None;
public Maybe> SystemUsageUuids { get; set; } = Maybe>.None;
public Maybe> Roles { get; set; } = Maybe>.None;
diff --git a/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentMilestone.cs b/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentMilestone.cs
deleted file mode 100644
index 733fbc731f..0000000000
--- a/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentMilestone.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Core.ApplicationServices.Model.Contracts.Write
-{
- public class ItContractPaymentMilestone
- {
- public string Title { get; set; }
- public DateTime? Expected { get; set; }
- public DateTime? Approved { get; set; }
- }
-}
\ No newline at end of file
diff --git a/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentModelModificationParameters.cs b/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentModelModificationParameters.cs
index 35ca28ebe3..bdca07d493 100644
--- a/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentModelModificationParameters.cs
+++ b/Core.ApplicationServices/Model/Contracts/Write/ItContractPaymentModelModificationParameters.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using Core.Abstractions.Types;
using Core.ApplicationServices.Model.Shared;
@@ -11,6 +10,5 @@ public class ItContractPaymentModelModificationParameters
public OptionalValueChange PaymentFrequencyUuid { get; set; } = OptionalValueChange.None;
public OptionalValueChange PaymentModelUuid { get; set; } = OptionalValueChange.None;
public OptionalValueChange PriceRegulationUuid { get; set; } = OptionalValueChange.None;
- public OptionalValueChange>> PaymentMileStones { get; set; } = OptionalValueChange>>.None;
}
}
\ No newline at end of file
diff --git a/Core.ApplicationServices/Model/Contracts/Write/ItContractProcurementModificationParameters.cs b/Core.ApplicationServices/Model/Contracts/Write/ItContractProcurementModificationParameters.cs
index d6057cb2e8..7a1bcd53e2 100644
--- a/Core.ApplicationServices/Model/Contracts/Write/ItContractProcurementModificationParameters.cs
+++ b/Core.ApplicationServices/Model/Contracts/Write/ItContractProcurementModificationParameters.cs
@@ -1,6 +1,7 @@
using System;
using Core.Abstractions.Types;
using Core.ApplicationServices.Model.Shared;
+using Core.DomainModel.Shared;
namespace Core.ApplicationServices.Model.Contracts.Write
{
@@ -8,6 +9,7 @@ public class ItContractProcurementModificationParameters
{
public OptionalValueChange PurchaseTypeUuid { get; set; } = OptionalValueChange.None;
public OptionalValueChange ProcurementStrategyUuid { get; set; } = OptionalValueChange.None;
- public OptionalValueChange> ProcurementPlan { get; set; } = OptionalValueChange>.None;
+ public OptionalValueChange> ProcurementPlan { get; set; } = OptionalValueChange>.None;
+ public OptionalValueChange> ProcurementInitiated { get; set; } = OptionalValueChange>.None;
}
}
\ No newline at end of file
diff --git a/Core.ApplicationServices/Model/EventHandler/ClearCacheOnAccessRightsChangedHandler.cs b/Core.ApplicationServices/Model/EventHandler/ClearCacheOnAdministrativeAccessRightsChangedHandler.cs
similarity index 61%
rename from Core.ApplicationServices/Model/EventHandler/ClearCacheOnAccessRightsChangedHandler.cs
rename to Core.ApplicationServices/Model/EventHandler/ClearCacheOnAdministrativeAccessRightsChangedHandler.cs
index c04dc5cd27..3b3b6a288d 100644
--- a/Core.ApplicationServices/Model/EventHandler/ClearCacheOnAccessRightsChangedHandler.cs
+++ b/Core.ApplicationServices/Model/EventHandler/ClearCacheOnAdministrativeAccessRightsChangedHandler.cs
@@ -5,16 +5,16 @@
namespace Core.ApplicationServices.Model.EventHandler
{
- public class ClearCacheOnAccessRightsChangedHandler : IDomainEventHandler
+ public class ClearCacheOnAdministrativeAccessRightsChangedHandler : IDomainEventHandler
{
private readonly IObjectCache _objectCache;
- public ClearCacheOnAccessRightsChangedHandler(IObjectCache objectCache)
+ public ClearCacheOnAdministrativeAccessRightsChangedHandler(IObjectCache objectCache)
{
_objectCache = objectCache;
}
- public void Handle(AccessRightsChanged domainEvent)
+ public void Handle(AdministrativeAccessRightsChanged domainEvent)
{
_objectCache.Clear(OrganizationalUserContextCacheKeyFactory.Create(domainEvent.UserId));
}
diff --git a/Core.ApplicationServices/Model/Organizations/OrganizationRemovalConflicts.cs b/Core.ApplicationServices/Model/Organizations/OrganizationRemovalConflicts.cs
index 2afe0ecd69..068d0baf00 100644
--- a/Core.ApplicationServices/Model/Organizations/OrganizationRemovalConflicts.cs
+++ b/Core.ApplicationServices/Model/Organizations/OrganizationRemovalConflicts.cs
@@ -3,6 +3,7 @@
using Core.DomainModel.GDPR;
using Core.DomainModel.ItContract;
using Core.DomainModel.ItSystem;
+using Core.DomainModel.ItSystemUsage;
namespace Core.ApplicationServices.Model.Organizations
{
@@ -16,6 +17,7 @@ public class OrganizationRemovalConflicts
public IReadOnlyList DprInOtherOrganizationsWhereOrgIsSubDataProcessor { get; }
public IReadOnlyList ContractsInOtherOrganizationsWhereOrgIsSupplier { get; }
public IReadOnlyList SystemsInOtherOrganizationsWhereOrgIsRightsHolder { get; }
+ public IReadOnlyList SystemUsagesWhereOrgIsArchiveSupplier { get; }
public OrganizationRemovalConflicts(
IReadOnlyList systemsWithUsagesOutsideTheOrganization,
@@ -25,7 +27,8 @@ public OrganizationRemovalConflicts(
IReadOnlyList dprInOtherOrganizationsWhereOrgIsDataProcessor,
IReadOnlyList dprInOtherOrganizationsWhereOrgIsSubDataProcessor,
IReadOnlyList contractsInOtherOrganizationsWhereOrgIsSupplier,
- IReadOnlyList systemsInOtherOrganizationsWhereOrgIsRightsHolder)
+ IReadOnlyList systemsInOtherOrganizationsWhereOrgIsRightsHolder,
+ IReadOnlyList systemUsagesWhereOrgIsArchiveSupplier)
{
SystemsWithUsagesOutsideTheOrganization = systemsWithUsagesOutsideTheOrganization;
InterfacesExposedOnSystemsOutsideTheOrganization = interfacesExposedOnSystemsOutsideTheOrganization;
@@ -35,6 +38,7 @@ public OrganizationRemovalConflicts(
DprInOtherOrganizationsWhereOrgIsSubDataProcessor = dprInOtherOrganizationsWhereOrgIsSubDataProcessor;
ContractsInOtherOrganizationsWhereOrgIsSupplier = contractsInOtherOrganizationsWhereOrgIsSupplier;
SystemsInOtherOrganizationsWhereOrgIsRightsHolder = systemsInOtherOrganizationsWhereOrgIsRightsHolder;
+ SystemUsagesWhereOrgIsArchiveSupplier = systemUsagesWhereOrgIsArchiveSupplier;
}
@@ -45,6 +49,7 @@ public OrganizationRemovalConflicts(
DprInOtherOrganizationsWhereOrgIsDataProcessor.Any() ||
DprInOtherOrganizationsWhereOrgIsSubDataProcessor.Any() ||
ContractsInOtherOrganizationsWhereOrgIsSupplier.Any() ||
- SystemsInOtherOrganizationsWhereOrgIsRightsHolder.Any();
+ SystemsInOtherOrganizationsWhereOrgIsRightsHolder.Any() ||
+ SystemUsagesWhereOrgIsArchiveSupplier.Any();
}
}
diff --git a/Core.ApplicationServices/Model/Users/UserRightsAssignments.cs b/Core.ApplicationServices/Model/Users/UserRightsAssignments.cs
new file mode 100644
index 0000000000..ad15b917dc
--- /dev/null
+++ b/Core.ApplicationServices/Model/Users/UserRightsAssignments.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+using System.Linq;
+using Core.DomainModel.GDPR;
+using Core.DomainModel.ItContract;
+using Core.DomainModel.ItProject;
+using Core.DomainModel.ItSystem;
+using Core.DomainModel.Organization;
+
+namespace Core.ApplicationServices.Model.Users
+{
+ public class UserRightsAssignments
+ {
+ public IEnumerable LocalAdministrativeAccessRoles { get; }
+ public IEnumerable DataProcessingRegistrationRights { get; }
+ public IEnumerable SystemRights { get; }
+ public IEnumerable ContractRights { get; }
+ public IEnumerable ProjectRights { get; }
+ public IEnumerable OrganizationUnitRights { get; }
+
+ public UserRightsAssignments(
+ IEnumerable organizationRoles,
+ IEnumerable dataProcessingRegistrationRoles,
+ IEnumerable systemRights,
+ IEnumerable contractRights,
+ IEnumerable projectRights,
+ IEnumerable organizationUnitRights)
+ {
+ LocalAdministrativeAccessRoles = organizationRoles.ToList();
+ DataProcessingRegistrationRights = dataProcessingRegistrationRoles.ToList();
+ SystemRights = systemRights.ToList();
+ ContractRights = contractRights.ToList();
+ ProjectRights = projectRights.ToList();
+ OrganizationUnitRights = organizationUnitRights.ToList();
+ }
+ }
+}
diff --git a/Core.ApplicationServices/Model/Users/UserRightsChangeParameters.cs b/Core.ApplicationServices/Model/Users/UserRightsChangeParameters.cs
new file mode 100644
index 0000000000..b9b5e58339
--- /dev/null
+++ b/Core.ApplicationServices/Model/Users/UserRightsChangeParameters.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using System.Linq;
+using Core.DomainModel.Organization;
+
+namespace Core.ApplicationServices.Model.Users
+{
+ public class UserRightsChangeParameters
+ {
+ public ISet AdministrativeAccessRoles { get; }
+ public ISet DataProcessingRegistrationRightIds { get; }
+ public ISet SystemRightIds { get; }
+ public ISet ContractRightIds { get; }
+ public ISet ProjectRightIds { get; }
+ public ISet OrganizationUnitRightsIds { get; }
+
+ public UserRightsChangeParameters(
+ IEnumerable organizationRoles,
+ IEnumerable dataProcessingRegistrationRightIds,
+ IEnumerable systemRightIds,
+ IEnumerable contractRightIds,
+ IEnumerable projectRightIds,
+ IEnumerable organizationUnitRightIds)
+ {
+ AdministrativeAccessRoles = organizationRoles.ToHashSet();
+ DataProcessingRegistrationRightIds = dataProcessingRegistrationRightIds.ToHashSet();
+ SystemRightIds = systemRightIds.ToHashSet();
+ ContractRightIds = contractRightIds.ToHashSet();
+ ProjectRightIds = projectRightIds.ToHashSet();
+ OrganizationUnitRightsIds = organizationUnitRightIds.ToHashSet();
+ }
+ }
+}
diff --git a/Core.ApplicationServices/OrganizationRoleService.cs b/Core.ApplicationServices/OrganizationRoleService.cs
index 1c2679538c..b71bfaddc1 100644
--- a/Core.ApplicationServices/OrganizationRoleService.cs
+++ b/Core.ApplicationServices/OrganizationRoleService.cs
@@ -29,8 +29,9 @@ private OrganizationRight AddOrganizationRoleToUser(User user, Organization orga
User = user,
Role = organizationRole,
});
- _domainEvents.Raise(new AccessRightsChanged(user.Id));
+
_organizationRights.Save();
+ _domainEvents.Raise(new AdministrativeAccessRightsChanged(user.Id));
return result;
}
@@ -40,11 +41,6 @@ public OrganizationRight MakeUser(User user, Organization organization)
return AddOrganizationRoleToUser(user, organization, OrganizationRole.User);
}
- public OrganizationRight MakeLocalAdmin(User user, Organization organization)
- {
- return AddOrganizationRoleToUser(user, organization, OrganizationRole.LocalAdmin);
- }
-
public IReadOnlyDictionary> GetOrganizationRoles(User user)
{
var rolesByRights = user.OrganizationRights
diff --git a/Core.ApplicationServices/Organizations/Handlers/HandleOrganizationBeingDeleted.cs b/Core.ApplicationServices/Organizations/Handlers/HandleOrganizationBeingDeleted.cs
index 08df6d9912..cbf666a148 100644
--- a/Core.ApplicationServices/Organizations/Handlers/HandleOrganizationBeingDeleted.cs
+++ b/Core.ApplicationServices/Organizations/Handlers/HandleOrganizationBeingDeleted.cs
@@ -3,13 +3,16 @@
using System.Linq;
using Core.Abstractions.Exceptions;
using Core.Abstractions.Extensions;
+using Core.Abstractions.Types;
using Core.ApplicationServices.Contract.Write;
+using Core.ApplicationServices.Extensions;
using Core.ApplicationServices.GDPR;
using Core.ApplicationServices.Interface;
using Core.ApplicationServices.Model.Contracts.Write;
using Core.ApplicationServices.Model.Organizations;
using Core.ApplicationServices.Model.Shared;
using Core.ApplicationServices.Model.System;
+using Core.ApplicationServices.Model.SystemUsage.Write;
using Core.ApplicationServices.Project;
using Core.ApplicationServices.System;
using Core.ApplicationServices.SystemUsage.Write;
@@ -70,6 +73,8 @@ public void Handle(EntityBeingDeletedEvent domainEvent)
ResolveRightsHolderConflicts(conflicts, organization);
+ ResolveArchiveSupplierConflicts(conflicts, organization);
+
ClearLocalRegistrations(organization);
var systemsToBeMovedToDefaultOrganization = ResolveGlobalItSystemConflicts(conflicts, defaultOrganization);
@@ -204,5 +209,19 @@ private void ResolveContractConflicts(OrganizationRemovalConflicts conflicts, Or
}).ThrowOnFailure());
organization.Supplier.Clear();
}
+
+ private void ResolveArchiveSupplierConflicts(OrganizationRemovalConflicts conflicts, Organization organization)
+ {
+ //Clearing organization on systems where it is set as supplier
+ var organizationSupplier = conflicts.SystemUsagesWhereOrgIsArchiveSupplier.ToList();
+ organizationSupplier.ForEach(x => _itSystemUsageService.Update(x.Uuid,
+ new SystemUsageUpdateParameters
+ {
+ Archiving = new UpdatedSystemUsageArchivingParameters
+ {
+ ArchiveSupplierOrganizationUuid = Maybe.None.AsChangedValue()
+ }
+ }).ThrowOnFailure());
+ }
}
}
diff --git a/Core.ApplicationServices/Organizations/IOrganizationService.cs b/Core.ApplicationServices/Organizations/IOrganizationService.cs
index 112fb34caf..65dc90f8aa 100644
--- a/Core.ApplicationServices/Organizations/IOrganizationService.cs
+++ b/Core.ApplicationServices/Organizations/IOrganizationService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using Core.Abstractions.Types;
using Core.ApplicationServices.Model.Organizations;
@@ -42,5 +43,7 @@ public interface IOrganizationService
/// If set to true any removal conflicts will be ignored and the deletion will proceed
///
Maybe RemoveOrganization(Guid organizationUuid, bool enforceDeletion);
+
+ Result, OperationError> GetUserOrganizations(int userId);
}
}
diff --git a/Core.ApplicationServices/Organizations/IStsOrganizationSynchronizationService.cs b/Core.ApplicationServices/Organizations/IStsOrganizationSynchronizationService.cs
new file mode 100644
index 0000000000..6733e2ebad
--- /dev/null
+++ b/Core.ApplicationServices/Organizations/IStsOrganizationSynchronizationService.cs
@@ -0,0 +1,17 @@
+using System;
+using Core.Abstractions.Types;
+using Core.DomainServices.Model.StsOrganization;
+
+namespace Core.ApplicationServices.Organizations
+{
+ public interface IStsOrganizationSynchronizationService
+ {
+ ///
+ /// Retrieves a view of the organization as it exists in STS Organization
+ ///
+ ///
+ ///
+ ///
+ Result GetStsOrganizationalHierarchy(Guid organizationId, Maybe levelsToInclude);
+ }
+}
diff --git a/Core.ApplicationServices/Organizations/OrganizationRightsService.cs b/Core.ApplicationServices/Organizations/OrganizationRightsService.cs
index 6de584d62f..2295f9561d 100644
--- a/Core.ApplicationServices/Organizations/OrganizationRightsService.cs
+++ b/Core.ApplicationServices/Organizations/OrganizationRightsService.cs
@@ -6,6 +6,7 @@
using Core.DomainModel.Organization.DomainEvents;
using Core.DomainServices;
using Core.DomainServices.Extensions;
+using Serilog;
namespace Core.ApplicationServices.Organizations
{
@@ -15,17 +16,18 @@ public class OrganizationRightsService : IOrganizationRightsService
private readonly IGenericRepository _organizationRightRepository;
private readonly IOrganizationalUserContext _userContext;
private readonly IDomainEvents _domainEvents;
+ private readonly ILogger _logger;
- public OrganizationRightsService(
- IAuthorizationContext authorizationContext,
+ public OrganizationRightsService(IAuthorizationContext authorizationContext,
IGenericRepository organizationRightRepository,
IOrganizationalUserContext userContext,
- IDomainEvents domainEvents)
+ IDomainEvents domainEvents, ILogger logger)
{
_authorizationContext = authorizationContext;
_organizationRightRepository = organizationRightRepository;
_userContext = userContext;
_domainEvents = domainEvents;
+ _logger = logger;
}
public Result AssignRole(int organizationId, int userId, OrganizationRole roleId)
@@ -42,9 +44,16 @@ public Result AssignRole(int organizationId
return OperationFailure.Forbidden;
}
+ var existingRight = _organizationRightRepository.AsQueryable().FirstOrDefault(x => x.OrganizationId == organizationId && x.UserId == userId && x.Role == roleId);
+ if (existingRight != null)
+ {
+ _logger.Warning("Attempt to assign existing organization ({orgId}) role ({roleId}) to user ({userId}). Existing right ({rightId}) returned", organizationId, roleId, userId, existingRight.Id);
+ return right;
+ }
+
right = _organizationRightRepository.Insert(right);
- _domainEvents.Raise(new AccessRightsChanged(userId));
_organizationRightRepository.Save();
+ _domainEvents.Raise(new AdministrativeAccessRightsChanged(userId));
return right;
}
@@ -85,8 +94,8 @@ private Result RemoveRight(OrganizationRigh
}
_organizationRightRepository.DeleteByKey(right.Id);
- _domainEvents.Raise(new AccessRightsChanged(right.UserId));
_organizationRightRepository.Save();
+ _domainEvents.Raise(new AdministrativeAccessRightsChanged(right.UserId));
return right;
}
diff --git a/Core.ApplicationServices/Organizations/OrganizationService.cs b/Core.ApplicationServices/Organizations/OrganizationService.cs
index c92344d4f1..d4bde8abad 100644
--- a/Core.ApplicationServices/Organizations/OrganizationService.cs
+++ b/Core.ApplicationServices/Organizations/OrganizationService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using Core.Abstractions.Extensions;
using Core.Abstractions.Types;
@@ -25,6 +26,7 @@ public class OrganizationService : IOrganizationService
private readonly IGenericRepository _orgRepository;
private readonly IOrganizationRepository _repository;
private readonly IOrgUnitService _orgUnitService;
+ private readonly IOrganizationRightsService _organizationRightsService;
private readonly IDomainEvents _domainEvents;
private readonly IGenericRepository _orgRightRepository;
private readonly IGenericRepository _userRepository;
@@ -42,6 +44,7 @@ public OrganizationService(
ILogger logger,
ITransactionManager transactionManager,
IOrganizationRepository repository,
+ IOrganizationRightsService organizationRightsService,
IOrgUnitService orgUnitService,
IDomainEvents domainEvents)
{
@@ -55,6 +58,7 @@ public OrganizationService(
_repository = repository;
_orgUnitService = orgUnitService;
_domainEvents = domainEvents;
+ _organizationRightsService = organizationRightsService;
}
//returns the default org unit for that user inside that organization
@@ -83,6 +87,7 @@ public void SetDefaultOrgUnit(User user, int orgId, int orgUnitId)
/// The user to be removed.
public Result RemoveUser(int organizationId, int userId)
{
+ using var transaction = _transactionManager.Begin();
var organization = _orgRepository.GetByKey(organizationId);
if (organization == null)
{
@@ -101,9 +106,15 @@ public Result RemoveUser(int organizationId, int
foreach (var right in rights)
{
- _orgRightRepository.DeleteByKey(right.Id);
+ var result = _organizationRightsService.RemoveRole(right.Id);
+ if (result.Failed)
+ {
+ _logger.Error("Failed to delete right with id {rightId} due to error: {errorCode}", right.Id, result.Error);
+ transaction.Rollback();
+ return Result.Failure(OperationFailure.UnknownError);
+ }
}
- _orgRightRepository.Save();
+ transaction.Commit();
return organization;
}
@@ -277,7 +288,11 @@ public Result ComputeOrganizationR
.BelongingSystems
.Where(x => x.OrganizationId != organizationWhichCanBeDeleted.Id)
.ToList();
-
+ var systemsWhereOrgIsArchiveSupplier = organizationWhichCanBeDeleted
+ .ArchiveSupplierForItSystems
+ .Where(x => x.OrganizationId != organizationWhichCanBeDeleted.Id)
+ .ToList();
+
return new OrganizationRemovalConflicts(
systemsWithUsagesOutsideTheOrganization,
interfacesExposedOnSystemsOutsideTheOrganization,
@@ -286,7 +301,8 @@ public Result ComputeOrganizationR
dprInOtherOrganizationsWhereOrgIsDataProcessor,
dprInOtherOrganizationsWhereOrgIsSubDataProcessor,
contractsInOtherOrganizationsWhereOrgIsSupplier,
- systemsInOtherOrgsWhereOrgIsRightsHolder);
+ systemsInOtherOrgsWhereOrgIsRightsHolder,
+ systemsWhereOrgIsArchiveSupplier);
});
}
@@ -329,6 +345,17 @@ public Maybe RemoveOrganization(Guid uuid, bool enforceDeletion)
return Maybe.None;
}
+ public Result, OperationError> GetUserOrganizations(int userId)
+ {
+ var user = _userRepository.GetByKey(userId);
+ if(user == null)
+ return Result, OperationError>.Failure(new OperationError($"User with id: {userId} was not found", OperationFailure.NotFound));
+
+ var userOrganizationsIds = user.GetOrganizationIds();
+
+ return Result, OperationError>.Success(_orgRepository.AsQueryable().ByIds(userOrganizationsIds.ToList()));
+ }
+
private Result WithDeletionAccess(Organization organization)
{
if (_authorizationContext.AllowDelete(organization))
diff --git a/Core.ApplicationServices/Organizations/StsOrganizationSynchronizationService.cs b/Core.ApplicationServices/Organizations/StsOrganizationSynchronizationService.cs
new file mode 100644
index 0000000000..5ace41bf55
--- /dev/null
+++ b/Core.ApplicationServices/Organizations/StsOrganizationSynchronizationService.cs
@@ -0,0 +1,77 @@
+using System;
+using Core.Abstractions.Types;
+using Core.ApplicationServices.Authorization;
+using Core.ApplicationServices.Authorization.Permissions;
+using Core.DomainModel.Organization;
+using Core.DomainServices.Model.StsOrganization;
+using Core.DomainServices.Organizations;
+using Serilog;
+
+namespace Core.ApplicationServices.Organizations
+{
+ public class StsOrganizationSynchronizationService : IStsOrganizationSynchronizationService
+ {
+ private readonly IStsOrganizationUnitService _stsOrganizationUnitService;
+ private readonly IOrganizationService _organizationService;
+ private readonly ILogger _logger;
+ private readonly IAuthorizationContext _authorizationContext;
+
+ public StsOrganizationSynchronizationService(
+ IAuthorizationContext authorizationContext,
+ IStsOrganizationUnitService stsOrganizationUnitService,
+ IOrganizationService organizationService,
+ ILogger logger)
+ {
+ _stsOrganizationUnitService = stsOrganizationUnitService;
+ _organizationService = organizationService;
+ _logger = logger;
+ _authorizationContext = authorizationContext;
+ }
+
+ public Result GetStsOrganizationalHierarchy(Guid organizationId, Maybe levelsToInclude)
+ {
+ var orgWithPermission = _organizationService
+ .GetOrganization(organizationId)
+ .Bind(WithImportPermission);
+
+ if (orgWithPermission.Failed)
+ return orgWithPermission.Error;
+
+ var organization = orgWithPermission.Value;
+ var orgTreeResult = _stsOrganizationUnitService.ResolveOrganizationTree(organization);
+ if (orgTreeResult.Failed)
+ {
+ var detailedOperationError = orgTreeResult.Error;
+ return new OperationError($"Failed to load organization tree:{detailedOperationError.Detail:G}:{detailedOperationError.FailureType:G}:{detailedOperationError.Message}", detailedOperationError.FailureType);
+ }
+
+ return FilterByRequestedLevels(orgTreeResult.Value, levelsToInclude);
+ }
+
+ private Result WithImportPermission(Organization organization)
+ {
+ if (_authorizationContext.HasPermission(new ImportHierarchyFromStsOrganizationPermission(organization)))
+ {
+ return organization;
+ }
+ return new OperationError($"The user does not have permission to use the STS Organization Sync functionality for the organization with uuid:{organization.Uuid}", OperationFailure.Forbidden);
+ }
+
+ private static Result FilterByRequestedLevels(StsOrganizationUnit root, Maybe levelsToInclude)
+ {
+ if (levelsToInclude.IsNone)
+ {
+ return root;
+ }
+
+ var levels = levelsToInclude.Value;
+ if (levels < 1)
+ {
+ return new OperationError($"{nameof(levelsToInclude)} must be greater than or equal to 1", OperationFailure.BadInput);
+ }
+
+ levels--;
+ return root.Copy(levels);
+ }
+ }
+}
diff --git a/Core.ApplicationServices/Rights/IUserRightsService.cs b/Core.ApplicationServices/Rights/IUserRightsService.cs
index c63900cbc4..4d64ae3323 100644
--- a/Core.ApplicationServices/Rights/IUserRightsService.cs
+++ b/Core.ApplicationServices/Rights/IUserRightsService.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Core.Abstractions.Types;
using Core.ApplicationServices.Model.RightsHolder;
+using Core.ApplicationServices.Model.Users;
using Core.DomainModel.Organization;
namespace Core.ApplicationServices.Rights
@@ -8,5 +9,9 @@ namespace Core.ApplicationServices.Rights
public interface IUserRightsService
{
Result, OperationError> GetUsersWithRoleAssignment(OrganizationRole role);
+ Result GetUserRights(int userId, int organizationId);
+ Maybe RemoveAllRights(int userId, int organizationId);
+ Maybe RemoveRights(int userId, int organizationId, UserRightsChangeParameters parameters);
+ Maybe TransferRights(int fromUserId, int toUserId, int organizationId, UserRightsChangeParameters parameters);
}
}
diff --git a/Core.ApplicationServices/Rights/UserRightsService.cs b/Core.ApplicationServices/Rights/UserRightsService.cs
index 5705e899c2..6b3972dd87 100644
--- a/Core.ApplicationServices/Rights/UserRightsService.cs
+++ b/Core.ApplicationServices/Rights/UserRightsService.cs
@@ -1,14 +1,25 @@
using Core.ApplicationServices.Authorization;
using Core.ApplicationServices.Organizations;
-using Core.DomainServices;
using System.Collections.Generic;
+using System;
using System.Linq;
using Core.Abstractions.Types;
using Core.ApplicationServices.Model.RightsHolder;
+using Core.ApplicationServices.Model.Users;
using Core.DomainModel;
+using Core.DomainModel.GDPR;
+using Core.DomainModel.ItContract;
+using Core.DomainModel.ItProject;
+using Core.DomainModel.ItSystem;
+using Core.DomainModel.ItSystemUsage;
using Core.DomainModel.Organization;
using Core.DomainServices.Authorization;
using Core.DomainServices.Extensions;
+using Core.DomainServices.Generic;
+using Core.DomainServices.Queries;
+using Core.DomainServices.Role;
+using Infrastructure.Services.DataAccess;
+using Serilog;
namespace Core.ApplicationServices.Rights
{
@@ -17,15 +28,47 @@ public class UserRightsService : IUserRightsService
private readonly IUserService _userService;
private readonly IOrganizationService _organizationService;
private readonly IAuthorizationContext _authorizationContext;
+ private readonly IEntityIdentityResolver _identityResolver;
+ private readonly IOrganizationRightsService _organizationRightsService;
+ private readonly IRoleAssignmentService _itContractRightService;
+ private readonly IRoleAssignmentService _itSystemRightService;
+ private readonly IRoleAssignmentService _itProjectRightService;
+ private readonly IRoleAssignmentService _organizationUnitRightService;
+ private readonly IRoleAssignmentService _dprRoleAssignmentsService;
+ private readonly ITransactionManager _transactionManager;
+ private readonly IDatabaseControl _databaseControl;
+ private readonly ILogger _logger;
- public UserRightsService(IUserService userService, IOrganizationService organizationService, IAuthorizationContext authorizationContext)
+ public UserRightsService(
+ IUserService userService,
+ IOrganizationService organizationService,
+ IAuthorizationContext authorizationContext,
+ IEntityIdentityResolver identityResolver,
+ IOrganizationRightsService organizationRightsService,
+ IRoleAssignmentService itContractRightService,
+ IRoleAssignmentService itSystemRightService,
+ IRoleAssignmentService itProjectRightService,
+ IRoleAssignmentService organizationUnitRightService,
+ IRoleAssignmentService dprRoleAssignmentsService,
+ ITransactionManager transactionManager,
+ IDatabaseControl databaseControl,
+ ILogger logger)
{
_userService = userService;
_organizationService = organizationService;
_authorizationContext = authorizationContext;
+ _identityResolver = identityResolver;
+ _organizationRightsService = organizationRightsService;
+ _itContractRightService = itContractRightService;
+ _itSystemRightService = itSystemRightService;
+ _itProjectRightService = itProjectRightService;
+ _organizationUnitRightService = organizationUnitRightService;
+ _dprRoleAssignmentsService = dprRoleAssignmentsService;
+ _transactionManager = transactionManager;
+ _databaseControl = databaseControl;
+ _logger = logger;
}
-
public Result, OperationError> GetUsersWithRoleAssignment(OrganizationRole role)
{
if (_authorizationContext.GetCrossOrganizationReadAccess() < CrossOrganizationDataReadAccessLevel.All)
@@ -38,6 +81,103 @@ public Result, OperationError> GetUsersWithR
.Bind(users => MapOrganizationalRightsHolderRelation(users, role));
}
+ public Result GetUserRights(int userId, int organizationId)
+ {
+ if (_authorizationContext.GetOrganizationReadAccessLevel(organizationId) < OrganizationDataReadAccessLevel.All)
+ {
+ return new OperationError(OperationFailure.Forbidden);
+ }
+ var orgUuid = _identityResolver.ResolveUuid(organizationId);
+ if (orgUuid.IsNone)
+ {
+ return new OperationError("Organization id is invalid", OperationFailure.BadInput);
+ }
+ var userUuid = _identityResolver.ResolveUuid(userId);
+ if (userUuid.IsNone)
+ {
+ return new OperationError("User id is invalid", OperationFailure.BadInput);
+ }
+
+ return _userService
+ .GetUserInOrganization(orgUuid.Value, userUuid.Value)
+ .Select(user => ExtractAllRightsInOrganization(user, orgUuid.Value))
+ .Select(rights => new UserRightsAssignments
+ (
+ rights.rolesInOrganization.Where(x => x != OrganizationRole.User && x != OrganizationRole.GlobalAdmin).ToList(),
+ rights.dprRights.ToList(),
+ rights.systemRights.ToList(),
+ rights.contractRights.ToList(),
+ rights.projectRights.ToList(),
+ rights.organizationUnitRights.ToList()
+ )
+ );
+ }
+
+ public Maybe RemoveAllRights(int userId, int organizationId)
+ {
+ return MutateUserRights(
+ userId,
+ organizationId,
+ context =>
+ RemoveRights
+ (
+ context.user,
+ context.organization,
+ context.dprRights,
+ context.contractRights,
+ context.projectRights,
+ context.systemRights,
+ context.organizationUnitRights,
+ context.rolesInOrganization
+ )
+ );
+ }
+
+ public Maybe RemoveRights(int userId, int organizationId, UserRightsChangeParameters parameters)
+ {
+ return MutateUserRights(
+ userId,
+ organizationId,
+ context =>
+ RemoveRights
+ (
+ context.user,
+ context.organization,
+ context.dprRights.Where(right => parameters.DataProcessingRegistrationRightIds.Contains(right.Id)).ToList(),
+ context.contractRights.Where(right => parameters.ContractRightIds.Contains(right.Id)).ToList(),
+ context.projectRights.Where(right => parameters.ProjectRightIds.Contains(right.Id)).ToList(),
+ context.systemRights.Where(right => parameters.SystemRightIds.Contains(right.Id)).ToList(),
+ context.organizationUnitRights.Where(right => parameters.OrganizationUnitRightsIds.Contains(right.Id)).ToList(),
+ context.rolesInOrganization.Where(role => parameters.AdministrativeAccessRoles.Contains(role)).ToList()
+ )
+ );
+ }
+
+ public Maybe TransferRights(int fromUserId, int toUserId, int organizationId, UserRightsChangeParameters parameters)
+ {
+ if (fromUserId == toUserId)
+ {
+ return Maybe.None;
+ }
+ return MutateUserRights(
+ fromUserId,
+ organizationId,
+ context =>
+ TransferRights
+ (
+ context.user,
+ context.organization,
+ toUserId,
+ context.dprRights.Where(right => parameters.DataProcessingRegistrationRightIds.Contains(right.Id)).ToList(),
+ context.contractRights.Where(right => parameters.ContractRightIds.Contains(right.Id)).ToList(),
+ context.projectRights.Where(right => parameters.ProjectRightIds.Contains(right.Id)).ToList(),
+ context.systemRights.Where(right => parameters.SystemRightIds.Contains(right.Id)).ToList(),
+ context.organizationUnitRights.Where(right => parameters.OrganizationUnitRightsIds.Contains(right.Id)).ToList(),
+ context.rolesInOrganization.Where(role => parameters.AdministrativeAccessRoles.Contains(role)).ToList()
+ )
+ );
+ }
+
private Result, OperationError> MapOrganizationalRightsHolderRelation(IQueryable users, OrganizationRole role)
{
var result = new List();
@@ -61,5 +201,284 @@ private Result, OperationError> MapOrganizat
return result;
}
+
+ private Maybe MutateUserRights(
+ int userId,
+ int organizationId,
+ Func<(Organization organization, User user, IEnumerable dprRights, IEnumerable