\!/ KyuuKazami \!/

Path : /scripts/
Upload :
Current File : //scripts/pl_update_users

#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - scripts/pl_update_users                   Copyright 2016 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package scripts::pl_update_users;

use strict;
use File::Path   ();
use Getopt::Long ();

use Cpanel::AccessIds::ReducedPrivileges               ();
use Cpanel::AcctUtils::Account                         ();
use Cpanel::AcctUtils::Owner                           ();
use Cpanel::Config                                     ();
use Cpanel::Config::CpUserGuard                        ();
use Cpanel::ConfigFiles                                ();
use Cpanel::iContact::Class::PaperLantern::UpdateUsers ();
use Cpanel::Locale                                     ();
use Cpanel::Logger::Aggregator                         ();
use Cpanel::PwCache                                    ();
use Cpanel::Reseller                                   ();
use Cpanel::Services::Cpsrvd                           ();
use Whostmgr::ACLS                                     ();

my $locale            = Cpanel::Locale->get_handle();
my %branding_dir_list = ();

exit main(@ARGV) unless caller;

sub main {
    my @args = my @orig_args = @_;

    if ( $> != 0 ) {
        die "$0: must run as root\n";
    }

    my ( $verbose, $notify, $help );
    my $log_aggregator = Cpanel::Logger::Aggregator->new();

    Getopt::Long::GetOptionsFromArray(
        \@args,
        'verbose' => \$verbose,
        'notify'  => \$notify,
        'help'    => \$help
      )
      and !@args
      or _die_usage(@orig_args);

    _exit_usage(@orig_args) if $help;

    $log_aggregator->info( $locale->maketext('The system will now update all users on [asis,x3] or [asis,x3mail] to use [asis,paper_lantern]') );

    my ( $result, $status, $failures ) = _update_users($verbose);

    if ( $result && $status ) {
        $log_aggregator->info( $locale->maketext( 'The system successfully updated [quant,_1,user,users]', $result ) );
    }
    elsif ( !$result && $status ) {
        $log_aggregator->info( $locale->maketext('No users are currently using [asis,x3] or [asis,x3mail]') );
    }
    else {
        $log_aggregator->info( $locale->maketext('The system failed to update some users:') );
        $log_aggregator->info("$_->{user} : $_->{exception}") for @{$failures};
    }

    if ( $notify && ( $result || !$status ) ) {
        Cpanel::iContact::Class::PaperLantern::UpdateUsers->new( detail => $log_aggregator->as_text, status => $status );
    }

    return $status ? 0 : 1;
}

sub _update_users {
    my ($verbose) = @_;

    my ( @failures, $result, %updated_users, $needs_update );

    my $list_users = _list_users();

    my $exception;
    foreach my $user ( @{$list_users} ) {
        $needs_update = 0;
        unless ( Cpanel::AcctUtils::Account::accountexists($user) ) {
            $exception = $locale->maketext( 'The user “[_1]” does not exist', $user );
            push @failures, { user => $user, exception => $exception };
            next;
        }

        my $user_branding = _get_custom_branding($user);
        if ( $user_branding && !_one_of_ours($user_branding) ) {
            print "“$user“ uses custom branding: $user_branding - not converting\n" if $verbose;
            next;
        }

        if ( my $cpuser_guard = Cpanel::Config::CpUserGuard->new($user) ) {
            my $cpuser_data = $cpuser_guard->{'data'};

            my $reseller_branding = _get_reseller_branding( $user, $cpuser_data->{'RS'} );
            if ( $reseller_branding && !_one_of_ours($reseller_branding) ) {
                print "“$user“ uses custom reseller branding: $reseller_branding - not converting\n" if $verbose;
                next;
            }

            if ( $cpuser_data->{'RS'} eq 'x3' ) {
                $cpuser_data->{'RS'} = 'paper_lantern';
                $needs_update = 1;
            }
            if ( $cpuser_data->{'RS'} eq 'x3mail' ) {
                $cpuser_data->{'RS'}          = 'paper_lantern';
                $cpuser_data->{'FEATURELIST'} = 'Mail Only' unless $cpuser_data->{'FEATURELIST'} && $cpuser_data->{'FEATURELIST'} ne 'default';
                $needs_update                 = 1;
            }
            if ($needs_update) {
                print "Converting “$user“ to Paper Lantern\n" if $verbose;
                $cpuser_guard->save();
                Cpanel::Services::Cpsrvd::signal_users_cpsrvd_to_reload($user);
                $updated_users{$user} = 1;
            }
        }
        else {
            $exception = $locale->maketext('Unable to read user data');
            push @failures, { user => $user, exception => $exception };
        }
    }

    $result = keys %updated_users;
    if ( scalar @failures ) {
        return ( $result, 0, \@failures );
    }
    else {
        return ( $result, 1, \@failures );
    }
}

