#! /usr/bin/perl

=head1 NAME

class_list - list of class members

=head1 SYNOPSIS

 https://server/schulkonsole/class_list

=head1 DESCRIPTION

C<class_list> displays a list of all members in a selected class.
The HTML template is class_list.tt.

=cut

use strict;
use utf8;
use lib '/usr/share/schulkonsole';
use Schulkonsole::Config;
use Schulkonsole::Cyrus;
use Schulkonsole::DB;
use Schulkonsole::Info;
use Schulkonsole::Printer;
use Schulkonsole::Session;
use Schulkonsole::Repair;
use Proc::ProcessTable;

my $this_file = 'class_list';


my $sk_session = new Schulkonsole::Session($this_file);
if (not $sk_session->get_password()) {
	my $q = new CGI;
	my $url = $q->url( -full => 1 );

	# we send cookies over secure connections only
	if ($url =~ s/^http:/https:/g) {
		$sk_session->redirect($url);
	} else {
		$sk_session->exit_with_login_page($this_file);
	}
}

my $q = $sk_session->query();

my $id = $sk_session->userdata('id');
my $password = $sk_session->get_password();

my $classs = Schulkonsole::Info::groups_classes($sk_session->groups());
my $class = $q->param('classes');
if (    $class
    and $$classs{$class}) {
	$sk_session->param('class', $class);
}
$class = $sk_session->param('class');

if (   not $class
    or not $$classs{$class}) {
	my $url = $q->url( -absolute => 1 );
	$url =~ s/$this_file$/class/g;
	$sk_session->redirect($url);
}

my $process_table = new Proc::ProcessTable;
my $app_repair = $Schulkonsole::Config::_cmd_sophomorix_repair;
$app_repair =~ s:.*/::;
my %running;
foreach my $process (@{ $process_table->table }) {
	if ($process->fname =~ /^soph/ and $process->cmndline =~ /$app_repair/) {
			$running{repair} = $process->pid;
	}
}

if ($q->param('repair_classhomes;' . $class) and $class) {
	eval {
		Schulkonsole::Repair::repair_classhomes($id, $password, $class);
	};
	if($@){
		$sk_session->standard_error_handling($this_file, $@);
	}
	$sk_session->set_status($sk_session->d()->get('Reparatur gestartet...'),0);
	$running{repair} = 1;
}

=head2 Form fields

none


=head2 Template variables

Additionally to the variables of Schulkonsole::Session C<class_list>
provides the following variables:

=over

=cut


my $id = $sk_session->userdata('id');
my $password = $sk_session->get_password();

if( $sk_session->param('repair_classhomes;'.$class) ){
    Schulkonsole::Repair::repair_classhomes($id, $password, $class);
  $sk_session->set_status($sk_session->d()->get(
			'Die Persönlichen Ordner wurden repariert.'), 0);
}

my $all_classs = Schulkonsole::DB::classes();
delete $$all_classs{'attic'};

my $class_userdatas = Schulkonsole::DB::get_class_userdatas($class);
my $user_quotaroots = Schulkonsole::Cyrus::quota($id, $password, keys %$class_userdatas);

my $user_printquotas;
if ($sk_session->{template_vars}{'link_start_druckquotas'}) {
    eval {
    	require Schulkonsole::Druckquotas;
    	$user_printquotas = Schulkonsole::Druckquotas::quota($id, $password, keys %$class_userdatas);
    	$sk_session->set_var('printquotas',1);
    };
}

