#! /usr/bin/perl

=head1 NAME

quotas_projects - quota settings for projects

=head1 SYNOPSIS

 https://server/schulkonsole/quotas_projects

=head1 DESCRIPTION

C<quotas_projects> lets you edit the quotas of projects.
The HTML template is quotas_projects.tt.

=head2 Template variables

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

=over

=cut

use strict;
use utf8;
use lib '/usr/share/schulkonsole';
use Schulkonsole::Session;
use Schulkonsole::SophomorixConfig;
use Schulkonsole::SophomorixQuotas;
use Schulkonsole::Error::SophomorixError;

use Proc::ProcessTable;

my $this_file = 'quotas_projects';




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);
	}
}

if (not $Schulkonsole::SophomorixConfig::quotaactivated) {
	my $q = new CGI;
	my $url = $q->url( -full => 1 );

	$url =~ s/$this_file$/quotas/g;
	$sk_session->redirect($url);
}

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

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



my @mountpoints = Schulkonsole::SophomorixQuotas::mountpoints();

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


eval {
COMMANDS: {
$q->param('acceptprojects') and do {
	my $projects = Schulkonsole::DB::projects();
	my %new_projects;

	my $is_changed = 0;
	my @errors;
	foreach my $param ($q->param) {
		if (my ($gid, $action)
		    	= $param =~ /^(.+)_project(.+-diskquota|mailquota)$/) {
			if ($$projects{$gid}) {
				my ($value) = $q->param($param) =~ /^\s*(.+?)\s*$/;
				if ($value !~ /^\d*$/) {
					push @errors, sprintf($sk_session->d()->get(
							'%s: Quota muss eine Zahl sein'),
						$$projects{$gid}{displayname});
				} else {

					if ($action =~ /^m/) {	# mailquota
						if (   (   $$projects{$gid}{addmailquota} == -1
							    and length($value))
						    or (    $$projects{$gid}{addmailquota} != -1
							    and $$projects{$gid}{addmailquota} != $value)) {

							$new_projects{$gid}{mailquota}
								= (length($value) ? $value : -1);
							$is_changed++;
						}
					} else {	# diskquota
						my ($mountpoint) = $action =~ /^(.+?)-diskquota$/;
						my $diskquotas =
							(    exists $new_projects{$gid}
							 and $new_projects{$gid}{diskquotas}) ?
							  $new_projects{$gid}{diskquotas}
							: Schulkonsole::SophomorixQuotas::split_diskquotas_to_hash($$projects{$gid}{addquota});
						if (   (    length($value)
						        and not defined $$diskquotas{$mountpoint})
						    or $$diskquotas{$mountpoint} ne $value) {
							# add old values
							$new_projects{$gid}{diskquotas} = $diskquotas
								unless exists $new_projects{$gid}{diskquotas};

							# overwrite with new value
							$new_projects{$gid}{diskquotas}{$mountpoint} = $value;
							$is_changed++;
						}
					}
				}
			} else {
				push @errors, sprintf($sk_session->d()->get(
					'Projekt %s unbekannt'), $gid);
			}
		}
	}

	if (@errors) {
		$sk_session->set_status(join(', ', @errors), 1);
	} elsif ($is_changed) {
		my @queue;
		# check values
		foreach my $gid (keys %new_projects) {
			my $diskquotas =
				Schulkonsole::SophomorixQuotas::hash_to_quotastring(
					$new_projects{$gid}{diskquotas})
				if defined $new_projects{$gid}{diskquotas};
			my $mailquota = $new_projects{$gid}{mailquota}
				if defined $new_projects{$gid}{mailquota};
			push @queue, [
				$gid,
				$diskquotas,
				$mailquota ] if length $diskquotas || length $mailquota;
		}

		foreach my $quota_info (@queue) {
			Schulkonsole::SophomorixQuotas::project_set_quota(
				$id, $password, @$quota_info);
		}
		$running{quota} = 1;

		$sk_session->set_status($sk_session->d()->get(
			'Änderungen übernommen.'), 0);
	} else {
		$sk_session->set_status($sk_session->d()->get(
			'Keine Änderungen.'), 1);
	}


	last COMMANDS;
};	# end acceptprojects

$q->param('acceptusers') and do {
	my $users = read_quota_conf();
	my %new_users;

	my $is_changed = 0;
	my @errors;
	my @processed_params;

	if (my $login = $q->param('newlogin')) {
		my $userdata = Schulkonsole::DB::get_userdata($login);
		if ($userdata) {
			if ($$userdata{gid} eq 'teachers') {
				$sk_session->set_status(sprintf($sk_session->d()->get(
					'%s ist ein Lehrer'), $login), 1);
				last COMMANDS;
			}
		} elsif (   not is_passwd_user($login)
		         or $login eq 'root') {
			$sk_session->set_status(sprintf($sk_session->d()->get(
				'Benutzer %s unbekannt'), $login), 1);
			last COMMANDS;
		} elsif ($$users{$login}) {
			$sk_session->set_status(sprintf($sk_session->d()->get(
					'Für Benutzer %s gibt es bereits einen Eintrag'),
					$login),
				1);
			last COMMANDS;
		}


		my %new_user;
		my $is_undefined = 0;
		foreach my $mountpoint (@mountpoints) {
			my $value = $q->param("$mountpoint-newdiskquota");
			if (length $value) {
				$new_user{diskquotas}{$mountpoint} = $value;
			} else {
				$is_undefined++;
			}
			push @processed_params, "$mountpoint-newdiskquota";
		}
		if (    $is_undefined
		    and $is_undefined != @mountpoints) {
			die new Schulkonsole::Error::SophomorixError(Schulkonsole::Error::SophomorixError::QUOTA_NOT_ALL_MOUNTPOINTS)
		}
		my $mailquota = $q->param('newmailquota');
		push @processed_params, 'newmailquota';
		if (length $mailquota) {
			$new_user{mailquota} = $mailquota;
		} elsif ($is_undefined == @mountpoints) {
			$sk_session->set_status($sk_session->d()->get(
				'Tragen Sie mindestens Disk- oder Mailquota ein'), 1);
			last COMMANDS;
		}

		$is_changed++;
		$new_users{$login} = \%new_user;
		push @processed_params, 'newlogin';
	}



	foreach my $param ($q->param) {
		if (my ($login, $action) = $param =~ /^(.+)_user(.+-diskquota|mailquota)$/) {
			if ($$users{$login}) {
				my ($value) = $q->param($param) =~ /^\s*(.+?)\s*$/;
				if ($value !~ /^\d*$/) {
					push @errors, sprintf($sk_session->d()->get(
							'%s: Quota muss eine Zahl sein'), $login);
				} else {
					push @processed_params, $param;

					if ($action =~ /^m/) {	# mailquota
						if (   (    not defined $$users{$login}{mailquota}
						        and length($value))
						    or (    defined $$users{$login}{mailquota}
						        and (   not length($value)
						             or $$users{$login}{mailquota} != $value))) {

							$new_users{$login}{mailquota} =
								(length($value) ?
								   $value
								 : $Schulkonsole::SophomorixQuotas::mailquota_undefined);
							$is_changed++;
						}
					} else {	# diskquota
						my ($mountpoint) = $action =~ /^(.+?)-diskquota$/;
						if (   (    length($value)
						        and not $$users{$login}{diskquotas}{$mountpoint})
						    or $$users{$login}{diskquotas}{$mountpoint} ne $value) {
							$new_users{$login}{diskquotas} = $$users{$login}{diskquotas} unless $new_users{$login}{diskquotas};
							$new_users{$login}{diskquotas}{$mountpoint} = $value;
							$is_changed++;
						}
					}
				}
			} else {
				push @errors, sprintf($sk_session->d()->get(
					'Benutzer %s hat keine Sonderquota'), $login);
			}
		}
	}

	if (@errors) {
		$sk_session->set_status(join(', ', @errors), 1);
	} elsif ($is_changed) {
		my $quota_lines = new_quota_lines(\%new_users);
		my $mailquota_lines = new_mailquota_lines(\%new_users);

		Schulkonsole::SophomorixQuotas::write_quota_conf($id, $password, $quota_lines);
		Schulkonsole::SophomorixQuotas::write_mailquota_conf($id, $password, $mailquota_lines);


		Schulkonsole::SophomorixQuotas::process_quota($id, $password, 8);

		$running{quota} = 1;

		$sk_session->set_status($sk_session->d()->get(
			'Änderungen übernommen.'), 0);
		$q->delete(@processed_params);
	} else {
		$sk_session->set_status($sk_session->d()->get(
			'Keine Änderungen.'), 1);
	}


	last COMMANDS;
};	# end acceptusers

($q->param('logquota') or $running{quota}) and do {
	eval {
		my $logquota =
			Schulkonsole::SophomorixQuotas::read_quota_log_file($id, $password);

=item C<logquota>

Output of C<sophomorix-quota --set>

=cut

		splice @$logquota, 0, -30;
		$sk_session->set_var('logquota', join("", @$logquota));
	};
	if ($@) {
		$sk_session->set_status(
			$sk_session->d()->get('Kann Logdatei nicht öffnen'), 1);
	}
	last COMMANDS;
};
} # end COMMANDS
};
if ($@) {
	$sk_session->standard_error_handling($this_file, $@);
}





