aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-04 12:49:59 +0200
committerGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-04 12:49:59 +0200
commite04e3174c1c38e7587df495c19082a864f2373b2 (patch)
treed4a53a9b6a1318808f841ccd74195b7ab470d949
parentb4e2151a91eb827bc90a44a906f7a7c40fde95c7 (diff)
Only propose to add entry if relevant.
-rw-r--r--css/style.css4
-rw-r--r--lib/FPanel/Interface.pm221
-rw-r--r--template/list-domains.html2
-rw-r--r--template/list-locals.html31
4 files changed, 163 insertions, 95 deletions
diff --git a/css/style.css b/css/style.css
index 465a7b1..b4925da 100644
--- a/css/style.css
+++ b/css/style.css
@@ -176,3 +176,7 @@ div.editform {
font-size: 11pt;
margin: 10pt;
}
+.dunno {
+ font-weight: bolder;
+ color: #888888;
+}
diff --git a/lib/FPanel/Interface.pm b/lib/FPanel/Interface.pm
index f73b5de..79e36b5 100644
--- a/lib/FPanel/Interface.pm
+++ b/lib/FPanel/Interface.pm
@@ -12,9 +12,9 @@ use base 'FPanel::Login';
# inherits the configuration from the super class.
sub cgiapp_init {
my $self = shift;
-
+
$self->SUPER::cgiapp_init;
-
+
# Every single Run Mode here is protected
$self->authen->protected_runmodes( ':all' );
}
@@ -26,23 +26,26 @@ sub ListDomains : StartRunmode {
my $self = shift;
my %CFG = $self->cfg;
my $suffix = join ',', @{$CFG{ldap_suffix}};
-
+
my ($l,$d) = split /@/, $self->authen->username, 2;
my $authzDN = "fvu=$l,fvd=$d,". $suffix;
my $ldap = $self->ldap_from_auth_user($authzDN);
-
+
my $domains = $ldap->search( base => $suffix
, scope => 'one'
, filter => 'objectClass=FripostVirtualDomain'
, deref => 'never'
- , attrs => [ qw/fvd description fripostIsStatusActive
- fripostCanCreateAlias fripostCanCreateList
- fripostOwner fripostPostmaster/ ]
+ , attrs => [ qw/fvd description
+ fripostIsStatusActive
+ fripostCanCreateAlias
+ fripostCanCreateList
+ fripostOwner
+ fripostPostmaster/ ]
);
die $domains->error if $domains->code;
$ldap->unbind;
-
-
+
+
my $template = $self->load_tmpl( 'list-domains.html', cache => 1, utf8 => 1
, loop_context_vars => 1
, global_vars => 1 );
@@ -50,12 +53,13 @@ sub ListDomains : StartRunmode {
$template->param( USER_LOCALPART => $l, USER_DOMAINPART => $d);
$template->param( DOMAINS => [
map { { DOMAIN => $_->get_value('fvd')
- , PERMS => &list_perms($_, $authzDN)
+ , PERMS => &list_perms_long($_, $authzDN)
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
+ 1 : 0
};
}
- $domains->sorted('fvd')
+ $domains->sorted('fvd')
]);
return $template->output;
}
@@ -67,34 +71,31 @@ sub ListLocals : Runmode {
my $self = shift;
my %CFG = $self->cfg;
my $suffix = join ',', @{$CFG{ldap_suffix}};
-
+
my ($l,$d) = split /@/, $self->authen->username, 2;
my $authzDN = "fvu=$l,fvd=$d,". $suffix;
my $ldap = $self->ldap_from_auth_user($authzDN);
-
+
my $domainname = (split /\//, $ENV{PATH_INFO}, 3)[1];
-
- my $answer = $ldap->search( base => "fvd=$domainname,$suffix"
- , scope => 'base'
- , filter => 'objectClass=FripostVirtualDomain'
- , deref => 'never'
- , attrs => [ qw/fvd description fripostIsStatusActive
- fripostOptionalMaildrop
- fripostOwner fripostPostmaster/ ]
- );
- die $answer->error if $answer->code;
- my $domain = $answer->entry('0');
-
- my $canedit = 0;
- foreach (qw/fripostOwner fripostPostmaster/) {
- my $x = $domain->get_value($_, asref=>1);
- if (defined $x and grep { $_ eq $authzDN} @$x) {
- $canedit = 1;
- last;
- }
- }
+ # Query *the* matching domain
+ my $domains = $ldap->search( base => "fvd=$domainname,$suffix"
+ , scope => 'base'
+ , filter => 'objectClass=FripostVirtualDomain'
+ , deref => 'never'
+ , attrs => [ qw/fvd description
+ fripostIsStatusActive
+ fripostOptionalMaildrop
+ fripostCanCreateAlias
+ fripostCanCreateList
+ fripostOwner
+ fripostPostmaster/ ]
+ );
+ die $domains->error if $domains->code;
+ die "Error: Domains not found" unless $domains->count;
+ die "Error: Multiple domains found" if $domains->count > 1;
+ # Query the mailboxes under the given domain
my $mailboxes = $ldap->search( base => "fvd=$domainname,$suffix"
, scope => 'one'
, filter => 'objectClass=FripostVirtualMailbox'
@@ -103,9 +104,10 @@ sub ListLocals : Runmode {
fripostIsStatusActive
fripostOptionalMaildrop
fripostMailboxQuota/ ]
- );
+ );
die $mailboxes->error if $mailboxes->code;
+ # Query the aliases under the given domain
my $aliases = $ldap->search( base => "fvd=$domainname,$suffix"
, scope => 'one'
, filter => 'objectClass=FripostVirtualAlias'
@@ -117,6 +119,7 @@ sub ListLocals : Runmode {
);
die $aliases->error if $aliases->code;
+ # Query the lists under the given domain
my $lists = $ldap->search( base => "fvd=$domainname,$suffix"
, scope => 'one'
, filter => 'objectClass=FripostVirtualList'
@@ -129,42 +132,79 @@ sub ListLocals : Runmode {
die $lists->error if $lists->code;
$ldap->unbind;
-
+
+ my $domain = $domains->entry('0');
+ my $perms = &list_perms($domain, $authzDN);
+
my $template = $self->load_tmpl( 'list-locals.html', cache => 1, utf8 => 1
, loop_context_vars => 1
, global_vars => 1 );
+
$template->param( URL => $self->query->url );
$template->param( DOMAIN => $domainname );
$template->param( USER_LOCALPART => $l, USER_DOMAINPART => $d);
- $template->param( DESCRIPTION => join ("\n", $domain->get_value('description')) );
- $template->param( ISACTIVE => $domain->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0 );
- $template->param( CANEDIT => $canedit );
+ $template->param( DESCRIPTION =>
+ join ("\n", $domain->get_value('description')) );
+ $template->param( ISACTIVE =>
+ $domain->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0 );
+ # Can the user edit the domain (change description, toggle
+ # activation, modify catchalls?)
+ $template->param( CANEDIT => $perms =~ /[op]/ );
+
+ # Can the user add mailboxes?
+ $template->param( CANADDMAILBOX => $perms =~ /p/ );
+ # Should we list mailboxes?
+ $template->param( LISTMAILBOXES => $mailboxes->count || $perms =~ /p/ );
$template->param( MAILBOXES => [
map { { USER => $_->get_value('fvu')
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0
- , FORWARDS => [ map { {FORWARD => $_} } $_->get_value('fripostOptionalMaildrop') ]
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
+ 1 : 0
+ , FORWARDS => [ map { {FORWARD => $_} }
+ $_->get_value('fripostOptionalMaildrop') ]
, QUOTA => $_->get_value('fripostMailboxQuota') // ''
};
}
- $mailboxes->sorted('fvu')
+ $mailboxes->sorted('fvu')
]);
+
+ # Can the user add aliases?
+ $template->param( CANADDALIAS => $perms =~ /[aop]/ );
+ # Should we list aliases?
+ $template->param( LISTMAILBOXES => $mailboxes->count || $perms =~ /p/ );
+ $template->param( LISTALIASES => $aliases->count || $perms =~ /[aop]/ );
$template->param( ALIASES => [
map { { ALIAS => $_->get_value('fva')
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0
- , OWNERS => [ map { {OWNER => &dn2email($_)} } $_->get_value('fripostOwner') ]
- , DESTINATIONS => [ map { {DESTINATION => $_} } $_->get_value('fripostMaildrop') ]
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
+ 1 : 0
+ , OWNERS => [ map { {OWNER => &dn2email($_)} }
+ $_->get_value('fripostOwner') ]
+ , DESTINATIONS => [ map { {DESTINATION => $_} }
+ $_->get_value('fripostMaildrop') ]
};
}
$aliases->sorted('fva')
]);
- $template->param( CATCHALLS => [ map { {CATCHALL => $_} } $domain->get_value('fripostOptionalMaildrop') ] );
+ $template->param( CATCHALLS => [ map { {CATCHALL => $_} }
+ $domain->get_value('fripostOptionalMaildrop') ]
+ , OWNERS => [ ( map { {OWNER => &dn2email($_)} }
+ $domain->get_value('fripostOwner') )
+ , ( map { {OWNER => &dn2email($_)} }
+ $domain->get_value('fripostPostmaster') ) ]
+ , CAODD => $aliases->count % 2 );
+
+ # Can the user add lists?
+ $template->param( CANADDLIST => $perms =~ /[lop]/ );
+ # Should we list lists?
+ $template->param( LISTLISTS => $lists->count || $perms =~ /[lop]/ );
$template->param( LISTS => [
map { { LIST => $_->get_value('fvl')
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0
- , OWNERS => [ map { {OWNER => &dn2email($_)} } $_->get_value('fripostOwner') ]
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
+ 1 : 0
+ , OWNERS => [ map { {OWNER => &dn2email($_)} }
+ $_->get_value('fripostOwner') ]
, TRANSPORT => $_->get_value('fripostListManager')
};
}
@@ -179,11 +219,11 @@ sub EditDomain : Runmode {
my $self = shift;
my %CFG = $self->cfg;
my $suffix = join ',', @{$CFG{ldap_suffix}};
-
+
my ($l,$d) = split /@/, $self->authen->username, 2;
my $authzDN = "fvu=$l,fvd=$d,". $suffix;
my $ldap = $self->ldap_from_auth_user($authzDN);
-
+
my $domainname = (split /\//, $ENV{PATH_INFO}, 3)[1];
if (defined $self->query->param('submit') or
@@ -209,7 +249,8 @@ sub EditDomain : Runmode {
$changes{fripostOptionalMaildrop} = [ @maildrop ];
}
- my $mesg = $ldap->modify( "fvd=$domainname,$suffix", replace => \%changes );
+ my $mesg = $ldap->modify( "fvd=$domainname,$suffix",
+ replace => \%changes );
die $mesg->error if $mesg->code;
}
@@ -228,44 +269,26 @@ sub EditDomain : Runmode {
$template->param( URL => $self->query->url );
$template->param( USER_LOCALPART => $l, USER_DOMAINPART => $d);
$template->param( DOMAIN => $domainname );
- $template->param( DESCRIPTION => join ("\n",$answer->get_value('description')) );
- $template->param( MAILDROP => join ("\n",$answer->get_value('fripostOptionalMaildrop')) );
- $template->param( ISACTIVE => $answer->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0 );
+ $template->param( DESCRIPTION =>
+ join ("\n",$answer->get_value('description')) );
+ $template->param( MAILDROP =>
+ join ("\n",$answer->get_value('fripostOptionalMaildrop')) );
+ $template->param( ISACTIVE => $answer->get_value('fripostIsStatusActive') eq 'TRUE' ?
+ 1 : 0 );
$template->param( NEWCHANGES => defined $self->query->param('submit') );
return $template->output;
}
-# This subroutine displays the access that the given DN has on the entry.
-# Possible values are :
+# This subroutine displays the access that the given DN has on the entry
+# (long version). Possible values are :
# - "can create aliases" (a)
# - "can create lists" (l)
# - "can create aliases & lists" (al)
# - "owner" (o)
# - "postmaster" (p)
-sub list_perms {
- my ($entry, $dn) = @_;
- my $perms = '';
-
- my $canCreateAlias = $entry->get_value ('fripostCanCreateAlias', asref => 1);
- $perms .= 'a'
- if defined $canCreateAlias and
- grep { $dn eq $_ or (split /,/,$dn,2)[1] eq $_ }
- @{$canCreateAlias};
-
- my $canCreateList = $entry->get_value ('fripostCanCreateList', asref => 1);
- $perms .= 'l'
- if defined $canCreateList and
- grep { $dn eq $_ or (split /,/,$dn,2)[1] eq $_ }
- @{$canCreateList};
-
- my $owner = $entry->get_value ('fripostOwner', asref => 1);
- $perms = 'o'
- if defined $owner and grep { $dn eq $_ } @{$owner};
-
- my $postmaster = $entry->get_value ('fripostPostmaster', asref => 1);
- $perms = 'p'
- if defined $postmaster and grep { $dn eq $_ } @{$postmaster};
+sub list_perms_long {
+ my $perms = &list_perms(@_);
if ( $perms =~ /a/) {
return 'can create aliases & lists' if ( $perms =~ /l/);
@@ -282,6 +305,29 @@ sub list_perms {
}
}
+# This subroutine displays the access that the given DN has on the entry
+# (short version).
+sub list_perms {
+ my ($entry, $dn) = @_;
+ my $perms = '';
+
+ $perms .= 'a'
+ if grep { $dn eq $_ or (split /,/,$dn,2)[1] eq $_ }
+ $entry->get_value ('fripostCanCreateAlias');
+
+ $perms .= 'l'
+ if grep { $dn eq $_ or (split /,/,$dn,2)[1] eq $_ }
+ $entry->get_value ('fripostCanCreateList');
+
+ $perms = 'o'
+ if grep { $dn eq $_ } $entry->get_value('fripostOwner');
+
+ $perms = 'p'
+ if grep { $dn eq $_ } $entry->get_value('fripostPostmaster');
+
+ return $perms;
+}
+
# This method SASL binds the web application and uses the provided
# authorization DN.
@@ -289,18 +335,21 @@ sub ldap_from_auth_user {
my $self = shift;
my $authzDN = shift;
- my $ldap = Net::LDAP->new( $self->cfg('ldap_uri'), async => 1, onerror => 'die' );
- my $sasl = Authen::SASL->new( mechanism => 'DIGEST-MD5'
- , callback => { user => $self->cfg('ldap_authcID')
- , pass => $self->cfg('ldap_authcPW')
- , authname => "dn:$authzDN" }
- );
- my $mesg = $ldap->bind( sasl => $sasl ) ;
+ my $ldap = Net::LDAP->new( $self->cfg('ldap_uri'),
+ async => 1, onerror => 'die' );
+ my $sasl = Authen::SASL->new(
+ mechanism => 'DIGEST-MD5',
+ callback => { user => $self->cfg('ldap_authcID')
+ , pass => $self->cfg('ldap_authcPW')
+ , authname => "dn:$authzDN" }
+ );
+ my $mesg = $ldap->bind( sasl => $sasl );
die $mesg->error if $mesg->code;
return $ldap;
}
+# Converts a DN into an email.
sub dn2email {
my $dn = shift;
$dn =~ /^fv[ual]=([^,]+),fvd=([^,]+),/ or return '';
diff --git a/template/list-domains.html b/template/list-domains.html
index b933167..f57d448 100644
--- a/template/list-domains.html
+++ b/template/list-domains.html
@@ -19,7 +19,7 @@
</div>
<hr/>
- <h1>Manage domains<span class="add">[<a href="<TMPL_VAR NAME=URL>/?a=AddDomain">add domain</a>]<span></h1>
+ <h1>Manage domains<span class="add">[<a href="<TMPL_VAR NAME=URL>/?a=AddDomain">add</a>]<span></h1>
<table class="list">
<thead>
diff --git a/template/list-locals.html b/template/list-locals.html
index 76b86ca..60d4581 100644
--- a/template/list-locals.html
+++ b/template/list-locals.html
@@ -27,7 +27,10 @@
<p>Domain status: <b><TMPL_IF NAME=ISACTIVE><span class="active">Active</span><TMPL_ELSE><span class="inactive">Inactive</span></TMPL_IF></b><p>
- <h3>Mailboxes<span class="add">[<a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/?a=AddUser">add</a>]</span></h3>
+ <TMPL_IF NAME=LISTMAILBOXES>
+ <h3>Mailboxes<TMPL_IF NAME=CANADDMAILBOX
+ ><span class="add">[<a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/?a=AddUser">add</a>]</span
+ ></TMPL_IF></h3>
<table class="list">
<thead>
@@ -53,11 +56,15 @@
</TMPL_LOOP>
</tbody>
</table>
+ </TMPL_IF>
<br/>
- <h3>Aliases<span class="add">[<a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/?a=Addlias">add</a>]</span></h3>
+ <TMPL_IF NAME=LISTALIASES>
+ <h3>Alias<TMPL_IF NAME=CANADDALIAS
+ ><span class="add">[<a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/?a=AddAlias">add</a>]</span
+ ></TMPL_IF></h3>
<table class="list">
<thead>
@@ -82,19 +89,26 @@
</tr>
</TMPL_LOOP>
<TMPL_IF NAME=CATCHALLS>
- <td>*</td>
- <td>Catch-all alias(es) for domain <tt><TMPL_VAR NAME=DOMAIN></tt>.</td>
- <td><TMPL_IF NAME=ISACTIVE><span class="active">&#x2714;</span><TMPL_ELSE><span class="inactive">&#x2718;</span></TMPL_IF></td>
- <td></td>
- <td><TMPL_LOOP NAME=CATCHALLS><tt><TMPL_VAR NAME=CATCHALL></tt><TMPL_UNLESS NAME=__last__>, </TMPL_UNLESS></TMPL_LOOP></td>
+ <TMPL_IF NAME=CAODD><tr class="odd"><TMPL_ELSE><tr></TMPL_IF>
+ <td>*</td>
+ <td>Catch-all alias(es) for domain <tt><TMPL_VAR NAME=DOMAIN></tt>.</td>
+ <td><span class="dunno">&#x2014;</span></td>
+ <td><TMPL_UNLESS NAME=OWNERS><span class="none">(none)</span></TMPL_UNLESS>
+ <TMPL_LOOP NAME=OWNERS><tt><TMPL_VAR NAME=OWNER></tt><TMPL_UNLESS NAME=__last__>, </TMPL_UNLESS></TMPL_LOOP></td>
+ <td><TMPL_LOOP NAME=CATCHALLS><tt><TMPL_VAR NAME=CATCHALL></tt><TMPL_UNLESS NAME=__last__>, </TMPL_UNLESS></TMPL_LOOP></td>
+ <tr>
</TMPL_IF>
</tbody>
</table>
+ </TMPL_IF>
<br/>
- <h3>Lists<span class="add">[<a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/?a=Addlist">add</a>]</span></h3>
+ <TMPL_IF NAME=LISTLISTS>
+ <h3>Lists<TMPL_IF NAME=CANADDLIST
+ ><span class="add">[<a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/?a=AddList">add</a>]</span
+ ></TMPL_IF></h3>
<table class="list">
<thead>
@@ -119,6 +133,7 @@
</TMPL_LOOP>
</tbody>
</table>
+ </TMPL_IF>
</body>