my @students;
foreach my $user (sort {
	$$class_userdatas{$a}{surname} cmp $$class_userdatas{$b}{surname} }
	keys %$class_userdatas) {

	my $quotaemail_usage;
	my $quotaemail_limit;
	my $quotaemail_percent;
	if ($$user_quotaroots{$user}) {
		$quotaemail_usage
			= $$user_quotaroots{$user}{"user.$user"}{quota}{STORAGE}{usage};
		$quotaemail_limit
			= $$user_quotaroots{$user}{"user.$user"}{quota}{STORAGE}{limit};
		$quotaemail_percent = sprintf("%.1f", 100 *
		                              $quotaemail_usage / $quotaemail_limit);
	} else {
		$quotaemail_percent = '0.0';
	}


	my $disk_quotas =
		Schulkonsole::Info::disk_quotas($$class_userdatas{$user}{uidnumber});

	my @array_diskquotas;
	foreach my $disk_quota (@$disk_quotas) {
	    my ($filesystem, $path,
		    $blocks_usage, $blocks_soft, $blocks_hard,
		    $blocks_grace,
		    $files_usage, $files_soft, $files_hard,
		    $files_grace) = @$disk_quota;
		next unless (defined $files_hard and ($blocks_hard or $files_hard));

		my $blocks_percent = $blocks_soft ?
			  sprintf('%.1f', 100 * $blocks_usage / $blocks_soft)
			: 0;
		my $files_percent = $files_soft ?
			  sprintf('%.1f', 100 * $files_usage / $files_soft)
			: 0;

		my $blocks_grace_str;
		if ($blocks_grace) {
			$blocks_grace -= $^T;
			if ($blocks_grace > 86400) {
				$blocks_grace_str = sprintf($sk_session->d()->get('%d Tage'),
					$blocks_grace / 86400 + 0.5);
			} elsif ($blocks_grace > 7200) {
				$blocks_grace_str = sprintf($sk_session->d()->get('%d Stunden'),
					$blocks_grace / 3600 + 0.5);
			} elsif ($blocks_grace > 0) {
				$blocks_grace_str = sprintf($sk_session->d()->get('%d Minuten'),
					$blocks_grace / 60 + 0.5);
			} else {
				$blocks_grace_str = $sk_session->d()->get('abgelaufen');
			}
		} else {
			$blocks_grace_str = '-';
		}
	
		my $files_grace_str;
		if ($files_grace) {
			$files_grace -= $^T;
			if ($files_grace > 86400) {
				$files_grace_str = sprintf($sk_session->d()->get('%d Tage'),
					$files_grace / 86400 + 0.5);
			} elsif ($files_grace > 7200) {
				$files_grace_str = sprintf($sk_session->d()->get('%d Stunden'),
					$files_grace / 3600 + 0.5);
			} elsif ($files_grace > 0) {
				$files_grace_str = sprintf($sk_session->d()->get('%d Minuten'),
					$files_grace / 60 + 0.5);
			} else {
				$files_grace_str = $sk_session->d()->get('abgelaufen');
			}
		} else {
			$files_grace_str = '-';
		}

		my $diskquota = {
			'warn' => $blocks_grace || $files_grace,
			path => $path,
			blocks_usage => $blocks_usage,
			blocks_soft => $blocks_soft,
			blocks_hard => $blocks_hard,
			blocks_percent => $blocks_percent,
			blocks_percent_rounded => ($blocks_percent < 100.0 ?
			                             int($blocks_percent + 0.5)
			                           : 100),
			blocks_grace => $blocks_grace_str,
			files_usage => $files_usage,
			files_soft => $files_soft,
			files_hard => $files_hard,
			files_percent => $files_percent,
			files_percent_rounded => ($files_percent < 100.0 ?
			                            int($files_percent + 0.5)
			                          : 100),
			files_grace => $files_grace_str,
		};

		push @array_diskquotas, $diskquota;
	}


	my $mailquotas =  {
		usage => $quotaemail_usage,
		limit => $quotaemail_limit,
		percent => $quotaemail_percent,
		percent_rounded => ($quotaemail_percent < 100.0 ?
		                      int($quotaemail_percent + 0.5)
		                    : 100),
		'warn' => ($quotaemail_usage > $quotaemail_limit)
	};

	my $printquota;
	if ($$user_printquotas{$user}) {
		my $usage = $$user_printquotas{$user}{usage};
		my $limit = $$user_printquotas{$user}{limit};

		my $usage_percent = $usage ?
			sprintf('%.1f', 100 * $usage / $limit)
			: 0;

		$printquota = {
			usage => $usage,
			limit => $limit,
			percent => $usage_percent,
			percent_rounded => ($usage_percent < 100.0 ?
					int($usage_percent + 0.5)
					: 100),
			'warn' => $usage > $limit,
		};
	} elsif(defined $user_printquotas) {
		$printquota = {
			usage => 0,
			limit => 0,
			percent => 0,
			percent_rounded => 0,
		};
	}

	my $groups = Schulkonsole::DB::user_groups(
		$$class_userdatas{$user}{uidnumber},
		$$class_userdatas{$user}{gidnumber},
		$$class_userdatas{$user}{gid});
	my @projects;
	my $projects = Schulkonsole::Info::groups_projects($groups);
	foreach my $project (values %$projects) {
		push @projects, $$project{displayname};
	}
	my $projects_str = join ', ', @projects;


	my $student = {
		login => $user,
		firstname => $$class_userdatas{$user}{firstname},
		surname => $$class_userdatas{$user}{surname},
		diskquotas => \@array_diskquotas,
		mailquotas => $mailquotas,
		subclass => $$class_userdatas{$user}{subclass},
		projects_str => $projects_str,
	};
	if(defined $user_printquotas){
		$$student{printquotas} = $printquota;
	}
	push @students, $student;
}

