E-Mail-Übersicht in der Schulkonsole

Hallo liebe Community,
ich habe mich heute daran versucht, unsere Schulkonsole (lml 6.2) ein wenig zu erweitern.
Ähnlich wie die Übersicht über die einzelnen Schüler einer Klasse, wollte ich noch eine Seite haben, in der man auf einen Blick alle E-Mail-Adressen der Schüler aufgelistet bekommt (teilweise eben die privaten, wenn eingestellt).
Nun habe ich es geschafft, in /usr/share/schulkonsole/tt/ eine Datei class_mails anzulegen (Vorlage war die „class_passwords“), der Menüpunkt „E-Mails“ wird mir unter „Klassen“ auch angezeigt und ich komme auch auf die entsprechende Seite.

Das ist der aktuelle Stand der class_mails.tt

[% page = {
      title    => loc('Schulkonsole') _ " - " _ loc('Klassen') _ ":  $class_name - " _ loc('E-Mails'),
      menu     => 1,
      submenu  => "class",
      disable_enter => 1,
      info     => loc('<p>Hier können Sie sich die E-Mail-Adressen der Schüler/innen der Klasse anschauen.</p><p>Außerdem können Sie sich die E-Mail-Liste der Klasse ausdrucken lassen.</p>'),
   }
%]

[% IF classes %]
<form method="post" accept-charset="UTF-8" onsubmit="return showBusy()">
<p class="selectdomain">
<select name="classes">
<optgroup label="Klassen">
[% FOREACH c IN classes %] <option value="[% c.gid %]">[% c.name %]</option>
[% END %]
</optgroup>
<optgroup label="aktuelle Klasse">
<option value="[% class_gid %]" selected>[% class_name %]</option>
</optgroup>
</select>
<input type="submit" value="[% loc('Wechseln') %]">
</p>
</form>
[% END %]


<h2>[% loc('Klassen') %] :: [% loc('E-Mails') %]</h2>

<h3>[% loc('Ausgewählte Klasse:') %] [% class_name %]</h3>

<!--
<form class="singleton" method="post" accept-charset="UTF-8" action="class_passwords/[% class %]-[% username %].pdf">
<p>
<input type="submit" name="passwords_print_pdf" value="[% loc('Passwortliste als PDF') %]">
</p>
</form>

<form class="singleton" method="post" accept-charset="UTF-8" action="class_passwords/[% class %]-[% username %].csv">
<p>
<input type="submit" name="passwords_print_csv" value="[% loc('Passwortliste als CSV') %]">
</p>
</form>
-->

<hr>

<form method="post" accept-charset="UTF-8">

<table id="classpasswords" class="liste">
<col width="1%">
<col span="2">
<col width="9%">
<col>
<tr>
<th>[% loc('Nr') %]</th>
<th>[% loc('Login') %]</th>
<th>[% loc('Name') %]</th>
<th>[% loc('E-Mail') %]</th>
</tr>
[% FOREACH s IN students %]
[% IF odd %][% odd=0 %]<tr class="odd">
[% ELSE %][% odd=1 %]<tr class="even">[% END %]
<td align="right">[% s.lfdnr %].&nbsp;</td>
<td>[% s.login %]</td>
<td>[% s.firstname %] [% s.surname %]</td>
<td>[% s.mail %]</td>
</tr>
[% END %]
<tr>
<th>[% loc('Nr') %]</th>
<th>[% loc('Login') %]</th>
<th>[% loc('Name') %]</th>
<th>[% loc('E-Mail') %]</th>
</tr>
</table>

Des weiteren habe ich herausgefunden, welche Zeile in der /usr/lib/schulkonsole/cgi-bin/class_mails (ebenfalls von class_passwords kopiert) meine Variable s.mail füllt, die ich in der class_mails.tt habe.

Aktuelle Stand der /cgi-bin/class_mails

#!/usr/bin/perl

=head1 NAME

class_mails - allow to show class member's mails

=head1 SYNOPSIS

 https://server/schulkonsole/class_mails

=head1 DESCRIPTION

C<class_mails> allows to show and display the mails of all or single
members of a selected class.
The HTML template is class_mails.tt