eval {
my $projects = Schulkonsole::DB::projects();
my @projects_array;
foreach my $project (sort {
		$$projects{$a}{displayname} cmp $$projects{$b}{displayname} }
	keys %$projects) {
	my $adddiskquotas = $$projects{$project}{addquota};
	my @quota_array;
	if ($adddiskquotas ne $Schulkonsole::SophomorixQuotas::diskquota_undefined) {
		@quota_array = split /\+(?!\+)/, $adddiskquotas;
		@quota_array = () unless $#quota_array == $#mountpoints;
	}
	my @adddiskquotas;
	foreach my $mountpoint (@mountpoints) {
		push @adddiskquotas, {
				mountpoint => $mountpoint,
				quota => shift @quota_array,
			};
	}
	my $addmailquota = $$projects{$project}{addmailquota};
	$addmailquota = '' if $addmailquota < 0;

	push @projects_array, {
			gid => $project,
			name => $$projects{$project}{displayname},
			adddiskquotas => \@adddiskquotas,
			addmailquota => $addmailquota,
		};
}

=item C<projects>

The quotas of the projects as an array of hashes with the keys

=over

=item C<gid>

GID of a project

=item C<name>

Name of the project

=item C<adddiskquotas>

Additional disk quotas for users of the project
as an array of hashes with the keys

=over

=item C<mountpoint>

A mountpoint

=item C<quota>

Additional quota for this mountpoint in MB

=back

=item C<addmailquota>

Additional mail quota in MB

=back

=cut

$sk_session->set_var('projects', \@projects_array);
};
if ($@) {
	$sk_session->standard_error_handling($this_file, $@);
}



=item C<mountpoints>

An array with the mountpoints

=cut

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

=item C<mountpoints_cnt>

The number of mountpoints

=cut

$sk_session->set_var('mountpoints_cnt', scalar(@mountpoints));

=item C<isbusy>

True if C<sophomorix-quota> is running

=cut

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


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


=back

=head2 Form fields

=over

=item C<acceptprojects>

Accept the changes of the form

=item C<${projects{gid}}_project${projects{diskquotas}{mountpoint}}-diskquota>

Disk quota for project C<$projects{gid}> for mountpoint
C<$projects{diskquotas}{mountpoint}>.
Created in loop over template variable C<projects{diskquotas}> in loop over
template variable C<projects>

=item C<${projects{gid}}_projectmailquota>

Mail quota for project C<$projects{gid}>.
Created in loop over template variable C<projects>

=back