=item C<students>

An array of hashes with the keys

=over

=item C<login>

The login of a user

=item C<firstname>

The user's first name

=item C<surname>

The user's surname

=item C<diskquotas>

The user's disk quotas in an array of hashes with the keys

=over

=item C<path>

A file path

=item C<blocks_usage>

The user's blocks usage in this path

=item C<blocks_soft>

The user's soft blocks limit for this path

=item C<blocks_hard>

The user's hard blocks limit for this path

=item C<blocks_percent>

The user's blocks usage in percent in this path

=item C<blocks_percent_rounded>

The user's blocks usage in percent in this path rounded to an integer

=item C<blocks_grace>

Time for this user to get below soft blocks limit

=item C<files_usage>

The user's file usage in this path

=item C<files_soft>

The user's soft files limit for this path

=item C<files_hard>

The user's hard files limit for this path

=item C<files_percent>

The user's files usage in percent in this path

=item C<files_percent_rounded>

The user's files usage in percent in this path rounded to an integer

=item C<files_grace>

Time for this user to get below soft files limit

=item C<warn>

True if over blocks or files quota

=back

=item C<mailquotas>

The user's INBOX mail quota in a hash with the keys

=over

=item C<usage>

The user's INBOX usage

=item C<limit>

The user's INBOX limit

=item C<percent>

The user's INBOX usage in percent

=item C<percent_rounded>

The user's INBOX usage in percent rounded to an integer

=item C<warn>

True if user is over quota

=back

=item C<printquotas>

The user's print quota in a hash with the keys

=over

=item C<usage>

The user's printed pages

=item C<limit>

The user's maximum allowed pages

=item C<percent>

The user's print quota usage in percent

=item C<percent_rounded>

The user's print quota usage in percent rounded to an integer

=back

=item C<subclass>

The subclass to which the user is assigned

=item C<projects_str>

The user's projects in a comma separated list

=back

=cut

$sk_session->set_var('students', \@students);



my @classs;
my @other_classs;
foreach my $class (sort {
	$$all_classs{$a}{displayname} cmp $$all_classs{$b}{displayname} }
                   keys %$all_classs) {
	if ($$classs{$class}) {
		push @classs, { gid => $class,
		                name => $$all_classs{$class}{displayname} };
	} else {
		push @other_classs, { gid => $class,
		                      name => $$all_classs{$class}{displayname} };
	}
}

=item C<classes>

An array of hashes of the classes of which the current user is a member
with the keys

=over

=item C<gid>

The GID of the class

=item C<name>

The name of the class

=back

=cut

$sk_session->set_var('classes', \@classs);

=item C<other_classes>

An array of hashes of the classes of which the current user is not a member
with the keys

=over

=item C<gid>

The GID of the class

=item C<name>

The name of the class

=back

=cut

$sk_session->set_var('other_classes', \@other_classs);


if ($class) {

=item C<class_gid>

The GID of the selected class (if a class is selected)

=cut

	$sk_session->set_var('class_gid', $class);

=item C<class_name>

The name of the selected class (if a class is selected)

=cut

	$sk_session->set_var('class_name', $$classs{$class}{displayname});
}

if($q->param('logrepair') or $running{repair}) {
	eval {
		my $logrepair =
			Schulkonsole::Repair::read_repair_log_file($id, $password);

=item C<logrepair>

Output of C<sophomorix-repair ...>

=cut

		splice @$logrepair, 0, -30;
		$sk_session->set_var('logrepair', join("", @$logrepair));
	};
	if ($@) {
		$sk_session->set_status(
			$sk_session->d()->get('Kann Logdatei nicht öffnen'), 1);
	}
	
}

=item C<isbusy>

True if C<sophomorix-repair> is running

=cut

$sk_session->set_var('isbusy', ($running{repair}? 1 : 0));

$sk_session->print_page("$this_file.tt", $this_file);


=back
