Compare commits
	
		
			19 Commits
		
	
	
		
			11_0_0-9_e
			...
			11_0_0-15_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 91ca26de27 | |||
| 8b93232bbe | |||
| ed1c3e13b1 | |||
| 095a0a1499 | |||
| d16ea6a847 | |||
| e70cc67430 | |||
| b097acafab | |||
| 5d7655a709 | |||
| a58df95aa9 | |||
| 251b454470 | |||
| 174d511899 | |||
| 4be8a1411f | |||
| ba431a8a7d | |||
| 77a7849898 | |||
| fb5b0942d6 | |||
| 5edc830f9b | |||
| 473cb57a47 | |||
| 55b85496d4 | |||
| 2fd6f8b630 | 
							
								
								
									
										59
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								README.md
									
									
									
									
									
								
							| @@ -17,6 +17,59 @@ Show list of outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?compo | ||||
|  | ||||
| ## Description | ||||
|  | ||||
| <br />*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.* | ||||
| *Once it has been checked, then this comment will be deleted* | ||||
| <br /> | ||||
| The *smeserver-manager* is a web-based management interface for the SME Server (formerly known as e-smith server and gateway). SME Server is a Linux-based distribution designed for small to medium-sized enterprises, providing a wide range of network services and simplified server management. | ||||
|  | ||||
| It is based on the perl Mojolicious package. Mojolicious is a real-time web framework for Perl, which provides a range of functionalities that make it a powerful and flexible tool for web development. | ||||
|  | ||||
| ### Features | ||||
|  | ||||
| #### Web-Based Management Interface: | ||||
| smeserver-manager provides an intuitive and user-friendly web interface that allows administrators to manage various aspects of the server without needing deep technical knowledge or command-line skills. | ||||
|  | ||||
| #### User and Group Management: | ||||
| It allows you to easily add, remove, and manage user accounts and groups. The interface simplifies creating email accounts, setting passwords, and configuring user permissions. | ||||
|  | ||||
| #### Network Configuration: | ||||
| You can configures network settings such as IP addresses, DNS, DHCP, and gateway settings. The interface also provides options for setting up VPNs, remote access, and firewall rules. | ||||
|  | ||||
| #### File Sharing and Storage: | ||||
| Enables and manages file sharing services like Samba (for Windows file sharing) and NFS (for Unix/Linux file sharing). Administrators can easily create shared folders and manage permissions. | ||||
|  | ||||
| #### Email Services: | ||||
| Configure and manage email services, including setting up mail domains, user mailboxes, and SMTP/IMAP/POP3 settings. It also provides options for spam and virus filtering. | ||||
|  | ||||
| #### Web Services: | ||||
| Host and manage websites using the integrated web server (usually Apache). It supports virtual hosting, where multiple websites can be hosted on the same server. | ||||
|  | ||||
| #### Backup and Restore: | ||||
| Perform backups of essential data and server configurations. The interface provides options for scheduled backups and restoring from backup files. | ||||
|  | ||||
| #### Software Updates and Installation: | ||||
| Keep the server up-to-date with the latest security patches and software updates. The interface helps in installing and updating software packages and extensions. | ||||
|  | ||||
| #### Monitoring and Reporting: | ||||
| Monitor server performance and health. The interface provides logs, status reports, and alerts for various server components, including disk usage, network traffic, and system load. | ||||
|  | ||||
|  | ||||
| ### Installation and Access | ||||
|  | ||||
| Typically, smeserver-manager is installed by default on SME Server. To access the interface: | ||||
|  | ||||
| Open a web browser on a device connected to the same network as the SME Server. Enter the server's IP address or hostname followed by /server-manager in the address bar (e.g., https://192.168.1.1/server-manager).  | ||||
| You will be prompted to log in. Use the administrator credentials set during the SME Server installation. | ||||
|  | ||||
| ### Benefits | ||||
|  | ||||
| Simplicity: Makes it easy for non-technical users to manage a server. | ||||
| Centralized Management: Provides a single point of control for various server functionalities. | ||||
| Efficiency: Saves time and reduces complexity in server management tasks. | ||||
| Security: Regular updates and built-in security features ensure the server remains secure. | ||||
|  | ||||
| ### Considerations | ||||
|  | ||||
| Learning Curve: While designed to be user-friendly, some features may still require a basic understanding of server and network management concepts. | ||||
| Dependencies: Relies on specific packages and configurations of SME Server, and may not be directly applicable to other Linux distributions. | ||||
|  | ||||
| ### Summary | ||||
|  | ||||
| SMEserver-manager is a powerful tool that brings simplicity and efficiency to server management for small to medium-sized enterprises. By providing a centralized, web-based interface, it allows administrators to manage users, network settings, file sharing, email services, web hosting, and more, all from a single location. | ||||
| @@ -33,6 +33,8 @@ use esmith::I18N; | ||||
|  | ||||
| use Data::Dumper;	# activate if DEBUG | ||||
|  | ||||
| binmode(STDOUT, ":encoding(UTF-8)"); | ||||
|  | ||||
| my $navigation_ignore =  | ||||
| 	"(\.\.?|Swttheme\.pm|Login\.pm|Request\.pm|Modules\.pm(-.*)?)"; | ||||
|  | ||||
| @@ -46,131 +48,193 @@ my @files = grep (!/^${navigation_ignore}$/, readdir (FUNCTIONS)); | ||||
| closedir FUNCTIONS; | ||||
|  | ||||
| my @langs = $i18n->availableLanguages();  | ||||
| #my @langs = ('en', 'fr');  | ||||
| #print Dumper(\@langs); | ||||
| #my @langs = ('tr');  #Temp override | ||||
|  | ||||
|  | ||||
| foreach my $lang (@langs) | ||||
| { | ||||
|     my $long_lex = SMNGR_LIB.'/'.I18NMODULES."/General/general_$lang.lex"; | ||||
|     next unless ( -e $long_lex ); | ||||
| 	my $long_lex = SMNGR_LIB.'/'.I18NMODULES."/General/general_$lang.lex"; | ||||
| 	next unless ( -e $long_lex ); | ||||
|  | ||||
|     open(LEX, '<:encoding(UTF-8)', $long_lex) | ||||
|          or die "Couldn't open ", $long_lex, " for reading.\n"; | ||||
|     my @gen_lex = <LEX>; | ||||
|     close LEX; | ||||
| 	open(LEX, '<:encoding(UTF-8)', $long_lex) | ||||
| 		 or die "Couldn't open ", $long_lex, " for reading.\n"; | ||||
| 	my @gen_lex = <LEX>; | ||||
| 	close LEX; | ||||
|  | ||||
|     foreach my $file (@files) | ||||
|     { | ||||
| 	next if (-d SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file"); | ||||
| #        next unless ( $file =~ m/D.*\.pm$/ ); | ||||
|         next unless ( $file =~ m/[A-Z].*\.pm$/ ); | ||||
|  | ||||
| 	my $file2 = lc($file); | ||||
| 	$file2 =~ s/\.pm$//; | ||||
|  | ||||
|     #--------------------------------------------------  | ||||
|     # extract heading, description and weight information | ||||
|     # from Mojo controller | ||||
|     #--------------------------------------------------  | ||||
| 	open(SCRIPT, SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file"); | ||||
|         my $heading            	= undef; | ||||
|         my $description        	= undef; | ||||
|         my $heading_weight     	= undef; | ||||
|         my $description_weight 	= undef; | ||||
|         my $menucat		= undef; | ||||
|         my $routes		= undef; | ||||
|  | ||||
|         while ( <SCRIPT> ) | ||||
| 	#my @files = ('Portforwarding.pm');  #Temp override | ||||
| 	foreach my $file (@files) | ||||
| 	{ | ||||
| 	    $heading = $1 if (/^\s*#\s*heading\s*:\s*(.+?)\s*$/); | ||||
| 	    $description = $1  | ||||
| 		if (/^\s*#\s*description\s*:\s*(.+?)\s*$/); | ||||
| 	    ($heading_weight, $description_weight) = ($1, $2)  | ||||
| 		if (/^\s*#\s*navigation\s*:\s*(\d+?)\s+(\d+?)\s*$/); | ||||
| 	    $menucat = $1  | ||||
| 		if (/^\s*#\s*menu\s*:\s*(.+?)\s*$/); | ||||
| 		next if (-d SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file"); | ||||
| 		#        next unless ( $file =~ m/D.*\.pm$/ ); | ||||
| 			next unless ( $file =~ m/[A-Z].*\.pm$/ ); | ||||
|  | ||||
| 	    last if (defined $heading and  | ||||
| 		defined $description and | ||||
| 		defined $heading_weight and | ||||
| 		defined $description_weight and | ||||
| 		defined $menucat); | ||||
| 		my $file2 = lc($file); | ||||
| 		$file2 =~ s/\.pm$//; | ||||
| 		#--------------------------------------------------  | ||||
| 		# extract heading, description and weight information | ||||
| 		# from Mojo controller | ||||
| 		#--------------------------------------------------  | ||||
| 		open(SCRIPT, SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file"); | ||||
| 		my $heading            	= undef; | ||||
| 		my $description        	= undef; | ||||
| 		my $heading_weight     	= undef; | ||||
| 		my $description_weight 	= undef; | ||||
| 		my $menucat		= undef; | ||||
| 		my $routes		= undef; | ||||
|  | ||||
| 	    # routes : end  (stop before eof if 'menu' is not here before 'routes'!!! | ||||
| 	    $routes = $1 if (/^\s*#\s*routes\s*:\s*(.+?)\s*$/); | ||||
| 	    last if (defined $routes and $routes eq 'end'); | ||||
| 		while ( <SCRIPT> ) | ||||
| 		{ | ||||
| 			$heading = $1 if (/^\s*#\s*heading\s*:\s*(.+?)\s*$/); | ||||
| 			$description = $1  | ||||
| 			if (/^\s*#\s*description\s*:\s*(.+?)\s*$/); | ||||
| 			($heading_weight, $description_weight) = ($1, $2)  | ||||
| 			if (/^\s*#\s*navigation\s*:\s*(\d+?)\s+(\d+?)\s*$/); | ||||
| 			$menucat = $1  | ||||
| 			if (/^\s*#\s*menu\s*:\s*(.+?)\s*$/); | ||||
|  | ||||
| 			last if (defined $heading and  | ||||
| 			defined $description and | ||||
| 			defined $heading_weight and | ||||
| 			defined $description_weight and | ||||
| 			defined $menucat); | ||||
|  | ||||
| 			# routes : end  (stop before eof if 'menu' is not here before 'routes'!!! | ||||
| 			$routes = $1 if (/^\s*#\s*routes\s*:\s*(.+?)\s*$/); | ||||
| 			last if (defined $routes and $routes eq 'end'); | ||||
| 		} | ||||
| 		close SCRIPT; | ||||
|  | ||||
| 		print "updating script $file for lang $lang\n"if DEBUG; | ||||
| 		my $navdb = $navdbs{$lang}; | ||||
| 		my $navinfo = NAVDIR.'/'.NAVIGATIONDIR . "/navigation.$lang"; | ||||
| 		$navdb ||= esmith::NavigationDB->open($navinfo); | ||||
| 		$navdb ||= esmith::NavigationDB->create($navinfo) or | ||||
| 			die "Couldn't create $navinfo\n"; | ||||
| 			$navdbs{$lang} ||= $navdb; | ||||
| 		my $rec = $navdb->get($file2) ||  | ||||
| 			$navdb->new_record($file2, { type => 'panel' } ); | ||||
| 		 | ||||
| 		my @panel_lex = (); | ||||
| 		$long_lex = SMNGR_LIB.'/'.I18NMODULES.'/'.ucfirst($file2)."/${file2}_$lang.lex"; | ||||
| 		if ( -e $long_lex ) { | ||||
| 			open(LEX, '<:encoding(UTF-8)', $long_lex) | ||||
| 				 or die "Couldn't open ", $long_lex, " for reading.\n"; | ||||
| 			@panel_lex = <LEX>; | ||||
| 			close LEX; | ||||
| 		} | ||||
| 		#Extract the prefix for this module | ||||
| 		my @keys = values @panel_lex;  # Get all values from the array | ||||
| 		 | ||||
| 		my $i = 0;                    # Initialize the index | ||||
| 		my $found = 0;                # Flag to check if the prefix was found | ||||
| 		my $prefix = "xx_";			  # Probably never match!! | ||||
|  | ||||
| 		while ($i < @keys) {          # Loop until we run out of entries | ||||
| 			my $extracted_value = $keys[$i] || "";  # The current entry | ||||
| 			#print("Extracted val: ".$extracted_value."\n"); | ||||
|  | ||||
| 			# Extract prefix from the second value (up to and including the first underscore) | ||||
| 			#my ($prefix) = $second_value =~ /^'(.*?_)/;  # Match everything up to and including the first underscore | ||||
| 			($prefix) = $extracted_value =~ /^'(.*?_)/;  # Match everything up to and including the first underscore | ||||
| 			 | ||||
| 			if (defined $prefix) { | ||||
| 				$found = 1;           # Set found flag to true | ||||
| 				last;                 # Exit the loop if prefix is found | ||||
| 			} else { | ||||
| 				#print("Extracted Val: " . $extracted_value . "\n"); | ||||
| 			} | ||||
|  | ||||
| 			$i++;                     # Increment the index to check the next entry | ||||
| 		} | ||||
|  | ||||
| 		if (!$found) { | ||||
| 			print(STDERR "No valid prefix found in any entries: ".$file2." (".$lang.")\n"); # if DEBUG; | ||||
| 			$prefix = "xx_";			  # Probably never match!! | ||||
| 			 | ||||
| 		} | ||||
| 		#print("Prefix: ".$prefix." ".$file2." (".$lang.")\n"); | ||||
| 		 | ||||
| 		my %Lexicon = (); | ||||
| 		push(@panel_lex, @gen_lex); | ||||
| 		my $top_error = 0; | ||||
|  | ||||
| 		chomp @panel_lex; | ||||
| 		for (@panel_lex) { | ||||
| 			next unless $_;	# first one empty | ||||
| 			my ($k, $v) = split / => /, $_; | ||||
| 		#	errors on split to $v (use DEBUG to see) | ||||
| 			if ( $k and $v ) { | ||||
| 				$k =~ s/\'//g; | ||||
| 				$v =~ s/\'//g; | ||||
| 				$v =~ s/,$//g; | ||||
| 				$Lexicon{ lc($k) } = $v; | ||||
| 			} else { | ||||
| 				$k = "?" unless ($k); | ||||
| 				print STDERR "Error for $lang $file2 on $k \n" if DEBUG; | ||||
| 				$top_error++; | ||||
| 			} | ||||
| 		} | ||||
| 		if ( $top_error > 0) { | ||||
| 			if ( DEBUG ) { | ||||
| 				print STDERR "$top_error errors for $lang $file2\n"; | ||||
| 				#		print Dumper(\@panel_lex); | ||||
| 				#		print Dumper(\%Lexicon); | ||||
| 				#		exit 1; | ||||
| 			} | ||||
| 		} | ||||
| 		$heading = "" unless defined $heading; | ||||
| 		$description = "" unless defined $description; | ||||
| 		# Get the base language code from $lang | ||||
| 		my $base_lang = (split('-', $lang))[0]; | ||||
| 		my $loc_heading =  process_localization( \%Lexicon, $heading, $lang, $prefix ); | ||||
| 		my $loc_description =  process_localization( \%Lexicon, $description, $lang, $prefix ); | ||||
| 		$loc_heading =~ s/^\s*(\w.*?)\s*$/$1/; | ||||
| 		$loc_description =~ s/^\s*(\w.*?)\s*$/$1/; | ||||
|  | ||||
| 		$rec->merge_props( | ||||
| 			Heading => $loc_heading, | ||||
| 			Description => $loc_description, | ||||
| 			HeadingWeight => localise( \%Lexicon, $heading_weight ), | ||||
| 			DescriptionWeight => localise( \%Lexicon, $description_weight ), | ||||
| 			MenuCat => (defined $menucat ? $menucat : 'A')); | ||||
| 	} | ||||
| 	close SCRIPT; | ||||
|  | ||||
| 	print "updating script $file for lang $lang\n" if DEBUG; | ||||
| 	#warn "trying to close for lang $lang\n"; | ||||
| 	my $navdb = $navdbs{$lang}; | ||||
| 	my $navinfo = NAVDIR.'/'.NAVIGATIONDIR . "/navigation.$lang"; | ||||
| 	$navdb ||= esmith::NavigationDB->open($navinfo); | ||||
| 	$navdb ||= esmith::NavigationDB->create($navinfo) or | ||||
| 	    die "Couldn't create $navinfo\n"; | ||||
|         $navdbs{$lang} ||= $navdb; | ||||
| 	my $rec = $navdb->get($file2) ||  | ||||
| 	    $navdb->new_record($file2, { type => 'panel' } ); | ||||
|  | ||||
| 	my @panel_lex = (); | ||||
| 	$long_lex = SMNGR_LIB.'/'.I18NMODULES.'/'.ucfirst($file2)."/${file2}_$lang.lex"; | ||||
| 	if ( -e $long_lex ) { | ||||
| 	    open(LEX, '<:encoding(UTF-8)', $long_lex) | ||||
|     		 or die "Couldn't open ", $long_lex, " for reading.\n"; | ||||
| 	    @panel_lex = <LEX>; | ||||
| 	    close LEX; | ||||
| 	} | ||||
|  | ||||
| 	my %Lexicon = (); | ||||
| 	push(@panel_lex, @gen_lex); | ||||
| 	my $top_error = 0; | ||||
|  | ||||
| 	chomp @panel_lex; | ||||
| 	for (@panel_lex) { | ||||
| 	    next unless $_;	# first one empty | ||||
| 	    my ($k, $v) = split / => /, $_; | ||||
| #	errors on split to $v (use DEBUG to see) | ||||
| 	    if ( $k and $v ) { | ||||
| 		$k =~ s/\'//g; | ||||
| 		$v =~ s/\'//g; | ||||
| 		$v =~ s/,$//g; | ||||
| 		$Lexicon{ $k } = $v; | ||||
| 	    } else { | ||||
| 		$k = "?" unless ($k); | ||||
| 		print STDERR "Error for $lang $file2 on $k \n" if DEBUG; | ||||
| 		$top_error++; | ||||
| 	    } | ||||
| 	} | ||||
| 	if ( $top_error > 0) { | ||||
| 	    if ( DEBUG ) { | ||||
| 	        print STDERR "$top_error errors for $lang $file2\n"; | ||||
| #		print Dumper(\@panel_lex); | ||||
| #		print Dumper(\%Lexicon); | ||||
| #		exit 1; | ||||
| 	    } | ||||
| 	} | ||||
|  | ||||
| 	my $loc_heading =  localise( \%Lexicon, $heading ); | ||||
| 	my $loc_description =  localise( \%Lexicon, $description ); | ||||
| 	$loc_heading =~ s/^\s*(\w.*?)\s*$/$1/; | ||||
| 	$loc_description =~ s/^\s*(\w.*?)\s*$/$1/; | ||||
|  | ||||
| 	$rec->merge_props( | ||||
| 	    Heading => $loc_heading, | ||||
| 	    Description => $loc_description, | ||||
| 	    HeadingWeight => localise( \%Lexicon, $heading_weight ), | ||||
| 	    DescriptionWeight => localise( \%Lexicon, $description_weight ), | ||||
| 	    MenuCat => (defined $menucat ? $menucat : 'A')); | ||||
|     } | ||||
|     #warn "trying to close for lang $lang\n"; | ||||
|     my $navdb = $navdbs{$lang}; | ||||
|     $navdb->close(); | ||||
| 	$navdb->close(); | ||||
| } | ||||
|  | ||||
|  | ||||
| sub localise { | ||||
|     my ($lexicon, $string) = @_; | ||||
|     #print("Looking up:".$string."\n"); | ||||
|     $string  = "" unless defined $string; | ||||
|     return $lexicon->{$string} || $string; | ||||
|     my $lc_string = lc($string); | ||||
|     my $res = $lexicon->{$lc_string} || $string; | ||||
|     #print("Returning:".$res."\n"); | ||||
|     return $res; | ||||
| } | ||||
|  | ||||
| # Subroutine to process localization | ||||
| sub process_localization { | ||||
|     my ($lexicon_ref, $heading, $lang, $prefix) = @_; | ||||
|  | ||||
|     # Localized heading based on original heading | ||||
|     my $loc_heading = localise($lexicon_ref, $heading); | ||||
|  | ||||
|     # Get the base language code from $lang | ||||
|     my $base_lang = (split('-', $lang))[0]; | ||||
|  | ||||
|     # Check the condition | ||||
|     if ($loc_heading eq $heading && $base_lang ne 'en') { | ||||
|         # Construct the new key by combining the prefix and the original heading | ||||
|         my $key = $prefix . $heading; | ||||
|         # Localize using the constructed key | ||||
|         $loc_heading = localise($lexicon_ref, $key); | ||||
|         # See if it got a hit | ||||
|         if ($loc_heading eq $key){ | ||||
| 			$loc_heading = $heading; | ||||
| 		} | ||||
|     } | ||||
|      | ||||
|     return $loc_heading; # Optionally return the localized heading | ||||
| } | ||||
|   | ||||
| @@ -234,7 +234,7 @@ a.menu-title { | ||||
|     width: 100%; | ||||
| } | ||||
| #h2e11 { | ||||
|     width: 70%; | ||||
|     width: 50%; | ||||
|     float: left; | ||||
| } | ||||
| #h2e12 { | ||||
| @@ -257,9 +257,9 @@ a.menu-title { | ||||
|     width: 70%; | ||||
| } | ||||
|  | ||||
| #h2e22,#h2e23 { | ||||
| #h2e22,#h2e23,#h2e12 { | ||||
|     float: left; | ||||
|     width: 10%; | ||||
|     width: 14em; | ||||
|     text-align: center; | ||||
| } | ||||
|  | ||||
| @@ -273,6 +273,7 @@ a.menu-title { | ||||
|     left: 2px; | ||||
| } | ||||
|  | ||||
|  | ||||
| /*end*/ | ||||
| EOF | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,27 @@ | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|   const flagContainer = document.getElementById('flag-container'); | ||||
|  | ||||
|   // Function to get the browser's locale | ||||
|   function getBrowserLocale() { | ||||
|     return navigator.language || navigator.userLanguage; | ||||
|   } | ||||
|  | ||||
|   // Function to map locale to country code | ||||
|   function getCountryCodeFromLocale(locale) { | ||||
|     const localeParts = locale.split('-'); | ||||
|     return localeParts.length > 1 ? localeParts[1] : localeParts[0]; | ||||
|   } | ||||
|  | ||||
|   // Function to create and display the flag icon | ||||
|   function displayFlagIcon(countryCode) { | ||||
|     const flagIcon = document.createElement('span'); | ||||
|     flagIcon.className = `flag-icon flag-icon-${countryCode.toLowerCase()}`; | ||||
|     flagIcon.id = 'flag-icon'; | ||||
|     flagContainer.appendChild(flagIcon); | ||||
|   } | ||||
|  | ||||
|   // Main logic | ||||
|   const locale = getBrowserLocale(); | ||||
|   const countryCode = getCountryCodeFromLocale(locale); | ||||
|   displayFlagIcon(countryCode); | ||||
| }); | ||||
| @@ -29,8 +29,8 @@ our %dbs; | ||||
|  | ||||
| for ( qw(available installed updates) ) | ||||
| { | ||||
|     $dbs{$_} = esmith::ConfigDB->open_ro("yum_$_") or | ||||
| 	die "Couldn't open yum_$_ DB\n"; | ||||
|     $dbs{$_} = esmith::ConfigDB->open_ro("dnf_$_") or | ||||
| 	die "Couldn't open dnf_$_ DB\n"; | ||||
| } | ||||
|  | ||||
| for ( qw(repositories) ) | ||||
| @@ -55,7 +55,7 @@ sub main { | ||||
|     if ( -e "/var/run/yum.pid" ) { | ||||
| 	$yum_datas{'trt'} = 'LOGF'; | ||||
| 	$dest = 'yumlogfile'; | ||||
|     } elsif ($cdb->get_prop('yum', 'LogFile')) { | ||||
|     } elsif ($cdb->get_prop('dnf', 'LogFile')) { | ||||
| 	$yum_datas{'trt'} = 'PSTU'; | ||||
| 	$yum_datas{'reconf'} = $cdb->get_value('UnsavedChanges', 'yes'); | ||||
| 	$dest = 'yumpostupg'; | ||||
| @@ -85,7 +85,7 @@ sub do_display { | ||||
|     # force $trt if current logfile | ||||
|     if ( -e "/var/run/yum.pid" ) { | ||||
| 	$trt = 'LOGF'; | ||||
|     } elsif ($cdb->get_prop('yum', 'LogFile')) { | ||||
|     } elsif ($cdb->get_prop('dnf', 'LogFile')) { | ||||
| 	$trt = 'PSTU'; | ||||
|     } | ||||
|  | ||||
| @@ -112,7 +112,7 @@ sub do_display { | ||||
| 	} | ||||
| 	 | ||||
|         if ( $trt eq 'PSTU') { | ||||
| 	    if ($cdb->get_prop('yum', 'LogFile')) { | ||||
| 	    if ($cdb->get_prop('dnf', 'LogFile')) { | ||||
| 		$dest = 'yumpostupg'; | ||||
| 		$yum_datas{'reconf'} = $cdb->get_value('UnsavedChanges', 'yes'); | ||||
| 	    } | ||||
| @@ -289,7 +289,7 @@ sub package_functions_enabled { | ||||
|  | ||||
|     my ($c) = @_; | ||||
|  | ||||
|     return ($cdb->get_prop("yum", "PackageFunctions") eq "enabled"); | ||||
|     return ($cdb->get_prop("dnf", "PackageFunctions") eq "enabled"); | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -298,7 +298,7 @@ sub get_status { | ||||
|  | ||||
|     my ($c, $prop, $localise) = @_; | ||||
|  | ||||
|     my $status = $cdb->get_prop("yum", $prop) || 'disabled'; | ||||
|     my $status = $cdb->get_prop("dnf", $prop) || 'disabled'; | ||||
|  | ||||
|     return $status unless $localise; | ||||
|  | ||||
| @@ -433,7 +433,7 @@ sub change_settings { | ||||
| 			PackageFunctions | ||||
|             	) ) | ||||
|     { | ||||
| 	$cdb->set_prop('yum', $param, $c->param("yum_$param")); | ||||
| 	$cdb->set_prop("dnf", $param, $c->param("yum_$param")); | ||||
|     } | ||||
|  | ||||
|     my $check4updates = $c->param("yum_check4updates"); | ||||
| @@ -441,21 +441,21 @@ sub change_settings { | ||||
|  | ||||
|     if ($check4updates ne 'disabled') { $status = 'enabled'; } | ||||
|  | ||||
|     $cdb->set_prop('yum', 'check4updates', $check4updates); | ||||
|     $cdb->set_prop("dnf", 'check4updates', $check4updates); | ||||
|  | ||||
|     my $deltarpm = $c->param("yum_DeltaRpmProcess"); | ||||
|     $cdb->set_prop('yum', 'DeltaRpmProcess', $deltarpm); | ||||
|     $cdb->set_prop("dnf", 'DeltaRpmProcess', $deltarpm); | ||||
|  | ||||
|     my $downloadonly = $c->param("yum_DownloadOnly"); | ||||
|     if ($downloadonly ne 'disabled') { $status = 'enabled'; } | ||||
|  | ||||
|     $cdb->set_prop('yum', 'DownloadOnly', $downloadonly); | ||||
|     $cdb->set_prop("dnf", 'DownloadOnly', $downloadonly); | ||||
|  | ||||
|     my $AutoInstallUpdates = $c->param("yum_AutoInstallUpdates"); | ||||
|     if ($AutoInstallUpdates ne 'disabled') { $status = 'enabled'; } | ||||
|  | ||||
|     $cdb->set_prop('yum', 'AutoInstallUpdates', $AutoInstallUpdates); | ||||
|     $cdb->set_prop('yum', 'status', $status); | ||||
|     $cdb->set_prop("dnf", 'AutoInstallUpdates', $AutoInstallUpdates); | ||||
|     $cdb->set_prop("dnf", 'status', $status); | ||||
|  | ||||
|     my %selected = map {$_ => 1} @{$c->every_param('SelectedRepositories')}; | ||||
|  | ||||
| @@ -469,7 +469,7 @@ sub change_settings { | ||||
|  | ||||
|     $dbs{repositories}->reload; | ||||
|  | ||||
|     unless ( system( "/sbin/e-smith/signal-event", "yum-modify" ) == 0 ) | ||||
|     unless ( system( "/sbin/e-smith/signal-event", "dnf-modify" ) == 0 ) | ||||
|     { | ||||
| 	return $c->l('yum_ERROR_UPDATING_CONFIGURATION'); | ||||
|     } | ||||
| @@ -484,11 +484,11 @@ sub do_yum { | ||||
|  | ||||
|     for ( qw(SelectedGroups SelectedPackages) ) | ||||
|     { | ||||
| 	$cdb->set_prop("yum", $_, join(',', (@{$c->every_param($_)} ))); | ||||
| 	$cdb->set_prop("dnf", $_, join(',', (@{$c->every_param($_)} ))); | ||||
|     } | ||||
|  | ||||
|     esmith::util::backgroundCommand(0, | ||||
|         "/sbin/e-smith/signal-event", "yum-$function"); | ||||
|         "/sbin/e-smith/signal-event", "DNF-$function"); | ||||
|  | ||||
|     for ( qw(available installed updates) ) { | ||||
| 	$dbs{$_}->reload; | ||||
| @@ -517,7 +517,7 @@ sub format_yum_log { | ||||
|  | ||||
|     $cdb->reload; | ||||
|  | ||||
|     my $filepage = $cdb->get_prop('yum', 'LogFile'); | ||||
|     my $filepage = $cdb->get_prop('dnf', 'LogFile'); | ||||
|     return '' unless $filepage and ( -e "$filepage" ); | ||||
|  | ||||
|     my $out = sprintf "<PRE>"; | ||||
| @@ -537,7 +537,7 @@ sub post_upgrade_reboot { | ||||
|  | ||||
|     my $c = shift; | ||||
|  | ||||
|     $cdb->get_prop_and_delete('yum', 'LogFile'); | ||||
|     $cdb->get_prop_and_delete('dnf', 'LogFile'); | ||||
|     $cdb->reload; | ||||
|  | ||||
|     if (fork == 0) { | ||||
| @@ -552,7 +552,7 @@ sub post_upgrade_reboot { | ||||
| sub show_yum_log { | ||||
|     my $c = shift; | ||||
|     my $out = $c->format_yum_log(); | ||||
|     my $yum_log = $cdb->get_prop_and_delete('yum', 'LogFile'); | ||||
|     my $yum_log = $cdb->get_prop_and_delete('dnf', 'LogFile'); | ||||
|     return $out; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,63 @@ | ||||
| document.addEventListener('DOMContentLoaded', () => { | ||||
|   const flagContainer = document.getElementById('flag-container'); | ||||
|  | ||||
|   // Function to get the browser's locale | ||||
|   function getBrowserLocale() { | ||||
|     return navigator.language || navigator.userLanguage; | ||||
|   } | ||||
|  | ||||
|   // Function to map locale to country code | ||||
|   function getCountryCodeFromLocale(locale) { | ||||
|     const localeParts = locale.split('-'); | ||||
|     return localeParts.length > 1 ? localeParts[1] : localeParts[0]; | ||||
|   } | ||||
|  | ||||
|   // Function to fetch country names from a CDN | ||||
|   async function fetchCountryNames() { | ||||
|     const response = await fetch('https://restcountries.com/v3.1/all'); | ||||
|     const countries = await response.json(); | ||||
|     const countryNames = {}; | ||||
|     for (const country of countries) { | ||||
|       const code = country.cca2.toLowerCase(); // Country code (ISO 3166-1 alpha-2) | ||||
|       const name = country.name.common; // Common name of the country | ||||
|       countryNames[code] = name; | ||||
|     } | ||||
|     return countryNames; | ||||
|   } | ||||
|  | ||||
|   // Function to create and display the flag icon | ||||
|   function displayFlagIcon(countryCode, countryName) { | ||||
|     const flagIcon = document.createElement('span'); | ||||
|     flagIcon.className = `flag-icon flag-icon-${countryCode.toLowerCase()}`; | ||||
|     flagIcon.id = 'flag-icon'; | ||||
|     flagIcon.title = countryName; // Set the title for the tooltip | ||||
|  | ||||
|     // If you want a custom tooltip instead (uncomment the lines below): | ||||
|     /* | ||||
|     const tooltip = document.createElement('span'); | ||||
|     tooltip.className = 'tooltip'; | ||||
|     tooltip.innerText = countryName; | ||||
|     flagIcon.appendChild(tooltip); | ||||
|  | ||||
|     flagIcon.addEventListener('mouseenter', () => { | ||||
|       tooltip.style.display = 'block'; | ||||
|     }); | ||||
|  | ||||
|     flagIcon.addEventListener('mouseleave', () => { | ||||
|       tooltip.style.display = 'none'; | ||||
|     }); | ||||
|     */ | ||||
|  | ||||
|     flagContainer.appendChild(flagIcon); | ||||
|   } | ||||
|  | ||||
|   // Main logic | ||||
|   (async () => { | ||||
|     const locale = getBrowserLocale(); | ||||
|     const countryCode = getCountryCodeFromLocale(locale); | ||||
|     const countryNames = await fetchCountryNames(); // Fetch country names | ||||
|  | ||||
|     const countryName = countryNames[countryCode.toLowerCase()] || 'Unknown Country'; // Get the country name | ||||
|     displayFlagIcon(countryCode, countryName); // Display the flag with country name | ||||
|   })(); | ||||
| }); | ||||
| @@ -31,7 +31,9 @@ | ||||
| 	%= javascript '/js/vfs_fonts.js' | ||||
| 	%= javascript '/js/buttons.html5.min.js' | ||||
| 	%= javascript '/js/buttons.print.min.js' | ||||
| 	%= javascript '/js/flag-by-locale.js' | ||||
|  | ||||
| 	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.5.0/css/flag-icon.min.css"> | ||||
| 	%= stylesheet '/css/sme-jquery-overrides.css' | ||||
|  | ||||
| </head> | ||||
|   | ||||
| @@ -1,27 +1,128 @@ | ||||
| <style> | ||||
| #h2l1 { | ||||
|     display: flex;                  /* Use flexbox layout */ | ||||
|     justify-content: space-between; /* Space between child elements */ | ||||
|     align-items: center;           /* Center items vertically */ | ||||
| } | ||||
|  | ||||
| #h2e11 { | ||||
|     flex: 1;                       /* Allow the first div to take available space on the left */ | ||||
| } | ||||
|  | ||||
| #h2e12 {  | ||||
|     display: flex;                 /* Make this div a flex container */ | ||||
|     align-items: center;           /* Vertically center content in this div */ | ||||
|     margin-left: 20px;            /* Add margin to the left of this div */ | ||||
| } | ||||
|  | ||||
| #flag-container { | ||||
|     display: flex;                 /* Make this div a flex container */ | ||||
|     align-items: center;           /* Vertically center content in this div */ | ||||
|     margin-left: 20px;             /* Add margin to the left of the flag container */ | ||||
|     padding-right: 20px;           /* Add padding to the right side of the flag container */ | ||||
| } | ||||
|  | ||||
| .flag-icon { | ||||
|     width: 43px; | ||||
|     font-size: 20px; | ||||
| } | ||||
|  | ||||
| #legacy-button button { | ||||
|     background-color: #98d36e; /* Button background color */ | ||||
|     font-weight: lighter;      /* Lighter text for the button */ | ||||
|     color: #063;               /* Button text color */ | ||||
|     padding: 5px 10px;         /* Padding for the button */ | ||||
|     border: none;              /* Remove default button border */ | ||||
|     border-radius: 4px;        /* Rounded corners for button */ | ||||
|     cursor: pointer;           /* Change cursor on hover */ | ||||
| } | ||||
|  | ||||
| #legacy-button button:hover { | ||||
|     background-color: #82c961; /* Change color on hover */ | ||||
| } | ||||
|  | ||||
| .infobar { | ||||
|     display: flex;                  /* Use flexbox for alignment */ | ||||
|     justify-content: space-between; /* Space between child elements */ | ||||
|     align-items: center;            /* Center items vertically */ | ||||
|     padding: 10px;                  /* Adjust padding as desired */ | ||||
| } | ||||
|  | ||||
| #h2e21 { | ||||
|     flex: 1;                        /* Allow the first div to take available space on the left */ | ||||
| } | ||||
|  | ||||
| #h2e22 { | ||||
|     display: flex;                  /* Make this div a flex container */ | ||||
|     justify-content: center;        /* Center the help button */ | ||||
|     align-items: center;            /* Center vertically */ | ||||
|     flex: none;                    /* Prevent this div from growing */ | ||||
|     position: relative;             /* Relative position for centering */ | ||||
|     width: 100px;                  /* Set a width for the help button container */ | ||||
| } | ||||
|  | ||||
| #h2e23 { | ||||
|     margin-left: auto;              /* Push the third div to the right */ | ||||
| } | ||||
|  | ||||
| .login-button { | ||||
|     background-color: #98d36e;     /* Button background color */ | ||||
|     font-weight: bold;              /* Bold text */ | ||||
|     xxcolor: #ffffff;                 /* Button text color */ | ||||
|     padding: 8px 12px;              /* Adjust padding for button height */ | ||||
|     border: none;                   /* Remove default border */ | ||||
|     border-radius: 4px;             /* Rounded corners */ | ||||
|     cursor: pointer;                /* Change cursor on hover */ | ||||
| } | ||||
|  | ||||
| .login-button:hover { | ||||
|     background-color: #82c961;      /* Change color on hover */ | ||||
| } | ||||
|  | ||||
| #help-button { | ||||
|     text-decoration: none;          /* Remove underline from link */ | ||||
|     font-size: 20px;                /* Adjust font size as needed */ | ||||
|     padding: 8px 12px;              /* Add padding to the help link */ | ||||
|     background-color: #98d36e;      /* Background for visibility */ | ||||
|     border-radius: 4px;             /* Rounded corners */ | ||||
|     color: #000;                    /* Button text color */ | ||||
| } | ||||
|  | ||||
| #help-button:hover { | ||||
|     background-color: #82c961;      /* Change background on hover */ | ||||
| } | ||||
| </style> | ||||
|  | ||||
| <div id="header2" class="hd2"> | ||||
|     <div id="h2l1">  | ||||
| 	<div id="h2e11"> | ||||
| 	    <a target='_blank' href="http://www.koozali.org"><img src="images/smeserver_logo.jpg" height="40" alt="SME Server"></a> | ||||
| 	</div> | ||||
| <!--        <div id="h2e12"><h5><a href="initial">Server Manager</a> | ||||
|             <a href="/server-manager" target='_blank'>    (Prev SM)</a></h5> -->            | ||||
|         <div id="h2e12" style="float:right;"><br><a href="/server-manager" target='_blank'><button style="background-color:#98d36e;font-weight:bold;color:#063;">Legacy SM</button></a></div> | ||||
|     </div> | ||||
| 		<div id="h2e11"> | ||||
| 			<a target='_blank' href="http://www.koozali.org"><img src="images/smeserver_logo.jpg" height="40" alt="SME Server"></a> | ||||
| 		</div>  | ||||
|  | ||||
|     <div id="h2l2" class="infobar">  | ||||
| 	<div id="h2e21"> | ||||
|         <b> | ||||
|         <%= session 'SystemName' %>@<%= session 'DomainName' %></b>  | ||||
| 	</div> | ||||
|         <div id="h2e22"> | ||||
|           <a target="_parent" href="manual">  <b> ? </b>  </a>  | ||||
| 	</div> | ||||
| 	<div id="h2e23"> | ||||
| %    if ( not defined $c->session->{username} ) { | ||||
|           <a target="_parent" href="login"><b>Login</b></a>  | ||||
| %    } else { | ||||
|           <a target="_parent" href="logout"><b><%= $c->session->{username} %> Logout</b></a>  | ||||
| %    } | ||||
| 	</div> | ||||
| 		<div id="h2e22"> | ||||
| 			<a id="help-button" target="_parent" href="manual"><button> ? </button></a> | ||||
| 		</div> | ||||
|      | ||||
|         <div id="h2e12"> | ||||
| 			<a id="legacy-button" href="/server-manager" target='_blank'><button>Legacy SM</button></a> | ||||
|         </div> | ||||
| 		<div id="h2e23"> | ||||
| 			% if ( not defined $c->session->{username} ) { | ||||
| 				<a target="_parent" href="login"><button class="login-button">Login</button></a> | ||||
| 			% } else { | ||||
| 				<a target="_parent" href="logout"><button class="login-button"><%= $c->session->{username} %> Logout</button></a> | ||||
| 			% } | ||||
| 		</div> | ||||
| 		<div id="flag-container"> | ||||
| 			<!-- The flag icon will be inserted here --> | ||||
| 		</div> | ||||
|     </div> | ||||
| 	<div id="h2l2" class="infobar">  | ||||
| 		<div id="h2e21"> | ||||
| 			<b> | ||||
| 				<%= session 'SystemName' %>@<%= session 'DomainName' %></b>  | ||||
| 		</div> | ||||
| 		 | ||||
| 		 | ||||
| 	</div> | ||||
| </div> | ||||
|   | ||||
| @@ -2,7 +2,7 @@ Summary: Sme server  navigation module : manager 2 | ||||
| %define name smeserver-manager | ||||
| Name: %{name} | ||||
| %define version 11.0.0 | ||||
| %define release 9 | ||||
| %define release 15 | ||||
| Version: %{version} | ||||
| Release: %{release}%{?dist} | ||||
| License: GPL | ||||
| @@ -108,6 +108,25 @@ true | ||||
| %defattr(-,root,root) | ||||
|  | ||||
| %changelog | ||||
| * Wed Aug 21 2024 Brian Read <brianr@koozali.org> 11.0.0-15.sme | ||||
| - Migrate SM2 Software installer panel from use of yum to dnf [SME: 12718] | ||||
|  | ||||
| * Sun Jul 28 2024 Brian Read <brianr@koozali.org> 11.0.0-14.sme | ||||
| - Version skipped due to operator error! [SME: <none> ] | ||||
|  | ||||
| * Sun Jul 28 2024 Brian Read <brianr@koozali.org> 11.0.0-13.sme | ||||
| - Fix sysles.css template - overwrote it by mistake [SME: 12706] | ||||
| - Also re-organised login and Legacy SM menus and help on top | ||||
|  | ||||
| * Sun Jul 28 2024 Brian Read <brianr@koozali.org> 11.0.0-12.sme | ||||
| - correct positio of flag-icon [SME: 12706] | ||||
|  | ||||
| * Sat Jul 27 2024 Brian Read <brianr@koozali.org> 11.0.0-11.sme | ||||
| - Add in flag icon indication of locale [SME: 12706] | ||||
|  | ||||
| * Fri Jul 26 2024 Brian Read <brianr@koozali.org> 11.0.0-10.sme | ||||
| - fix navigation2.conf to more correctly translate menus [SME: 12714] | ||||
|  | ||||
| * Thu May 09 2024 Brian Read <brianr@koozali.org> 11.0.0-9.sme | ||||
| - Add mojo logo to footer [SME: 12679] | ||||
| - Fix default for HeaderWeight to avoid noise in logs if no Nav header in file | ||||
|   | ||||
		Reference in New Issue
	
	Block a user