<commit_before>﻿using System;
using Core.ApplicationServices.Authorization.Permissions;
using Core.DomainModel;
using Core.DomainModel.ItContract;
using Core.DomainModel.ItSystem;
using Core.DomainModel.Organization;
using Core.DomainServices.Authorization;
using Infrastructure.Services.DataAccess;

namespace Core.ApplicationServices.Authorization
{
    public class OrganizationAuthorizationContext : IAuthorizationContext, IPermissionVisitor
    {
        private readonly IOrganizationalUserContext _activeUserContext;
        private readonly IEntityTypeResolver _typeResolver;
        private readonly IAuthorizationPolicy<IEntity> _moduleLevelAccessPolicy;
        private readonly IAuthorizationPolicy<Type> _globalReadAccessPolicy;

        public OrganizationAuthorizationContext(
            IOrganizationalUserContext activeUserContext,
            IEntityTypeResolver typeResolver,
            IAuthorizationPolicy<IEntity> moduleLevelAccessPolicy,
            IAuthorizationPolicy<Type> globalReadAccessPolicy)
        {
            _activeUserContext = activeUserContext;
            _typeResolver = typeResolver;
            _moduleLevelAccessPolicy = moduleLevelAccessPolicy;
            _globalReadAccessPolicy = globalReadAccessPolicy;
        }

        public CrossOrganizationDataReadAccessLevel GetCrossOrganizationReadAccess()
        {
            if (IsGlobalAdmin())
            {
                return CrossOrganizationDataReadAccessLevel.All;
            }

            return IsUserInMunicipality() ?
                CrossOrganizationDataReadAccessLevel.Public :
                CrossOrganizationDataReadAccessLevel.None;
        }

        public OrganizationDataReadAccessLevel GetOrganizationReadAccessLevel(int organizationId)
        {
            if (TargetOrganizationMatchesActiveOrganization(organizationId))
            {
                return OrganizationDataReadAccessLevel.All;
            }

            switch (GetCrossOrganizationReadAccess())
            {
                case CrossOrganizationDataReadAccessLevel.Public:
                    return OrganizationDataReadAccessLevel.Public;
                case CrossOrganizationDataReadAccessLevel.All:
                    return OrganizationDataReadAccessLevel.All;
                default:
                    return OrganizationDataReadAccessLevel.None;
            }
        }

        public EntityReadAccessLevel GetReadAccessLevel<T>()
        {
            var entityType = _typeResolver.Resolve(typeof(T));
            return GetReadAccessLevel(entityType);
        }

        public bool AllowReads(IEntity entity)
        {
            if (entity == null)
            {
                return false;
            }

            if (EntityEqualsActiveUser(entity))
            {
                return true;
            }

            var entityType = _typeResolver.Resolve(entity.GetType());

            var readAccessLevel = GetReadAccessLevel(entityType);
            switch (readAccessLevel)
            {
                case EntityReadAccessLevel.None:
                    return false;
                case EntityReadAccessLevel.OrganizationOnly:
                    return ActiveContextIsEntityContext(entity);
                case EntityReadAccessLevel.OrganizationAndPublicFromOtherOrganizations:
                    return ActiveContextIsEntityContext(entity) || EntityIsShared(entity);
                case EntityReadAccessLevel.All:
                    return true;
                default:
                    throw new ArgumentOutOfRangeException(nameof(readAccessLevel), "unsupported read access level");
            }
        }

        public bool AllowCreate<T>()
        {
            if (IsReadOnly())
            {
                return false;
            }

            if (MatchType<T, ItSystem>())
            {
                return IsGlobalAdmin();
            }

            //NOTE: Once we migrate more types, this will be extended
            return true;
        }

        public bool AllowCreate<T>(IEntity entity)
        {
            return
                AllowCreate<T>() &&
                CheckNewObjectAccessModifierPolicy(entity) &&
                CheckSpecificCreationPolicy(entity) &&
                AllowModify(entity); //NOTE: Ensures backwards compatibility as long as some terms are yet to be fully migrated
        }

        private EntityReadAccessLevel GetReadAccessLevel(Type entityType)
        {
            var globalRead = _globalReadAccessPolicy.Allow(entityType) || IsGlobalAdmin();
            if (globalRead)
            {
                return EntityReadAccessLevel.All;
            }

            if (IsContextBound(entityType))
            {
                return GetCrossOrganizationReadAccess() >= CrossOrganizationDataReadAccessLevel.Public
                    ? EntityReadAccessLevel.OrganizationAndPublicFromOtherOrganizations
                    : EntityReadAccessLevel.OrganizationOnly;
            }

            return EntityReadAccessLevel.None;
        }

