Viewing File: /usr/local/cpanel/whostmgr/docroot/themes/x/rebuildtmpl
#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - whostmgr/docroot/themes/x/rebuildtmpl Copyright 2022 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
# Perl code to build menu templates
# Processes dynamicui.conf file to build:
# Left frame navigation template - docroot/templates/menu/command.tmpl
# Navigation pages with icons and links - example:docroot/templates/menu/main.tmpl; docroot/templates/menu/Account_Functions.tmpl
# Breadcrumb file which is used in breadcrumb logic - docroot/themes/x/breadcrumb
# Processes raw:plugins "menu/plugins_list.tmpl" to include plugins in left frame and
# Add code to process templates/plugins_icons.tmpl to display icons on the plugin page.
use cPstrict;
use Cpanel::Locale ();
use Cpanel::StringFunc::Group ();
use Whostmgr::DynamicUI::Loader ();
use Whostmgr::Templates::Command::Directory ();
my $WARNING = "# This file is generated automatically.\n# Do not edit it manually; instead, edit the /usr/local/cpanel/whostmgr/docroot/themes/x/dynamicui.conf file.\n";
my $TMPL_WARNING = "[%# This file is generated automatically.\nDo not edit it manually; instead, edit the /usr/local/cpanel/whostmgr/docroot/themes/x/dynamicui.conf file. -%]\n";
my $fallback_icon_path = 'fallback_icon.png';
# Wrapper for main.tmpl and categories (Account_Function.tmpl, Account_Information.tmpl)
# 'skipheader' - template flag to determine if we need to include page title.
# ===CONTENT=== is a place holder for the content that goes into wrapper
my $MAIN_HF_WRAPPER = $TMPL_WARNING . <<END;
[% WRAPPER 'master_templates/master.tmpl'
theme="bootstrap"
app_key="===key==="
-%]
[% USE Whostmgr -%]
[% USE JSON -%]
[% USE EasyApache -%]
[% USE VarCache -%]
[% USE ServerRoles -%]
[% USE Services -%]
[% USE CPOS -%]
[% varcache.set('checkacl_all',Whostmgr.checkacl('all')); %]
[% varcache.set('dnsonly',Whostmgr.dnsonly()); %]
===CONTENT===
[% END -%]
END
my $CATEGORY_WRAPPER = $TMPL_WARNING . <<END;
===CONTENT===
END
# Wrapper for command.tmpl
my $COMMAND_WRAPPER = $TMPL_WARNING . <<END;
[% USE Whostmgr -%]
[% USE JSON -%]
[% USE EasyApache -%]
[% USE VarCache -%]
[% USE ServerRoles -%]
[% USE Services -%]
[% USE CPOS -%]
[% varcache.set('checkacl_all',Whostmgr.checkacl('all')); %]
[% varcache.set('dnsonly',Whostmgr.dnsonly()); %]
<div class="commandContainer">
<!-- command2.header3 -->
<div class="searchContainer">
<div class="searchBox">
<div class="quickJumpWrapper">
<input name="find" id="quickJump" accesskey="f" title="[% locale.maketext('Search') %]" autocomplete="off" aria-label="Search">
<div id="searchAction" class="quickJumpIcon search"> </div>
</div>
</div>
<div id="toggleAll" class="collapseExpandContainer">
<div class="collapseExpandButtonContainer">
<a class="collapseExpandButton collapse" title="[% locale.maketext('Collapse All') %]" href="javascript:void(0);"></a>
<a class="collapseExpandButton expand" title="[% locale.maketext('Expand All') %]" href="javascript:void(0);"></a>
</div>
</div>
</div>
<div class="mainCommandWrapper">
<ul id="mainCommand" class="">
===CONTENT===
</ul>
<div class="commandFooter">
<div class="jumpUp categoryHeader">
<a href="javascript:void(0)" id="jumpUpLink" title="[% locale.maketext('Navigate to the top of the list.') %]">
<img alt="[% locale.maketext('Back To Top')%]"
src="[% Whostmgr.find_file_url('images/jumpUp.png') %]"
class="backtotop" />
[% locale.maketext('Back To Top') %]
</a>
</div>
<div class="legal">
<span class="soloWrapper" id="soloWrapper">
[% IF Whostmgr.has_multiuser == 0 %]
<img class="logo" src="[% Whostmgr.find_file_url('solo.svg') %]" alt="cPanel Solo" />
[% END %]
</span>
<span class="copyright">
[% locale.maketext('Copyright©[output,nbsp][current_year] [output,url,_1,cPanel~, L.L.C.,title,cPanel Website,target,_2]', 'https://www.cpanel.com/', 'cpanel_company_website') %]
</span>
<a href="[% cp_security_token %]/scripts10/eula"
title="[% locale.maketext_plain_context('[output,acronym,EULA,End User License Agreement]') %]">
[% locale.maketext('[output,acronym,EULA,End User License Agreement]') %]
</a>
<a id="lnkTrademark" href="[% cp_security_token %]/scripts10/trademarks"
title="[% locale.maketext('Trademarks') %]" class="trademark">
[% locale.maketext('Trademarks') %]
</a>
<a id="lnkPrivacy" href="https://go.cpanel.net/privacy"
title="[% locale.maketext('Privacy Policy') %]"
target="_blank">
[% locale.maketext('Privacy Policy') %]
</a>
</div>
</div>
</div>
</div>
END
my ( $HICON, $HEADER_URL, $HF, $hf_buffer, $HDNS, $safeheader );
my $MAIN_URL = "/scripts/command?PFILE=main";
my $this_dir = $0;
$this_dir =~ s{[^/]+\z}{};
chdir $this_dir if $this_dir;
my $tmpl_path = '/usr/local/cpanel/whostmgr/docroot/templates/menu'; # directory where generated templates are saved
my $command_buffer;
my $category_buffer;
open( my $BREADCRUMB, '>', "breadcrumb" ) or die "Could not open breadcrumb: $!\n";
open( my $COMMAND, '>', \$command_buffer ) or die "Could not open command.tmpl: $!\n";
open( my $CATEGORY, '>', \$category_buffer ) or die "Could not open category.tmpl: $!\n";
print $BREADCRUMB $WARNING;
print $CATEGORY qq{
<div id="iconSea" class="panel-body icon-container-body">
};
make_breadcrumb( $MAIN_URL, '', 'Home' );
my $dynui_data = Whostmgr::DynamicUI::Loader::load_dynamicui_conf('/usr/local/cpanel/whostmgr/docroot/themes/x/dynamicui.conf');
my $HEADER = '';
my $HKEY = '';
my $HADHEADER = '-1';
my $categoryIfCondition = '';
my $slugified_item = ""; # used to add slugified text to items/pages in a category
my $slugified_header = ""; # used to add slugified text to a category
my $application_key = "";
foreach my $group ( @{ $dynui_data->{'groups'} } ) {
#now, on to the new header....
$HEADER = $group->{'groupdesc'};
$HICON = $group->{'file'} || $fallback_icon_path;
$HDNS = $group->{'dnsonly_ok'} && $group->{'dnsonly_ok'} =~ m{dns};
$HKEY = $group->{'key'};
if ( length $HEADER && $HEADER =~ m{\$LANG\{'?([^'\}]+)'?\}} ) {
$HEADER = $1;
}
$safeheader = $HEADER;
$safeheader =~ s{\s}{_}g;
$safeheader =~ s{/}{_}g;
$application_key = $HKEY;
#TODO: what is this for ???
if ( $safeheader =~ m{\AcPanel_} ) {
if ( $safeheader ne "cPanel_Cloud" ) { # exclude cpanel cloud from this “what is this for” change
$safeheader = 'cPanel';
}
}
$HEADER_URL = "/scripts/command?PFILE=$safeheader";
$slugified_header = Cpanel::StringFunc::Group::group_words($HEADER);
make_breadcrumb( $HEADER_URL, $HICON, $HEADER, $MAIN_URL, "$slugified_header" );
open $HF, '>', \$hf_buffer;
print $HF qq{
<div id="iconSea" class="panel-body icon-container-body">};
my $tmpl_if;
if ( $HADHEADER ne '-1' ) {
print $COMMAND qq{</ul></li>\n};
if ($categoryIfCondition) {
print $COMMAND "[% END -%]\n";
}
# re-initialize $categoryIfCondition to use for the next iteration
$categoryIfCondition = '';
}
if ( $group->{'group'} eq 'plugins' ) {
# The 'plugins' group is a special-case - and requires that the check
# use the "addons" flag - which translates to Whostmgr.check_flag("addons")
# in the template code.
$HADHEADER = 'addons';
}
else {
# Instead of tracking the ACL requirements for the group separately,
# we simply use the set of ACLs defined for the subitems in the group.
# This avoids problematic use cases wherein a 'subitem' requires ACLs
# that the group does not have.
my %group_acls;
foreach my $item ( @{ $group->{'items'} } ) {
my @item_acls = split /,/, $item->{'acl'};
$group_acls{$_}++ for grep { index( $_, 'ACL=' ) == 0 } @item_acls;
}
$HADHEADER = join ',', sort keys %group_acls;
}
my $add_if_statement_for_group = $HADHEADER || !$HDNS;
if ($add_if_statement_for_group) {
$tmpl_if = whmdefine_to_tmpl( $HADHEADER, $HDNS, $group );
print $CATEGORY "$tmpl_if\n";
}
# $HEADER value is marked for translation via TPDS build-tools/translations/dynamicui
print $CATEGORY <<"EOM";
[% varcache.set('locale_str',locale.makevar("$HEADER")) %]<div class="item" data-page-type="feature">
<a class="item-link" href="[% cp_security_token %]$HEADER_URL" title="[% varcache.locale_str -%]" >
<img class="itemImageWrapper" src="[% Whostmgr.get_icon_url('icons/$HICON') %]" alt="[% varcache.locale_str -%]" />
<span class="itemTextWrapper">[% varcache.locale_str %]</span>
</a>
</div>
EOM
if ($add_if_statement_for_group) {
print $CATEGORY "\n[% END -%]\n";
print $COMMAND "\n$tmpl_if\n";
$categoryIfCondition = $tmpl_if;
}
if ( $safeheader eq 'Plugins' ) {
print $HF '[% PROCESS \'plugins_icons.tmpl\' plugins_data=Whostmgr.plugins_data -%]';
}
# $HEADER value is marked for translation via TPDS build-tools/translations/dynamicui
print $COMMAND <<"EOM";
[% varcache.set('locale_str',locale.makevar("$HEADER")) %]<li id="${safeheader}" class="category expanded">
<div id="${safeheader}Header" class="categoryHeader" data-page-type="category">
<a id="$slugified_header" href="[% cp_security_token %]$HEADER_URL"
uniquekey="$slugified_header" title="[% varcache.locale_str -%]">
<img src="[% Whostmgr.get_icon_url('icons/$HICON') %]" alt="$HEADER" />
<span class="wraptext">[% varcache.locale_str -%]</span>
</a>
<div class="actionIconContainer" title="Collapse">
<div class="actionIcon"></div>
</div>
</div>
<ul id="${safeheader}Content" class="sub">
EOM
#finish up the "incumbent" header file, if there is one
if ($HF) {
#handle all the items that have been queued up
handleitems( $group->{'items'} );
#close off list of icons
print $HF "</div>\n";
close $HF;
add_wrapper_and_save( $hf_buffer, $MAIN_HF_WRAPPER, "$tmpl_path/${safeheader}.tmpl", $application_key );
undef $HF;
}
}
foreach my $directive ( @{ $dynui_data->{'raw'} } ) {
print $COMMAND $directive->{'itemdesc'};
print $COMMAND "\n";
}
if ( $HADHEADER ne '-1' ) {
print $COMMAND <<'EOM';
</ul>
</li>
EOM
if ( $HADHEADER || !$HDNS ) { # $add_if_statement_for_group ??
print $COMMAND "\n[% END -%]\n";
}
}
# end icon list
print $CATEGORY "</div>\n";
close $CATEGORY;
close $COMMAND;
close $BREADCRUMB;
add_wrapper_and_save( $hf_buffer, $MAIN_HF_WRAPPER, "$tmpl_path/${safeheader}.tmpl", $application_key );
add_wrapper_and_save( $category_buffer, $CATEGORY_WRAPPER, "$tmpl_path/category.tmpl" );
add_wrapper_and_save( $command_buffer, $COMMAND_WRAPPER, "$tmpl_path/command.tmpl" );
Whostmgr::Templates::Command::Directory::clear_cache_dir();
# Adds processed content to their respective templates
sub add_wrapper_and_save ( $content, $wrapper, $file, $key = '' ) {
$wrapper =~ s{===CONTENT===\n}{$content};
$wrapper =~ s{===key===}{$key};
open( my $write_fh, '>', $file )
or die "Couldn't open $file for writing: $!\n";
print $write_fh $wrapper;
close $write_fh;
return;
}
# Generates breadcrumbs for some links inside pages
sub handlesubitems ($items) {
foreach my $item (@$items) {
my ( $desc, $url, $icon );
$desc = $item->{'itemdesc'};
$url = $item->{'url'};
$icon = $item->{'file'};
$icon ||= $fallback_icon_path;
if ( length $desc && $desc =~ m{\$LANG\{'?([^'\}]+)'?\}} ) {
$desc = $1;
}
my $item_unique_key = ($slugified_header) ? $slugified_header . "_$slugified_item" : "";
make_breadcrumb( $url, $icon, $desc, $item->{'breadcrumb'} || (), $item_unique_key );
}
return;
}
# Generates html markup for an item in command.tmpl, category templates (Account_Functions.tmpl etc)
sub handleitem ($item) {
my $desc = $item->{'itemdesc'};
my $url = $item->{'url'};
my $icon = $item->{'file'};
my $whm_define = $item->{'acl'};
my $target = $item->{'target'};
my $dnsonly_ok = $item->{'dnsonly_ok'};
my $searchtext = $item->{'searchtext'};
my $cpanel_os_check = $item->{'cpanel_os_check'};
# The experimental flag for experimental features
my $experimental_flag = $item->{'experimental'};
if ( length $desc && $desc =~ m{\$LANG\{'?([^'\}]+)'?\}} ) {
$desc = $1;
}
$icon ||= $fallback_icon_path;
$target ||= '';
$searchtext ||= '';
$slugified_item = Cpanel::StringFunc::Group::group_words($desc);
my $key_to_compare = ($slugified_header) ? $slugified_header . "_$slugified_item" : "";
make_breadcrumb( $url, $icon, $desc, $item->{'breadcrumb'} || $HEADER_URL || (), $key_to_compare );
handlesubitems( $item->{'subitems'} );
# TODO: Why are we matching $icon =~ m{\A/}???
my $iconpath =
( $icon =~ m{\A/} )
? $icon
: "icons/$icon";
$whm_define //= '';
my $add_if_statement_for_item = $whm_define || !$dnsonly_ok || $cpanel_os_check;
if ($add_if_statement_for_item) {
my $tmpl_if = whmdefine_to_tmpl( $whm_define, $dnsonly_ok, $item, $cpanel_os_check, $experimental_flag );
print $COMMAND "\n$tmpl_if\n";
print $HF "\n$tmpl_if\n";
}
if ( $url !~ tr{:}{} ) {
$url = "[% cp_security_token %]" . $url;
}
else {
$url = $url;
}
# $desc value is marked for translation via TPDS build-tools/translations/dynamicui
print $COMMAND qq{[% varcache.set('locale_str',locale.makevar("$desc")) %]<li searchtext="$desc $searchtext [% varcache.locale_str -%]"
data-page-type="feature">
<a id="$key_to_compare" href="$url" target="$target" uniquekey="$key_to_compare" title='[% varcache.locale_str -%]'>
[% varcache.locale_str -%]
</a>
</li>\n};
print $HF <<"EOM";
[% varcache.set('locale_str',locale.makevar("$desc")) %]<div class="item" data-page-type="feature">
<a class="item-link" href="$url" target="$target" title='[% varcache.locale_str -%]'>
<img class="itemImageWrapper" src="[% Whostmgr.get_icon_url('$iconpath') %]" alt="[% varcache.locale_str -%]" />
<span class="itemTextWrapper">[% varcache.locale_str -%]</span>
</a>
</div>
EOM
if ($add_if_statement_for_item) {
print $COMMAND "[% END %]\n";
print $HF "[% END %]\n";
}
return;
}
# url, icon, description, backurl
# Inserts a single breadcrum entry into docroot/themes/x/breadcrumb
sub make_breadcrumb {
#do the map to avoid concatenating undef
return print {$BREADCRUMB} join( ':', map { $_ || '' } @_ ) . "\n";
}
# Sorts the items and processes each item in handleitem sub
sub handleitems {
my ($items) = @_;
foreach my $item (@$items) {
handleitem($item);
}
return;
}
# Defines rules for template to show and hide based on ACL, DNS only
sub whmdefine_to_tmpl ( $whmdefine, $dnsonly_ok, $item, $cpanel_os_check = undef, $experimental_flag = undef ) { ## no critic qw(ProhibitManyArgs)
my @conditions = ();
my @acls = ();
my @flags = ();
for my $piece ( split m{,}, $whmdefine ) {
if ( $piece eq 'ACL=all' ) {
push @acls, "varcache.checkacl_all";
}
elsif ( $piece =~ m{^ACL=(.*)} ) {
my $acl = "Whostmgr.checkacl('$1')";
# TODO: Remove this special case when the deprecated accesshash
# key authentication system is removed.
#
# This ties the 'manage-api-tokens' check for the 'Clusters' menu group to
# the 'allow_deprecated_accesshash' cpanel.config value to ensure that the
# empty group does not show in WHM.
if ( $item->{'group'} eq 'clusters' && $item->{groupdesc} && $1 eq 'manage-api-tokens' ) {
$acl = "(Whostmgr.checkacl('$1') && Whostmgr.check_flag('CPCONF=allow_deprecated_accesshash'))";
}
push @acls, $acl;
}
elsif ( $piece eq 'dns' ) {
$dnsonly_ok = 1;
}
# e.g. 'ea >= 4' implies 'EasyApache major version greater than or equal to 4'
elsif ( $piece =~ /^\s*ea\s*([<>=]+)\s*(\d+)\s*$/ ) {
push @flags, qq{EasyApache.get_ea_version() $1 $2};
}
else {
push @flags, "Whostmgr.check_flag('$piece')";
}
}
# add the acl & flag conditions into the common conditions array.
if ( scalar @acls > 0 ) {
push @conditions, '(' . join( ' || ', @acls ) . ')';
}
if ( scalar @flags > 0 ) {
push @conditions, '(' . join( ' && ', @flags ) . ')';
}
if ( !$dnsonly_ok ) {
push @conditions, '!varcache.dnsonly';
}
if ( length $cpanel_os_check ) {
my @checks = split( ',', $cpanel_os_check );
foreach my $check (@checks) {
my ( $k, $v ) = split( '=', $check, 2 );
push @conditions, "CPOS.check_eq('$k','$v')";
}
}
if ( $item->{role} ) {
if ( ref $item->{role} eq 'HASH' ) {
my @expvar = map { "ServerRoles.is_role_enabled('$_')" } @{ $item->{role}{roles} };
my $join = $item->{role}{match} eq 'any' ? ' || ' : ' && ';
push @conditions, '(' . join( $join, @expvar ) . ')';
}
else {
push @conditions, "ServerRoles.is_role_enabled('" . $item->{role} . "')";
}
}
if ( $item->{profile} ) {
push @conditions, "Whostmgr.check_current_profile('" . $item->{profile} . "')";
}
if ( $item->{service} ) {
if ( ref $item->{service} eq 'HASH' ) {
my @expvar = map { "Services.is_service_provided('$_')" } @{ $item->{service}{services} };
my $join = $item->{service}{match} eq 'any' ? ' || ' : ' && ';
push @conditions, '(' . join( $join, @expvar ) . ')';
}
else {
push @conditions, "Services.is_service_provided('" . $item->{service} . "')";
}
}
if ( my $minimum_accounts_needed = $item->{'minimum_accounts_needed'} ) {
#This deals with the # of cP accounts that are actually on the box.
push @conditions, "Whostmgr.minimum_accounts_needed($minimum_accounts_needed)";
#This deals with the license-allowed # of cP accounts
if ( $minimum_accounts_needed > 1 ) {
push @conditions, "Whostmgr.has_multiuser()";
}
}
if ($experimental_flag) {
push @conditions, "Whostmgr.experimental_feature_enabled('$experimental_flag')";
}
if ( $item->{'multiuser_required'} ) {
push @conditions, "Whostmgr.has_multiuser()";
}
if ( $item->{'sandbox_only'} ) {
push @conditions, "Whostmgr.is_sandbox()";
}
if ( $item->{'if_exists'} ) {
push @conditions, "Whostmgr.exists('$item->{if_exists}')";
}
# TODO: This function should return list of @conditions. Each call for this function should
# handle the template's IF statement.
return '[% IF ' . join( ' && ', @conditions ) . ' -%]';
}
Back to Directory
File Manager