<commit_before>%%%-------------------------------------------------------------------
%%% @author <NAME>
%%% @copyright (C) 2015 ACK CYFRONET AGH
%%% This software is released under the MIT license
%%% cited in 'LICENSE.txt'.
%%% @end
%%%-------------------------------------------------------------------
%%% @doc Models definitions. Extends datastore models.
%%% @end
%%%-------------------------------------------------------------------

-ifndef(DATASTORE_SPECIFIC_MODELS_HRL).
-define(DATASTORE_SPECIFIC_MODELS_HRL, 1).

-include("modules/events/subscriptions.hrl").
-include_lib("ctool/include/posix/file_attr.hrl").
-include_lib("cluster_worker/include/modules/datastore/datastore_models.hrl").

-type file_descriptors() :: #{session:id() => non_neg_integer()}.

% Graph Sync cache metadata, common for all od_* records (synchronized by
% Graph Sync).
-type cache_state() :: #{
    % maximum scope that is currently cached
    scope => gs_protocol:scope(),
    % revision (version of the record that increments with every update)
    revision => gs_protocol:revision(),
    % connection identifier to verify if the cache is not outdated.
    connection_ref => pid()
}.

%%%===================================================================
%%% Records synchronized via Graph Sync
%%%===================================================================

% Records starting with prefix od_ are special records that represent entities
% in the system and are synchronized to providers via Graph Sync.
% The entities can have various relations between them, especially effective
% membership is possible via groups and nested groups.
% these records are synchronized from OZ via Graph Sync.
%
% The below ASCII visual shows possible relations in entities graph.
%
%  provider    share
%      ^         ^
%       \       /
%        \     /
%         space    handle_service     handle
%         ^  ^        ^        ^       ^   ^
%         |   \      /         |      /    |
%         |    \    /          |     /     |
%        user    group          user      group
%                  ^                        ^
%                  |                        |
%                  |                        |
%                group                     user
%                ^   ^
%               /     \
%              /       \
%            user     user
%

-record(od_user, {
    full_name :: undefined | binary(),
    username :: undefined | binary(),
    emails = [] :: [binary()],
    linked_accounts = [] :: [od_user:linked_account()],
    default_space :: binary() | undefined,
    % List of user's aliases for spaces
    space_aliases = #{} :: #{od_space:id() => od_space:alias()},

    % Direct relations to other entities
    eff_groups = [] :: [od_group:id()],
    eff_spaces = [] :: [od_space:id()],
    eff_handle_services = [] :: [od_handle_service:id()],
    eff_handles = [] :: [od_handle:id()],

    cache_state = #{} :: cache_state()
}).

%% Local, cached version of OZ group
-record(od_group, {
    name :: undefined | binary(),
    type = role :: od_group:type(),

    cache_state = #{} :: cache_state()
}).

%% Model for caching space details fetched from OZ
-record(od_space, {
    name :: undefined | binary(),

    direct_users = #{} :: #{od_user:id() => [privileges:space_privilege()]},
    eff_users = #{} :: #{od_user:id() => [privileges:space_privilege()]},

    direct_groups = #{} :: #{od_group:id() => [privileges:space_privilege()]},
    eff_groups = #{} :: #{od_group:id() => [privileges:space_privilege()]},

    providers = #{} :: #{od_provider:id() => Size :: integer()},

    shares = [] :: [od_share:id()],

    harvesters = [] :: [od_harvester:id()],

    cache_state = #{} :: cache_state()
}).

%% Model for caching share details fetched from OZ
-record(od_share, {
    name = undefined :: undefined | binary(),
    public_url = undefined :: undefined | binary(),

    % Direct relations to other entities
    space = undefined :: undefined | od_space:id(),
    handle = undefined :: undefined | od_handle:id(),
    root_file = undefined :: undefined | binary(),

    cache_state = #{} :: cache_state()
}).

%% Model for caching provider details fetched from OZ
-record(od_provider, {
    name :: undefined | binary(),
    admin_email :: undefined | binary(),
    subdomain_delegation = false :: undefined | boolean(),
    domain :: binary(),
    subdomain = undefined :: undefined |  binary(),
    latitude = 0.0 :: float(),
    longitude = 0.0 :: float(),
    online = false :: boolean(),

    % Direct relations to other entities
    spaces = #{} :: #{od_space:id() => Size :: integer()},

    % Effective relations to other entities
    eff_users = [] :: [od_user:id()],
    eff_groups = [] :: [od_group:id()],

    cache_state = #{} :: cache_state()
}).