sub _list_users {
    if ( !$ENV{'REMOTE_USER'} ) { $ENV{'REMOTE_USER'} = 'root'; }

    Whostmgr::ACLS::init_acls();

    my %userdomains = Cpanel::Config::loadtrueuserdomains( undef, 1 );

    return [ keys %userdomains ];
}

sub _get_custom_branding {
    my ($user) = @_;
    my $homedir = Cpanel::PwCache::gethomedir($user) or return;

    my $privs         = Cpanel::AccessIds::ReducedPrivileges->new($user);
    my $branding_file = $homedir . '/.cpanel/nvdata/brandingpkg';
    return unless -e $branding_file;

    my $branding_pkg;
    if ( open( my $fh, '<', $branding_file ) ) {
        $branding_pkg = <$fh>;
        close $fh;
        chomp $branding_pkg;
    }

    return $branding_pkg;
}

sub _get_reseller_branding {
    my ( $user, $theme ) = @_;

    return unless $theme eq 'x3' || $theme eq 'x3mail';

    my $privs;
    my $branding_dir;
    if ( Cpanel::Reseller::isreseller($user) ) {
        $privs        = Cpanel::AccessIds::ReducedPrivileges->new($user);
        $branding_dir = Cpanel::PwCache::gethomedir($user) or return;
    }
    else {
        my $owner = Cpanel::AcctUtils::Owner::getowner($user);
        if ( !length $owner || $owner eq 'root' || $owner eq 'system' || $owner eq 'cpanel' || !Cpanel::AcctUtils::Account::accountexists($owner) ) {
            $branding_dir = $Cpanel::ConfigFiles::ROOT_CPANEL_HOMEDIR;
        }
        else {
            $branding_dir = Cpanel::PwCache::gethomedir($owner);
            $privs        = Cpanel::AccessIds::ReducedPrivileges->new($owner);
        }
        return if !length $branding_dir;
    }
    $branding_dir .= '/cpanelbranding/' . $theme;

    return unless $branding_dir && -d $branding_dir;

    return $branding_dir_list{$branding_dir} if exists $branding_dir_list{$branding_dir};

    my $default_branding = $branding_dir . '/default';
    return unless -e $default_branding;

    my $branding_pkg;
    if ( open( my $fh, '<', $default_branding ) ) {
        $branding_pkg = <$fh>;
        close $fh;
        chomp $branding_pkg;
    }

    $branding_dir_list{$branding_dir} = $branding_pkg;

    return $branding_pkg;
}

sub _one_of_ours {
    my ($pkg) = @_;

    my %cpanel_branding_pkgs = (
        black_ice         => 1,
        blue_lagoon       => 1,
        blueroy           => 1,
        business2business => 1,
        clocks            => 1,
        crimson_smoke     => 1,
        falltheme         => 1,
        mobile            => 1,
        monsoon           => 1,
        motor_city        => 1,
        servers           => 1,
        sundaymorning     => 1,
        tealmadness       => 1,
        the_beach         => 1,
        x                 => 1,
    );

    return $cpanel_branding_pkgs{$pkg} ? 1 : 0;
}

sub _die_usage {
    my @orig_args = @_;
    print <<EOU;
Invalid argument set: @orig_args

EOU
    die _usage();
}

sub _exit_usage {
    print _usage();
    exit 0;
}

sub _usage {

    return <<EOU;
usage: pl_update_users <options>

This script updates all existing users that have x3 or x3mail as cPanel themes to
use paper lantern and the Retro style. For x3mail users, their feature lists will
be set to Mail Only unless their feature lists are already set to something different.

Options:

--verbose - If passed will generate more verbose output.
--notify  - If provided, the script will send a notification to the server
            contact upon success or failure with additional details about the
            outcome of the run.
EOU
}

1;

@KyuuKazami