#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - Cpanel/Admin/Modules/Cpanel/ccs.pm       Copyright 2020 cPanel L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package Cpanel::Admin::Modules::Cpanel::ccs;

use strict;
use warnings;

use base qw( Cpanel::Admin::Base );

use Cpanel                            ();
use Cpanel::Debug                     ();
use Cpanel::Exception                 ();
use Cpanel::ServerTasks               ();
use Cpanel::Validate::VirtualUsername ();

use lib '/var/cpanel/perl';

use Cpanel::CCS::DBUtils   ();
use Cpanel::CCS::Delegates ();
use Cpanel::CCS::Userdata  ();

=head1 NAME

Cpanel::Admin::Modules::Cpanel::ccs

=head1 SYNOPSIS

Cpanel::AdminBin::Call::call( 'Cpanel', 'ccs', 'INSTALLSSL', @domains );
Cpanel::AdminBin::Call::call( 'Cpanel', 'ccs', 'DELSSL', @domains );
Cpanel::AdminBin::Call::call( 'Cpanel', 'ccs', 'OUTPUT_ACCOUNTS' );
my $res = Cpanel::AdminBin::Call::call( 'Cpanel', 'ccs', 'MANAGE_DELEGATIONS', $delegator, $delegatee, $readonly, $action );
my $res = Cpanel::AdminBin::Call::call( 'Cpanel', 'ccs', 'GET_DELEGATIONS' );
my $res = Cpanel::AdminBin::Call::call( 'Cpanel', 'ccs', 'GET_CCS_USERS' );

=head1 DESCRIPTION

Admin Module for functions pertaining to CCS and cPanel users which handles
the escalation paths needed for various things a user may want to do.

=head1 SUBROUTINES

=cut

sub _actions {
    return qw/OUTPUT_ACCOUNTS GET_UID INSTALLSSL DELSSL GET_DELEGATIONS MANAGE_DELEGATIONS GET_CCS_USERS/;
}

=head2 OUTPUT_ACCOUNTS

Scans the server for any cPanel users and virtual accounts which do not yet
have CCS users created for them and then creates them. Any no longer existing
users are additionally removed in the same pass.

No arguments are accepted. Returns whether or not scheduling this action
succeeded or not.

=cut

sub OUTPUT_ACCOUNTS {
    my ($self) = @_;

    if ($Cpanel::Debug::level) {
        Cpanel::Debug::log_info("OUTPUT_ACCOUNTS: called");
    }

    local $@;
    eval { Cpanel::ServerTasks::schedule_task( ['CCSTasks'], 5, 'rebuild_ccs_users' ); };
    Cpanel::Debug::log_warn($@) if $@;

    return $@ ? 0 : 1;
}

=head2 GET_UID

Gives you back the UUID for a CCS user which CCS uses to identify a user.

Accepts an email address as input.

Returns the UUID if one exists, blank string if not.

=cut

sub GET_UID {
    my ( $self, $email ) = @_;

    # Note we have to validate here that the passed in email actually belongs to the user, due to the execution context
    $email || do {
        die Cpanel::Exception::create( 'MissingParameter', [ name => 'email' ] );
    };

    # Existing, but need better exception for this sometime
    die "I can't let you do that, Dave" if $email =~ /\.\./;

    my $cpuser = $self->get_caller_username();
    Cpanel::Validate::VirtualUsername::validate_or_die($email) if $email ne $cpuser;
    Cpanel::initcp($cpuser);

    # Check if the domain part of user is owned by this user.
    if( $email ne $cpuser ) {
        my ( $mailbox, $domain ) = split( /[@]/, $email, 2 );
        $self->verify_that_cpuser_owns_domain($domain);
    }

    # Now get the UID from the calendar server persistence DB we maintain
    my $uid = Cpanel::CCS::Userdata::get_user_uid( $email, 'autocreate' => 0 ) || '';

    return $uid;
}

sub _boilerplate {
    my ($self) = @_;
    my $cpuser = $self->get_caller_username();

    # Verifies it is a cpuser
    Cpanel::initcp($cpuser);

    # Pass in cpuser to only get CCS users grouped by this cpuser
    my $users_hr = Cpanel::CCS::Userdata::get_users($cpuser);

    # now fetch the delegates from the DB
    my $dbh = Cpanel::CCS::DBUtils::get_dbh();

    return ( $users_hr, $dbh, $cpuser );
}

=head2 GET_DELEGATIONS

Returns the list of users which currently have delegation relationships setup
along with information about that relation. (ARRAYREF).

Example:
    [
        {
            'delegator' => 'executive@dom.test',
            'delegatee' => 'assistant@dom.test',
            'readonly'  => 0,
        },
        ...
    ]

=cut

sub GET_DELEGATIONS {
    my ($self) = @_;
    return Cpanel::CCS::Delegates::get( _boilerplate($self) );
}

=head2 MANAGE_DELEGATIONS

Allows you to add, edit or delete a delegation relation for users.
Inputs are positional arguments:
* delegator: STRING corresponding to a CCS user. Their calendars will be delegated to the delegatee.
* delegatee: STRING corresponding to a CCS user. This user will be able to access the delegator's calendars.
* readonly:  BOOL   Whether or not you want the delegatee to be able to alter the calendars.
* action:    STRING What action to executed. Valid actions are 'CREATE', 'UPDATE' and 'DELETE'.

Returns whether or not the update succeeded.

=cut

sub MANAGE_DELEGATIONS {
    my ( $self, $delegator, $delegatee, $readonly, $action ) = @_;
    my ( $users_hr, $dbh, $cpuser ) = _boilerplate($self);
    my $args_hr = {
        'delegator' => $delegator,
        'delegatee' => $delegatee,
        'readonly'  => $readonly,
        'action'    => $action,
        'users_hr'  => $users_hr,
        'dbh'       => $dbh,
        'cpuser'    => $cpuser,
    };
    return Cpanel::CCS::Delegates::manage($args_hr);
}

=head2 GET_CCS_USERS

Returns the list of users in CCS for the cPuser (HASHREF) with their UUIDs.
Example:
{
    'luser@test.test'      => 'some_uuid',
    'otherguy@test.test'   => 'another_uuid',
    'ldapuser@my.org.test' => 'uuid_from_ldap',
    ...
}

=cut

sub GET_CCS_USERS {
    my ($self) = @_;
    my ( $users_hr, undef, $cpuser ) = _boilerplate($self);

    # Flatten datastructure
    $users_hr = { map { $_ => $users_hr->{$_}{'uuid'} } keys(%$users_hr) };

    return $users_hr;
}

=head2 INSTALLSSL

Copies whatever certificate currently is installed for input @domains over
to CCS' "Domain TLS" store so that CCS can also use these certs.

Inputs: @domains to copy certs from.

Returns truthy or throws exception on failure.

=cut

sub INSTALLSSL {
    my ( $self, @domains ) = @_;

    foreach (@domains) {
        $self->verify_that_cpuser_owns_domain($_);
    }
    require Cpanel::CCS::DomainTLS;
    Cpanel::CCS::DomainTLS::real_copy_certs_for_domains(@domains);

    return 1;

}

=head2 DELSSL

Deletes the certificate CCS has on file for @domains.

Inputs: @domains to delete certs for.

Returns truthy or throws exception on failure.

=cut

sub DELSSL {
    my ( $self, @domains, ) = @_;

    foreach (@domains) {
        $self->verify_that_cpuser_owns_domain($_);
    }
    require Cpanel::CCS::DomainTLS;
    Cpanel::CCS::DomainTLS::real_remove_certs_for_domains(@domains);

    return 1;
}

1;