%% Model for caching handle service details fetched from OZ
-record(od_handle_service, {
    name :: od_handle_service:name() | undefined,

    % Effective relations to other entities
    eff_users = #{} :: #{od_user:id() => [privileges:handle_service_privilege()]},
    eff_groups = #{} :: #{od_group:id() => [privileges:handle_service_privilege()]},

    cache_state = #{} :: cache_state()
}).

%% Model for caching handle details fetched from OZ
-record(od_handle, {
    public_handle :: od_handle:public_handle() | undefined,
    resource_type :: od_handle:resource_type() | undefined,
    resource_id :: od_handle:resource_id() | undefined,
    metadata :: od_handle:metadata() | undefined,
    timestamp = od_handle:actual_timestamp() :: od_handle:timestamp() | undefined,

    % Direct relations to other entities
    handle_service :: od_handle_service:id() | undefined,

    % Effective relations to other entities
    eff_users = #{} :: #{od_user:id() => [privileges:handle_privilege()]},
    eff_groups = #{} :: #{od_group:id() => [privileges:handle_privilege()]},

    cache_state = #{} :: cache_state()
}).

-record(od_harvester, {
    indices = [] :: [od_harvester:index()],
    spaces = [] :: [od_space:id()],
    cache_state = #{} :: cache_state()
}).

%%%===================================================================
%%% Records specific for oneprovider
%%%===================================================================

%% Authorization of this provider, access and identity tokens are derived from
%% the root token and cached for a configurable time.
-record(provider_auth, {
    provider_id :: od_provider:id(),
    root_token :: tokens:serialized(),
    cached_access_token = {0, <<"">>} :: {ValidUntil :: time_utils:seconds(), tokens:serialized()},
    cached_identity_token = {0, <<"">>} :: {ValidUntil :: time_utils:seconds(), tokens:serialized()}
}).

-record(authorization_nonce, {
    timestamp :: integer()
}).

-record(file_download_code, {
    session_id :: session:id(),
    file_guid :: fslogic_worker:file_guid()
}).

%% Identity containing user_id
-record(user_identity, {
    user_id :: undefined | od_user:id(),
    provider_id :: undefined | oneprovider:id()
}).

-record(file_force_proxy, {
    provider_id :: undefined | oneprovider:id()
}).