        private bool CheckNewObjectAccessModifierPolicy(IEntity entity)
        {
            if (entity is IHasAccessModifier accessModifier)
            {
                return HasPermission(new CreateEntityWithVisibilityPermission(accessModifier.AccessModifier, entity));
            }<commit_msg>only other global admins may create global admins<commit_after>﻿using System;
using Core.ApplicationServices.Authorization.Permissions;
using Core.DomainModel;
using Core.DomainModel.ItContract;
using Core.DomainModel.ItSystem;
using Core.DomainModel.Organization;
using Core.DomainServices.Authorization;
using Infrastructure.Services.DataAccess;

namespace Core.ApplicationServices.Authorization
{
    public class OrganizationAuthorizationContext : IAuthorizationContext, IPermissionVisitor
    {
        private readonly IOrganizationalUserContext _activeUserContext;
        private readonly IEntityTypeResolver _typeResolver;
        private readonly IAuthorizationPolicy<IEntity> _moduleLevelAccessPolicy;
        private readonly IAuthorizationPolicy<Type> _globalReadAccessPolicy;

        public OrganizationAuthorizationContext(
            IOrganizationalUserContext activeUserContext,
            IEntityTypeResolver typeResolver,
            IAuthorizationPolicy<IEntity> moduleLevelAccessPolicy,
            IAuthorizationPolicy<Type> globalReadAccessPolicy)
        {
            _activeUserContext = activeUserContext;
            _typeResolver = typeResolver;
            _moduleLevelAccessPolicy = moduleLevelAccessPolicy;
            _globalReadAccessPolicy = globalReadAccessPolicy;
        }

        public CrossOrganizationDataReadAccessLevel GetCrossOrganizationReadAccess()
        {
            if (IsGlobalAdmin())
            {
                return CrossOrganizationDataReadAccessLevel.All;
            }

            return IsUserInMunicipality() ?
                CrossOrganizationDataReadAccessLevel.Public :
                CrossOrganizationDataReadAccessLevel.None;
        }

        public OrganizationDataReadAccessLevel GetOrganizationReadAccessLevel(int organizationId)
        {
            if (TargetOrganizationMatchesActiveOrganization(organizationId))
            {
                return OrganizationDataReadAccessLevel.All;
            }

            switch (GetCrossOrganizationReadAccess())
            {
                case CrossOrganizationDataReadAccessLevel.Public:
                    return OrganizationDataReadAccessLevel.Public;
                case CrossOrganizationDataReadAccessLevel.All:
                    return OrganizationDataReadAccessLevel.All;
                default:
                    return OrganizationDataReadAccessLevel.None;
            }
        }

        public EntityReadAccessLevel GetReadAccessLevel<T>()
        {
            var entityType = _typeResolver.Resolve(typeof(T));
            return GetReadAccessLevel(entityType);
        }

        public bool AllowReads(IEntity entity)
        {
            if (entity == null)
            {
                return false;
            }

            if (EntityEqualsActiveUser(entity))
            {
                return true;
            }

            var entityType = _typeResolver.Resolve(entity.GetType());

            var readAccessLevel = GetReadAccessLevel(entityType);
            switch (readAccessLevel)
            {
                case EntityReadAccessLevel.None:
                    return false;
                case EntityReadAccessLevel.OrganizationOnly:
                    return ActiveContextIsEntityContext(entity);
                case EntityReadAccessLevel.OrganizationAndPublicFromOtherOrganizations:
                    return ActiveContextIsEntityContext(entity) || EntityIsShared(entity);
                case EntityReadAccessLevel.All:
                    return true;
                default:
                    throw new ArgumentOutOfRangeException(nameof(readAccessLevel), "unsupported read access level");
            }
        }

        public bool AllowCreate<T>()
        {
            if (IsReadOnly())
            {
                return false;
            }

            if (MatchType<T, ItSystem>())
            {
                return IsGlobalAdmin();
            }

            //NOTE: Once we migrate more types, this will be extended
            return true;
        }

        public bool AllowCreate<T>(IEntity entity)
        {
            return
                AllowCreate<T>() &&
                CheckNewObjectAccessModifierPolicy(entity) &&
                CheckSpecificCreationPolicy(entity) &&
                AllowModify(entity); //NOTE: Ensures backwards compatibility as long as some terms are yet to be fully migrated
        }

        private EntityReadAccessLevel GetReadAccessLevel(Type entityType)
        {
            var globalRead = _globalReadAccessPolicy.Allow(entityType) || IsGlobalAdmin();
            if (globalRead)
            {
                return EntityReadAccessLevel.All;
            }

            if (IsContextBound(entityType))
            {
                return GetCrossOrganizationReadAccess() >= CrossOrganizationDataReadAccessLevel.Public
                    ? EntityReadAccessLevel.OrganizationAndPublicFromOtherOrganizations
                    : EntityReadAccessLevel.OrganizationOnly;
            }

            return EntityReadAccessLevel.None;
        }

        private bool CheckNewObjectAccessModifierPolicy(IEntity entity)
        {
            if (entity is User user)
            {
                if (user.IsGlobalAdmin)
                {
                    return IsGlobalAdmin(); //Only global admin can create other global admins
                }
            }

            if (entity is IHasAccessModifier accessModifier)
            {
                return HasPermission(new CreateEntityWithVisibilityPermission(accessModifier.AccessModifier, entity));
            }
{'fraction_non_alphanumeric': 0.05469960798614277, 'fraction_numerical': 0.0, 'mean_word_length': 1.9753186872796311, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4629159', 'n_tokens_mistral': 2427, 'n_tokens_neox': 2346, 'n_words': 474}