=head2 Template variables

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

=over

=cut

use strict;
use utf8;
use lib '/usr/share/schulkonsole';
use Schulkonsole::Session;
use Schulkonsole::Info;
use Schulkonsole::Sophomorix;

my $this_file = 'class_mails';


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 $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->param('requested_page',$this_file);
	$sk_session->redirect($url);
}


my @classs;
foreach my $class (sort {
    $$classs{$a}{displayname} cmp $$classs{$b}{displayname} } keys %$classs) {
	push @classs, { gid => $class,
	                name => $$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<class_name>

The name of the class

=cut

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

my $path = $q->path_info();
$path =~ s:^/+:: if defined $path;
if ($path) {
	eval {
	TYPE: {
	$q->param('passwords_print_pdf') and do {
		my $pdf_data = Schulkonsole::Sophomorix::print_class(
			$sk_session->userdata('id'),
			$sk_session->get_password(),
			$class, 0);

		if ($pdf_data =~ /^\%PDF/) {
			binmode STDOUT;
			
			print $q->header( -type => 'application/pdf' ), $pdf_data;

			exit;
		} else {
			$sk_session->set_status_redirect($sk_session->d()->get(
				'Fehler bei der Erzeugung des Dokuments'), 1);
		}

		last TYPE;
	};
	$q->param('passwords_print_csv') and do {
		my $csv_data = Schulkonsole::Sophomorix::print_class(
			$sk_session->userdata('id'),
			$sk_session->get_password(),
			$class, 1);

		if ($csv_data =~ /^.*;.*;.*;/) {
			binmode STDOUT, ':utf8';

			print $q->header( -type => 'text/comma-separated-values' ),
			      $csv_data;

			exit;
		} else {
			$sk_session->set_status_redirect($sk_session->d()->get(
				'Fehler bei der Erzeugung des Dokuments'), 1);
		}

		last TYPE;
	};
	}
	};
	if ($@) {
		$sk_session->standard_error_handling($this_file, $@, 1);
	}

	# in case of error, re-direct to URL without PATH_INFO
	my $url = $q->url( -absolute => 1 );
	$sk_session->redirect($url);
}



my $class_userdatas = Schulkonsole::DB::get_class_userdatas($class);


=back

=head3 Template variables specific to showpassword.tt

=over

=cut

foreach my $user (keys %$class_userdatas) {
	if ($q->param("${user}_showpassword")) {

=item C<showfirstname>

The first name of the user of the displayed password

=cut

		$sk_session->set_var('showfirstname',
			$$class_userdatas{$user}{firstname});

=item C<showsurname>

The surname of the user of the displayed password

=cut

		$sk_session->set_var('showsurname',
			$$class_userdatas{$user}{surname});

=item C<showusername>

The username of the user of the displayed password

=cut

		$sk_session->set_var('showusername', $user);

=item C<showpassword>

The initial password of the user of the displayed password

=back

=cut

		$sk_session->set_var('showpassword',
			$$class_userdatas{$user}{firstpassword});

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


=head3 Template variables specific to class_passwords.tt

=over

=cut

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

	$lfdnr++;

	my $student = {
                lfdnr => $lfdnr,
		login => $user,
		firstname => $$class_userdatas{$user}{firstname},
		surname => $$class_userdatas{$user}{surname},
		mail => $$class_userdatas{$user}{surname}
	};
	push @students, $student;
}

=item C<students>

An array of hashes with the keys

=over

=item C<lfdnr>

The line nr of the user

=over

=item C<login>

The login of a user

=item C<firstname>

The user's first name

=item C<surname>

The user's surname

=back

=cut

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


eval {
COMMANDS: {
$q->param('passwords_reset') and do {
	if (@user_selects) {
		Schulkonsole::Sophomorix::passwords_reset(
			$sk_session->userdata('id'),
			$sk_session->get_password(),
			@user_selects);

		$sk_session->set_status(
			$sk_session->d()->get('Passwörter zurückgesetzt'), 0);
	} else {
		$sk_session->set_status(
			$sk_session->d()->get('Keine Benutzer ausgewählt'), 1);
	}
	last COMMANDS;
};
$q->param('passwords_random') and do {
	if (@user_selects) {
		Schulkonsole::Sophomorix::passwords_random(
			$sk_session->userdata('id'),
			$sk_session->get_password(),
			@user_selects);

		$sk_session->set_status(
			$sk_session->d()->get('Zufallspasswörter gesetzt'), 0);
	} else {
		$sk_session->set_status(
			$sk_session->d()->get('Keine Benutzer ausgewählt'), 1);
	}
	last COMMANDS;
};
$q->param('passwords_set') and do {
	if (@user_selects) {
		if (my $user_password = $q->param('userpassword')) {
			Schulkonsole::Sophomorix::passwords_set(
				$sk_session->userdata('id'),
				$sk_session->get_password(),
				$user_password,
				@user_selects);

			$sk_session->set_status(
				$sk_session->d()->get('Passwörter gesetzt'), 0);
		} else {
			$sk_session->set_status(
				$sk_session->d()->get('Kein Passwort eingegeben'), 1);
		}

	} else {
		$sk_session->set_status(
			$sk_session->d()->get('Keine Benutzer ausgewählt'), 1);
	}
	last COMMANDS;
};
}
};
if ($@) {
	$sk_session->standard_error_handling($this_file, $@);
}



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

=back

=head2 Form fields

=over

=item C<passwords_print>

Write PDF-document with passwords to the file name in the PATHINFO

=item C<${students{login}}_showpassword>

Show password of user with login.
Created in loop over template variable C<students>.

=item C<${students{login}};select>

Checkboxes created in loop over template variable C<students>. The selected
action (passwords_reset/passwords_random/passwords_set) is performed with
the selected logins.

=item C<passwords_reset>

Reset passwords of selected users

=item C<passwords_random>

Set random password for selected users

=item C<passwords_set>

Set password in C<userpassword> for selected users

=item C<userpassword>

Password to be set by passwords_set

=back

Aktuell steht in der folgenden Zeile jetzt als Dummy noch der Nachname als E-Mail-Adresse drin.

mail => $$class_userdatas{$user}{surname}

Und jetzt komme ich auch endlich zur eigentlichen Frage:
Kann ich (und wenn ja, wie?) in diesem Skript die persönliche E-Mail-Adresse des Nutzers aus dem LDAP auslesen?

Ich hoffe, mein Anliegen ist einigermaßen verständlich.

Vielen Dank, liebe Grüße und bleibt gesund,

Wolfgang

Hallo Wolfgang,

coole Arbeit an der SchuKo :slight_smile:

Ich kann dir vioelleicht ein wenig helfen durch dieses script von Jörg,
mit dem ich das Mailfeld im Seminar befülle:


#!/bin/bash
# HIB modifiziertes AddMail2LDAP von Joerg Richter
for lehrer in /home/teachers/*; do
  MYUSER=$(echo $lehrer | cut -d "/" -f 4)
  MYMAIL=$(ldapsearch -x -b "ou=accounts,dc=linuxmuster,dc=local"
"(uid=${MYUSER})" mail|grep "^mail:"| cut -d\: -f2)
#  MYPRE=$(ldapsearch -x -b "ou=accounts,dc=linuxmuster,dc=local"
"(uid=${MYUSER})" givenName|grep "^givenName:"| cut -d\: -f2)
  if [ -z "$MYMAIL" ]; then
    echo "AddMail2LDAP Lehrer(${MYUSER}) bisher(${MYMAIL})
neu(${MYUSER}@semgym-karlsruhe.de)"
#    smbldap-usermod -M ${MYUSER}@gymnasium-himmelsthuer.de $MYUSER
  else
    echo "AddMail2LDAP Lehrer(${MYUSER}) bisher(${MYMAIL}) bleibt"
  fi
#  echo "${MYUSER}	: ${MYMAIL}"

done

Da siehts du nicht nur wie man das Feld ausliest, sondern auch wie man
es befüllt.

Hast du gewußt, dass man in der Schulkonsole das Feld „email“ für jeden
Benutzer freischalten kann, damit man selbst das Feld email im LDAP
manipulieren kann?

http://docs.linuxmuster.net/de/latest/user-management/use-mail-ldap/index.html

LG

Holger

Hallo Holger,

tolles Feature, das ich gar nicht kannte.
Wird es etwas Ähnliches auch in der Schuko V7 geben?

Viele Grüße

Wilfried

Hallo Holger,
vielen Dank für deine Rückmeldung!

Die Funktion, dass man seine private Adresse über die Schulkonsole einstellen kann, habe ich bereits aktiviert. Allerdings wissen das bisher nur die allerwenigsten, dass man sie dort ändern kann.

Ansonsten auch besten Dank für das Skript. Den Befehl smblad-usermod kannte ich bereits, aber das auslesen aus dem LDAP dürfte sehr nützlich sein.

Ich werde mich wieder melden, wenn ich weitergekommen bin. Ansonsten muss ich mich gerade um ein dringenderes Problem kümmern…
Siehe:
HELP! sophomorix-mail hat die LDAP-Adressen gekillt

Liebe Grüße und beste Gesundheit,

Wolfgang

Hallo Holger,

nun bin ich endlich dazu gekommen, dein (bzw. Jörgs) Skript auszuprobieren.
Prinzipiell verstehe ich, wie es funktioniert (auch, wenn ich noch nicht weiß, wie ich die Befehle nachher in meinem class_mails - Skript ausführen soll), allerdings habe ich folgendes Problem in meinem LDAP:

Wenn ich einen Eintrag auslesen möchte, dann kommt unter anderem die Zeile
mail:: <(verschlüsselter?) Kauderwelsch>
Zum einen weiß ich nicht, warum er nur hinter dem Attribut mail zwei Doppelpunkte verwendet?
(Gut, euer Skript habe ich dann eben mit
cut -d: -f3
angepasst.)
Aber zum anderen zeigt er mir auch nicht die E-Mail-Adresse im Klartext an.
Speichert die Datenbank die E-Mail-Adressen verschlüsselt? Handelt es sich nur um einen Hash-Wert?
Wenn ich ein externes Programm benutze (LDAP Admin für Windows), kann ich die E-Mail-Adresse ganz normal lesen.
Bin mal wieder ein wenig verwirrt und hoffe auf Hilfestellungen.

Edit: Die E-Mail-Adresse ist base64 codiert und nicht verschlüsselt. Muss ich nur noch rauskriegen, wie ich sie decodiert kriege…

Edit²:

echo `echo <decodierter Wert> | base64 --decode`

Entschuldigt, dass ich so in den Thread spamme. Hoffe, dass es jemand anderem bei einem ähnlichen Problem weiterhilft…

Liebe Grüße und immer schön Hände waschen,

Wolfgang

So, weiter gehts…

Das Perl-Script (erster Ausflug in Perl)

#!/usr/local/bin/perl -w

$user="pgmadmin";
$m = `echo \`echo \$(ldapsearch -x -b "ou=accounts,dc=linuxmuster-net,dc=lokal" uid=$user | grep mail | cut -d\: -f3) | base64 --decode\` `;
print($m);

gibt mir wunderbar die E-Mail-Adresse des bspw. pgmadmins aus.
Habe extra recherchiert, wie man aus einem Perl-Skript (und soweit ich das beurteilen kann, ist das bei der Schulkonsole der Fall) einen bash-Befehl ausführen kann.

Schreibe ich die entsprechende Zeile aber in meine /usr/lib/schulkonsole/cgi-bin/class_mails

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

        $lfdnr++;

        $m = `echo \`echo \$(ldapsearch -x -b "ou=accounts,dc=linuxmuster-net,dc=lokal" uid=$user | grep mail | cut -d\: -f3) | base64 --decode\` `;

        my $student = {
                lfdnr => $lfdnr,
                login => $user,
                firstname => $$class_userdatas{$user}{firstname},
                surname => $$class_userdatas{$user}{surname},
                mail => $user
        };
        push @students, $student;
}

so verabschiedet sich die Schulkonsole mit einem „Internal Server Error“.

Wäre großartig, wenn da jemand weiter weiß.

Bis dahin wünsche ich eine gute Nacht,

Wolfgang