%% User session
-record(session, {<commit_msg>VFS-5727 Remove obsolete definition of authorization_nonce model<commit_after>%%%-------------------------------------------------------------------
%%% @author <NAME>
%%% @copyright (C) 2015 ACK CYFRONET AGH
%%% This software is released under the MIT license
%%% cited in 'LICENSE.txt'.
%%% @end
%%%-------------------------------------------------------------------
%%% @doc Models definitions. Extends datastore models.
%%% @end
%%%-------------------------------------------------------------------

-ifndef(DATASTORE_SPECIFIC_MODELS_HRL).
-define(DATASTORE_SPECIFIC_MODELS_HRL, 1).

-include("modules/events/subscriptions.hrl").
-include_lib("ctool/include/posix/file_attr.hrl").
-include_lib("cluster_worker/include/modules/datastore/datastore_models.hrl").

-type file_descriptors() :: #{session:id() => non_neg_integer()}.

% Graph Sync cache metadata, common for all od_* records (synchronized by
% Graph Sync).
-type cache_state() :: #{
    % maximum scope that is currently cached
    scope => gs_protocol:scope(),
    % revision (version of the record that increments with every update)
    revision => gs_protocol:revision(),
    % connection identifier to verify if the cache is not outdated.
    connection_ref => pid()
}.

%%%===================================================================
%%% Records synchronized via Graph Sync
%%%===================================================================

% Records starting with prefix od_ are special records that represent entities
% in the system and are synchronized to providers via Graph Sync.
% The entities can have various relations between them, especially effective
% membership is possible via groups and nested groups.
% these records are synchronized from OZ via Graph Sync.
%
% The below ASCII visual shows possible relations in entities graph.
%
%  provider    share
%      ^         ^
%       \       /
%        \     /
%         space    handle_service     handle
%         ^  ^        ^        ^       ^   ^
%         |   \      /         |      /    |
%         |    \    /          |     /     |
%        user    group          user      group
%                  ^                        ^
%                  |                        |
%                  |                        |
%                group                     user
%                ^   ^
%               /     \
%              /       \
%            user     user
%

-record(od_user, {
    full_name :: undefined | binary(),
    username :: undefined | binary(),
    emails = [] :: [binary()],
    linked_accounts = [] :: [od_user:linked_account()],
    default_space :: binary() | undefined,
    % List of user's aliases for spaces
    space_aliases = #{} :: #{od_space:id() => od_space:alias()},

    % Direct relations to other entities
    eff_groups = [] :: [od_group:id()],
    eff_spaces = [] :: [od_space:id()],
    eff_handle_services = [] :: [od_handle_service:id()],
    eff_handles = [] :: [od_handle:id()],

    cache_state = #{} :: cache_state()
}).

%% Local, cached version of OZ group
-record(od_group, {
    name :: undefined | binary(),
    type = role :: od_group:type(),

    cache_state = #{} :: cache_state()
}).

%% Model for caching space details fetched from OZ
-record(od_space, {
    name :: undefined | binary(),

    direct_users = #{} :: #{od_user:id() => [privileges:space_privilege()]},
    eff_users = #{} :: #{od_user:id() => [privileges:space_privilege()]},

    direct_groups = #{} :: #{od_group:id() => [privileges:space_privilege()]},
    eff_groups = #{} :: #{od_group:id() => [privileges:space_privilege()]},

    providers = #{} :: #{od_provider:id() => Size :: integer()},

    shares = [] :: [od_share:id()],

    harvesters = [] :: [od_harvester:id()],

    cache_state = #{} :: cache_state()
}).

%% Model for caching share details fetched from OZ
-record(od_share, {
    name = undefined :: undefined | binary(),
    public_url = undefined :: undefined | binary(),

    % Direct relations to other entities
    space = undefined :: undefined | od_space:id(),
    handle = undefined :: undefined | od_handle:id(),
    root_file = undefined :: undefined | binary(),

    cache_state = #{} :: cache_state()
}).

%% Model for caching provider details fetched from OZ
-record(od_provider, {
    name :: undefined | binary(),
    admin_email :: undefined | binary(),
    subdomain_delegation = false :: undefined | boolean(),
    domain :: binary(),
    subdomain = undefined :: undefined |  binary(),
    latitude = 0.0 :: float(),
    longitude = 0.0 :: float(),
    online = false :: boolean(),

    % Direct relations to other entities
    spaces = #{} :: #{od_space:id() => Size :: integer()},

    % Effective relations to other entities
    eff_users = [] :: [od_user:id()],
    eff_groups = [] :: [od_group:id()],

    cache_state = #{} :: cache_state()
}).

%% Model for caching handle service details fetched from OZ
-record(od_handle_service, {
    name :: od_handle_service:name() | undefined,

    % Effective relations to other entities
    eff_users = #{} :: #{od_user:id() => [privileges:handle_service_privilege()]},
    eff_groups = #{} :: #{od_group:id() => [privileges:handle_service_privilege()]},

    cache_state = #{} :: cache_state()
}).

%% Model for caching handle details fetched from OZ
-record(od_handle, {
    public_handle :: od_handle:public_handle() | undefined,
    resource_type :: od_handle:resource_type() | undefined,
    resource_id :: od_handle:resource_id() | undefined,
    metadata :: od_handle:metadata() | undefined,
    timestamp = od_handle:actual_timestamp() :: od_handle:timestamp() | undefined,

    % Direct relations to other entities
    handle_service :: od_handle_service:id() | undefined,

    % Effective relations to other entities
    eff_users = #{} :: #{od_user:id() => [privileges:handle_privilege()]},
    eff_groups = #{} :: #{od_group:id() => [privileges:handle_privilege()]},

    cache_state = #{} :: cache_state()
}).

-record(od_harvester, {
    indices = [] :: [od_harvester:index()],
    spaces = [] :: [od_space:id()],
    cache_state = #{} :: cache_state()
}).

%%%===================================================================
%%% Records specific for oneprovider
%%%===================================================================

%% Authorization of this provider, access and identity tokens are derived from
%% the root token and cached for a configurable time.
-record(provider_auth, {
    provider_id :: od_provider:id(),
    root_token :: tokens:serialized(),
    cached_access_token = {0, <<"">>} :: {ValidUntil :: time_utils:seconds(), tokens:serialized()},
    cached_identity_token = {0, <<"">>} :: {ValidUntil :: time_utils:seconds(), tokens:serialized()}
}).

-record(file_download_code, {
    session_id :: session:id(),
    file_guid :: fslogic_worker:file_guid()
}).

%% Identity containing user_id
-record(user_identity, {
    user_id :: undefined | od_user:id(),
    provider_id :: undefined | oneprovider:id()
}).

-record(file_force_proxy, {
    provider_id :: undefined | oneprovider:id()
}).

%% User session
-record(session, {
{'fraction_non_alphanumeric': 0.21015000700967335, 'fraction_numerical': 0.0018225150707977008, 'mean_word_length': 2.877955966295189, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4034230', 'n_tokens_mistral': 4152, 'n_tokens_neox': 4029, 'n_words': 967}