=pod

=head1 NAME

repocafe - self-service for svn hosting

=head1 USAGE

Repocafe helps admins and users to manage subversion repositories.

=over 4

=item *

Admins can easily set up svn hosting.

=item *

Users can create repositories and manage access rights,
using a web application.

=item *

Authentication is ldap based, but guest accounts can be created as well.

=back

Central to a repocafe installation is the I<config file>.
It is used by the web application, and all setup- and support scripts.

Creating a config file is the biggest part of setting up a repocafe.

=head1 CONFIG FILE

=head2 location

The default locations of the config file are :

=over

=item * B<./repocafe.conf>

=item * B<$HOME/.repocafe.conf>

=item * B</etc/repocafe.conf>

=back

=head2 syntax

A config file looks like this :

  +--------------------------------------------------
  |# lines that start with '#' are comment
  |# blank lines are ignored too
  |# tabs are replaced by a space
  |
  |# the config entries are 'key' and 'value' pairs
  |# a 'key' begins in column 1
  |# the 'value' is the rest of the line
  |somekey  part1 part2 part3 ...
  |otherkey part1 part2 part3 ...
  |
  |# keyword EMPTY represents the empty string ;
  |# in the next line some_key's part2 is set to ''
  |somekey part1 EMPTY part3 ...
  |
  |# indented lines are glued
  |# the next three lines mean 'somekey part1 part2 part3'
  |somekey part1
  |  part2
  |  part3
  |
  |# lines starting with a '+' are concatenated
  |# the next three lines mean 'somekey part1part2part3'
  |somekey part1
  |+ part2
  |+ part3
  |
  |# lines starting with a '.' are glued too
  |# don't use a '.' on a line by itself
  |# 'somekey' gets the value "part1\n part2\n part3"
  |somekey part1
  |. part2
  |. part3
  +--------------------------------------------------

In some places in the config (so indicated below) you can glue a
"string with spaces" into one I<part> by replacing spaces with
underscores as in C<string_with_spaces>.

=head2 config file : required entries

=over 4

=item dir_admin I<path>

Specify the full pathname of the C<admin> tree.

  dir_admin /path/to/admin-tree

=item dir_www I<path>

Specify the full pathname of the C<www> tree.

  dir_www /path/to/www-tree

=item dir_data I<path>

Specify the full pathname of the directory where the data lives.

  dir_data /path/to/data-tree

The data directory is created by C<setup-data> in the setup phase.
It contains subdirectories C<admin>, C<archive>, C<logs> and C<repos>.

=item organisation I<html>

Specify the name of your organisation ; this will be embedded in the
user documention, so an url is fine.

  organisation <a href="http://www.my.org">my organisation</a>

=item db_host I<host>

Specify the hostname of your database server

  db_host pghost.some.name.org

=item db_name I<name>

Specify the name of the database where the repocafe tables live.

See I<db_pref> below.

=item db_user I<user>

Specify the username for the database connections in applications.

=item db_pswd I<password>

Specify the password for the database connections in applications.

=item admin_user I<name>

Specify the uid (name or number) of the user who owns the files in
the admin tree and the www tree.
This information is used only in the setup-scripts.

=item admin_group I<name>

Specify the gid (name or number) of the I<admin_user>.
This information is used only in the setup-scripts.

=item www_user I<name>

Specify the uid (name or number) of the apache httpd run-user
(APACHE_RUN_USER). All files created by the httpd (including
the repositories, logs etc) will be owned by this uid.
This information is used only in the setup-scripts.

=item www_group I<name>

Specify the gid (name or number) of the I<www_user> (APACHE_RUN_GROUP).
This information is used only in the setup-scripts.

=item www_server I<name>

Specify the name of your web server

  www_server repocafe.science.uu.nl

=item www_secret I<string>

Specify a long, I<secret> (random) string ; this secret is used in the
web applications to checksum the contents of sessions, protect
plots from prying eyes etc.

  www_secret %SECRET%

Your secret should be random, and at least 16 characters long.

=item www_contact I<string>

Specify an email address, so users can contact the svn-admins.

  www_contact svn-admins@my.org

This address is also used in (the default for) the From:-line of
mail sent to guests ; see C<mail_from_admin>.

=item clas I<class> ldap I<ldap-tag> I<pattern> [I<description>]

=item clas guests table repo_guests login passwd name [I<description>]

Specify one or more I<user classes>.
When a user attempts to login, the clas-lines are tried in turn
to verify the user's username and password. The line that
succeeds, determines the logged-in user's I<class>.

The I<description> should describe the user class (staff, students,
sales, marketing).
Write blanks as underscores to make it a single string.
The descriptions are shown on the login page, and should explain
which users should use what username/passwd.
The default for I<description> is the configured I<class>.

=begin html

For an <i>ldap user class</i>, the ldap server, identified by
<a href="#item_ldap_tag_ldap_2dhost_base__5bdescription_5d">
<i>ldap-tag</i></a>, is queried anonymously.
If/when a DN is returned, it is matched against <i>pattern</i>.
If it matches, an authenticated bind is done. If it succeeds,
the user is authenticated. Use optional config entry
<a href="#item_ldap_tag_ldap_2dhost_base__5bdescription_5d">
<tt>ldap</tt></a>
to configure ldap-servers.

=end html

=begin man

.Sp
For an \fIldap user class\fR, the ldap server, identified by \fIldap-tag\fR,
is queried anonymously. If/when a \s-1DN\s0 is returned, it is matched
against \&\fIpattern\fR. If it matches, an authenticated bind is done.
If it succeeds, the user is authenticated.
.Sp
See also optional config entry \fIldap\fR.

=end man

For the I<guests user class>, a database table lookup is done.
If it succeeds and the password matches, the user's class is 'guests'.
If you want guests, copy this line into the config:

  clas guests table repo_guests login passwd name

The extra parameters (table, repo_guests, login, passwd, name)
are there for possible future enhancements.

A simple setup would be :

  ldap myldap ldap.your.org ou=people,dc=my.org,dc=nl usual
  clas guests table repo_guests login passwd name
  clas user   ldap myldap ,ou=people my.org_users

You have guest accounts, and one class of ldap users.
The login page says :

    guests       : use the login/password we sent you
    my.org users : use your usual login/password

A more complicated example :

  ldap sci ldap.science.uu.nl dc=science,dc=uu,dc=nl solis-id/password
  ldap art ldap.arts.uu.nl    dc=arts,dc=uu,dc=nl    arts.uu.nl_id

  clas guests   table repo_guests login passwd name
  clas sci      ldap sci ou=staff,ou=users     science_staff
  clas edu      ldap sci ou=students,ou=users  science_students
  clas staff    ldap art ou=people,ou=staff    arts_staff
  clas students ldap art ou=people,ou=students arts_students

Here we define two ldap servers, one for 'science' (with usernames
known as I<solis id's>) and one for 'arts' (with I<arts.uu.nl id's>).

We have five user classes: I<guests>, I<science> staff and students,
I<arts> staff and students.

=item tree I<path> I<prefix> [I<user-classes>]

Specify one or more I<tree>-lines. It describes how actual repository
names are structured. Field I<user-classes> is a (possibly empty)
comma-separated list of user classes (eg C<staff,students>).

When a user creates a repository, he/she supplies an alpha-numeric
I<name> for the repository. Optionally, this I<name> is prefixed
with a tag that depends on the user's class and/or username.
For instance, if you want staff repository names to be prefixed
with 'stf', and student's repository names with 'edu', you specify

  tree stf %p staff
  tree edu %p student

If you want student's repository names prefixed with
'edu.I<loginname>', you specify

  tree edu %p.%o student

Admins can create repositories in all trees ; if no I<user-classes>
are specified in a tree-line, users are told repositories in that
tree can be created I<on request>. You configure :

  tree <path> <prefix> EMPTY

For a simple, I<flat> namespace, specify

  tree EMPTY EMPTY clas1,clas2,clas3

where keyword  C<EMPTY> represents the empty string and I<clas1,clas2,clas3>
sums up the user classes that may create repositories.
The name of a repository will be the name supplied by
the owner/creator of the repository.

In general, each tree-line specifies which user classes can create
repositories prefixed with the given I<path>. The actual repository
names are generated by substituting, in the given I<prefix>,
the given I<path> for '%p' and the username of the creator for '%o'.

B<Caveat>: Once you configure a certain tree layout, you can't change
or remove a tree-line, if/when repositories in that tree have been created.
The actual file path of a new repository isn't saved in the database
after creation. Instead, the pathname is recomputed each time when needed,
based on I<tree>, I<owner> and I<name> and the config file. So, if/when the
(user or tree) config changes, we can't compute the proper repo's pathname
from the info in the database. Hm, a quick fix seems obvious. However,
the best solution would be to put user/tree stuff in the database and
under application control, so a change in 'config' could result in a proper
'renaming' of repo's.

=back

=head2 config file : optional entries

=over 4

=item create_guests I<clas1> I<clas2> ...

Optionally specify the classes of users that may create I<guests>.

  create_guests staff

If only admins may create guests, don't specify C<create_guests>
or configure

  create_guests EMPTY

=item no_viewvc

If you don't have package I<viewvc> installed (yet), configure

  no_viewvc

to get rid of the (non-working) C<viewvc>-urls in the web pages.

=item no_groups

If you don't want your repocafe to have I<groups>, configure

  no_groups

=item motd I<html>

Optionally specify a I<message-of-the-day> which will be displayed
prominently on every page.

=item ldap I<tag> I<ldap-host> I<base> [I<description>]

Optionally specify one or more I<ldap-host>s that can authenticate users.
When a user attempts to login, the I<ldap-host>s are queried,
using base I<base>.

The I<description> should be name for the username/password
verified by the ldap (I<school id>, I<unix/linux>, I<usual>).
The descriptions are shown on the login page, and should explain
which users should use what username/passwd.
Write blanks as underscores to make it a single string.

  ldap cs ldap.cs.uu.nl dc=cs,dc=uu,dc=nl cs.uu.nl_user_id

The default for I<description> is the configured I<tag>.

See optional configuration entries C<bind> and C<attr>
for more configuration options.

=item bind I<ldap-tag> I<binddn> I<bindpw>

Optionally specify a I<dn> and I<password> for the indicated ldap-server ;
useful only if the ldap-server does not allow anonymous binds.

=item attr I<ldap-tag> I<login> I<full-name> I<email>

Optionally specify the attribute-names for the indicated ldap-server.

The default is

  attr <ldap-tag> uid cn mail

Some ldap-servers use this set of attribute-names :

  attr <ldap-tag> cn displayName mail

=item top_head I<html>

=item aux_head I<html>

Optionally specify some html to be included at the beginning
(end) of the C<HEAD>-section of every page.

=item top_body I<html>

=item aux_body I<html>

Optionally specify some html to be included at the beginning
(end) of the C<BODY>-section of every page.

=item top_rules_usage I<html>

Optionally specify one or more I<LI> items to be included in the
user documentation page, as the first bullets under I<rules - usage>.

  top_rules_usage <LI>never, never, ....
    <LI>always follow instructions of ....

=item aux_rules_usage I<html>

Optionally specify one or more I<LI> items to be included in the
user documentation page, as the last bullets under I<rules - usage>.

  aux_rules_usage <P>
    <LI>finally, remember that ...

=item top_statistics I<html>

Optionally specify one or more I<LI> items to be included in the
user documentation page, as the first bullets under I<statistics>.

=item aux_statistics I<html>

Optionally specify one or more I<LI> items to be included in the
user documentation page, as the last bullets under I<statistics>.

=item db_pref I<prefix>

Optionally specify a I<prefix> for the names of all
database tables. The default is EMPTY ('') ; a prefix
must be all lowercase.

=item db_owner I<user>

Optionally specify a the I<owner> of the database.
This user must be allowed to create/drop tables etc.
it is used to connect to the database in the C<setup-db>
and C<upd-admins> scripts script. The default is EMPTY ('').

=item db_opswd I<password>

Optionally specify the database I<password> of the database I<owner> ;
it is used to connect to the database in the C<setup-db>
and C<upd-admins> scripts. The default is EMPTY ('').

=item mail_from_admin

Optionally specify the From: address used in mail to guests ;
by default, the configured C<www_contact> mail address is used.

=item mail_from_noreply

Optionally specify the From: address used in I<commit> emails ;
by default, C<svn-no-reply@>I<www_server> is used ;
where C<www_server> is the configured www server hostname.

=item www_scheme I<http> B<|> I<https>

Optionally specify the I<scheme> for the I<www_server> ;
the default is

  www_scheme https

=item file_access I<filename>

Optionally specify the name of the svn accessfile.
The default is 'svnaccessfile'.

=item file_guests I<filename>

Optionally specify the name of the DB file where the apache server
looks up the guests' credentials. The default is 'guestusers'.

=item file_log I<filename>

Optionally specify the name of the file where logins/outs etc are logged.
The default is C<repocafe_log>.

=item cmd_commit_email I<command>

This option now obsolete.

=item cmd_svnadmin I<path>

Optionally specify the full pathname of the B<svnadmin> command.
The default is C</usr/bin/svnadmin>.

=item cmd_svnlook I<path>

Optionally specify the full pathname of the B<svnlook> command.
The default is C</usr/bin/svnlook>.

=item cmd_perl I<path>

Optionally specify the full pathname of the B<perl> command.
The default is C</usr/bin/perl>.

=back

=head1 SUPPORT SCRIPTS

The setup support scripts are documented in section C<INSTALLATION>.

=head2 maintenance

=over 4

=item * mk_stats

Program B<mk_stats> collects version and size info of each repository.
It should be run daily by cron from the configured directory I<dir_admin>.

  42 05 * * * ( cd <dir_admin> ; /usr/bin/perl mk_stats -f )

A plot is genererated by C<gnuplot>.

%MK_STATS%

=item * upd-xusers

Program B<upd-xusers> updates table C<repo_xusers> (ex-users).
It should be run daily by cron from the configured directory I<dir_admin>.

  44 05 * * * ( cd <dir_admin> ; /usr/bin/perl upd-xusers -f )

Running it as C<upd-xusers -l -v> will show a detailed list of all logins.

%UPD_XUSERS%

=back

=head2 system

The scripts in this section are called by the php programs.
Normally, they are not used by repocafe admins.

=over 4

=item mail-watchers

After a commit, program C<mail-watchers> notifies (by mail) the
repository's watchers. It inspects the I<diff>, which contains
various I<parts>.
A user is notified if he/she is a watcher of any I<part>.
The notification mail contains only the relevant parts of the I<diff>.

%MAIL_WATCHERS%

=item mk_guest_list

Program C<mk_guest_list> creates the DB file, used by the httpd
to authenticate guests.

%MK_GUEST_LIST%

=item new-post-commit

Program C<new-post-commit> creates post-commit hooks.

%NEW_HOOKS%

=back

=head1 INSTALLATION

=head2 requirements, pre-setup considerations

=over 4

=item * required : perl

Required Perl modules : C<DBI>, C<DBD::Pg>, C<Net::LDAP>, C<SVN::Notify>

=item * required : a secure apache web server

Because the application handles usernames and passwords,
the webserver should support I<https> connections and have
a valid certificate.

The statistics plots use 'jpgraph', which is easy to install.
The daily plots are generated with I<gnuplot>.

The software now runs on apache 2.2 with php-5 ; C<mod_dav> is required.

=item * summary for I<Ubuntu Server>

To dress up an Ubuntu Server (10.10), you need the following :

  sudo apt-get install apache2
  sudo apt-get install subversion
  sudo apt-get install apache2 libapache2-svn
  sudo apt-get install libapache2-mod-php5
  sudo apt-get install perl
  sudo apt-get install postgresql
  sudo apt-get install gnuplot-nox
  sudo apt-get install libdbi-perl
  sudo apt-get install libdbd-pg-perl
  sudo apt-get install libnet-ldap-perl 
  sudo apt-get install php5-ldap
  sudo apt-get install php5-pgsql
  sudo apt-get install libio-socket-ssl-perl
  sudo apt-get install viewvc
  sudo a2enmod authn_alias
  sudo a2enmod authn_dbm
  sudo a2enmod rewrite
  sudo a2enmod ssl
  sudo a2enmod ldap
  sudo a2enmod authnz_ldap

Edit /etc/viewvc/viewvc.conf :

  root_parents = %%DIR_DATA%%/repos : svn
  docroot = /viewvc-doc

JPGraph: dowload and install latest version from jpgraph website, because the
packages distributed in Ubuntu are old (version 1.5) ; possibly due to the
license of jpgraph (commercial, but free for opensource and non-profit use).

=item * required : a postgresql database

Repocafe needs some postgresql database tables to store information.
To set up the database, talk to your database administrator (DBA).

First determine a database I<user> (username, password) that can
I<select/delete/update> the tables ; you configure :

  db_user ...
  db_pswd ...

How you obtain a new, empty database depends on your DBA.

B<If your DBA lets you own a database>, determine a database
I<owner> (username, password).

Ask your DBA to create a database C<repocafe> where I<owner> has
been granted all priviliges :

  CREATE DATABASE repocafe WITH OWNER <owner>

or

  CREATE DATABASE repocafe
  GRANT ALL ON DATABASE repocafe TO <owner>

You configure the database owner's username and password :

  db_owner ....
  db_opswd ....

B<If your DBA can't let you own a database>, she has to create the
database tables for you. There are two cases :

=over 4

=item 1 the DBA wants to create the tables in a new database

You configure :

  db_pref  EMPTY
  db_owner EMPTY
  db_opswd EMPTY

=item 2 the DBA wants to create the tables in an existing database

Now your DBA may want to prefix the table names with a common prefix
I<my_prefix>. You configure :

  db_pref  <my-prefix>
  db_owner EMPTY
  db_opswd EMPTY

=back

When you have finished creating your config, send your DBA the output of

  setup-db -sql

The DBA can create the tables for you, and your database setup is complete.

=item * consideration : structure repocafe's repository names

If you expect that your users will create many (hundreds of)
repositories, and you have two or more identifiable user groups,
you may want to divide up the repository name space, so the
repository overviews will look more I<organised>. For details,
see the config entries for I<user> and I<tree>. Please note that
if you decide not to structure your name space, adding (or changing)
structure later, will require a lot of hand-work.

=back

=head2 download the software

Checkout the software ; the latest release :

  checkout https://svn.science.uu.nl/repos/project.repocafe.dev/release

or the development version (recommended) :

  checkout https://svn.science.uu.nl/repos/project.repocafe.dev/trunk

The I<development version> (C<trunk>) is stable and used in production
by the authors.

The distro has two parts : the C<admin> tree and the C<www> tree.
The C<admin> tree is used for setup and maintenance ;
the C<www> tree will be your apache's DOCUMENTROOT.

Later, you can move each tree to a new location ; if you do,
remember to fix the config file and C<www/local.ppp> (see below).

=head2 setup

=over 4

=item * documentation

The documentation is in de C<admin/doc> directory :

=over 4

=item - C<repocafe.html>

a html page

=item - C<repocafe.1>

a C<man(1)> source

=item - C<repocafe.txt>

a formatted man page

=back

All three pages contain the same information.

=item * the config file

In the C<admin> tree, create the config file C<repocafe.conf>.
Here is a start :

  organisation <a href="http://www.my-org.org/">
  . Name of My Organisation</a>

  dir_admin /path/to/admin/tree
  dir_data  /path/to/data/tree
  dir_www   /path/to/www/tree

  admin_user  <some uid>
  admin_group <some gid>

  www_user    <some uid>
  www_group   <some gid>
  www_server  repocafe.my-org.org
  www_secret  **********
  www_contact svn-admin@my-org.org

  db_host  pghost.my-org.org
  db_name  repocafe
  db_user  apache
  db_pswd  **********

  ldap my_tag ldap.my-org.org dc=my-org,dc=nl usual

  clas users  ldap my_tag ou=people my-org_users
  clas guests table repo_guests login passwd name

  # users and guests can create repositories

  tree EMPTY EMPTY users,guests

Test the config by running C<configtest>.

Program B<configtest> just loads the config ; any detected errors will
be shown. Optionally, it connects to the database as the configured
database user I<db_user> or I<db_owner>. The program can also test
the ldap connections(s).

%CONFIGTEST%

=item * I<setup-data>

Run B<setup-data> to setup the various files and directories.
It should run as root so it can chown stuff to I<www_user>/I<www_group>.

%SETUP_DATA%

=item * I<setup-vhost>

Run B<setup-vhost> ; it shows (on STDOUT) the suggested vhost setup.
Catch the output and use it to set up an appropriate apache vhost.
Use C<-a> to see the suggested apache I<authconfig>.

You may have to tweak the vhost and auth configs to make them fit in
your distro's default apache setup.

%SETUP_VHOST%

=item * I<setup-db>

If you own the repocafe database, you can use program C<setup-db>
to setup the repocafe tables.

If not, you can send your DBA the output of

  setup-db -sql

and she can create the tables for you.

Please note:

=over 4

=item 1 program I<setup-db> should only be used during setup and upgrades

=item 2 always do dry-runs before forcing action with option C<-f>

=back

Program C<setup-db> checks the database for the presence of required
tables, contraints, triggers etc.

After doing a dry-run, create/fix the database setup with option C<-f>.
When upgrading, make a backup of your database before you use
program C<setup-db> ; always use dry-runs.

B<Repocafe> requires that database-language I<plpgsql> is enabled
for the repocafe database. To check if it is, use :

  SELECT * FROM pg_catalog.pg_language WHERE lanname = 'plpgsql'

Program C<setup-db> will attempt to I<create> the language,
if it is not enabled for your database :

  CREATE LANGUAGE plpgsql

but may lack permission. To avoid the problem, make sure language
C<plpgsql> is enabled for the repocafe databse, I<before> running
program C<setup-db> :

=over 4

=item 1 use program C<psql> to check :

  SELECT * FROM pg_catalog.pg_language WHERE lanname = 'plpgsql' ;

=item 2 if the selection is empty, attempt to I<create> the language

  CREATE LANGUAGE plpgsql ;

=item 3 if you lack permission, ask your DBA to I<create> the language.

=back

%SETUP_DB%

=item * I<upd-admins>

Define repocafe admins with C<upd-admins>.

Normally, only the configured I<db_owner> can do actual add/deletes,
and database user C<db_user> can only do SELECT and UPDATE on the
I<repo_roots> database table. However, if I<db_owner> or I<db_opswd>
is empty or not configured, the I<db_user>, I<db_pswd> username and
password are used by C<upd-admins>.

Before an admin is added, the specified admin login is looked up.

%UPD_ADMINS%

=item * C<local.ppp>

Check the contents of file C<dir_www/local.ppp>
(created by C<setup-data>) ; it should
contain the full pathname of the config file ; for example :

  <?
  $CONF_ROOT = '/home/repocafe/repocafe.conf' ;
  ?>

Make sure the apache/php config allows php scripts to read
the config file.

=back

=head2 finish

The repocafe setup is now almost complete. A few more details remain :

=over 4

=item * viewvc

Install package viewvc, or do it later ; nothing depends on it.
You can (temporarily) configure

  no_viewvc

to get rid of the (non-working) C<viewvc>-urls in the web pages.

=item * php package C<jpgraph>

Install php package B<jpgraph> ; this should work :

  require_once 'jpgraph/src/jpgraph.php' ;
  require_once 'jpgraph/src/jpgraph_line.php' ;

Package B<jpgraph> is used in C<plot.php>.

=item * C<gnuplot>

Make sure program C<gnuplot> is installed ; it is used by C<mk_stats>
to plot the data.

=item * cron jobs

Remember to setup cronjobs for C<mk_stats> and C<upd-xusers>.

  42 05 * * * ( cd <dir_admin> ; /usr/bin/perl mk_stats -f )
  44 05 * * * ( cd <dir_admin> ; /usr/bin/perl upd-xusers -f )

=item * mail alias

You may want to set an email alias for the configured C<www_contact>.

=item * configuration

If you have configured a (non-EMPTY) I<db_owner> and I<db_opswd>,
you can now remove them from the config.
You will have to put them back in later, if/when you
want to add or delete svn-admins with C<upd_admins>.

=item * feedback

If you got this far, please send some feedback to the authors
(repocafe@cs.uu.nl).
What was the hardest part of setting up the cafe ?
What was unclear (or wrong) ? Ideas for improvement ?

=back

=head1 ADMINISTRATION

After setting up a repocafe, there is not a lot to do for the admins.
Here are a few points an admin should know :

=over 4

=item * active / inactive

When you (an admin) login, you are either I<active> or I<inactive>
(as an admin). When I<active>, you have full admin rights ;
when I<inactive> repocafe treats you as it would any other user.

When you are logged in, every page shows a button with which you
can switch between I<active> and I<inactive>.

=item * guest accounts

Use config_option C<create_guests> to specify which user classes
are allowd to create guests.

Guest accounts are created by web form. You only need to specify
a I<full name> and an I<email address>. A login-name is generated
from the I<full name> ; the login-name and a random password are
mailed to the guest.

When a guest tries to login, and her password fails, the guest can
request that her password is sent to her (again).

A logged-in guest can change her password.

=item * repositories on request

If you have structured your repository names, and the config
has tree-lines without user-classes, then repositories in those
trees can only be created I<on request> ; that means you, because
only the admins can create them.

=item * cleanup the archive

When a user or admin deletes a repository, the repository is moved from
C<dir_data/repos/> to C<dir_data/archive/>. The repository's name
is suffixed with a number, so deleting more than one repository with
the same name, doesn't give a name conflict in C<dir_data/archive>.

On deletion, the repository directory is I<touched>, so with C<ls -lart>
you can list (and remove) the archived repostories by deletion date.

=item * cleanup repositories

In the I<statistics page>, there is a list of I<revision 0> repositories :
repositories that were created, but were used to put stuff in.
The list is ordered by date. You may want to delete them after some
(fixed, announced) time.

The statistics page also has lists of I<unused guests> and
I<unused groups> ; I<unused> meaning I<unreferenced>.

=item * cleanup ex-users

An I<ex-user> is a login-name that appears in a repocafe (as owner,
in the repository rights, or as group member) but can't be found
in the cafe's guest list or ldap(s).

The statistics page shows a list of repositories owned by ex-users.

The statistics page also shows a list of ex-users holding access
rights and/or group memberships. For every ex-user you see :

=over 4

=item 1 the I<repositories> where the ex-user has access rights,

=item 2 the I<groups> where the ex-user is a member,

=item 3 a button to remove all the ex-user's access rights
and group memberships.

=back

=back

=head1 WISHLIST

Here are a few things we would like to add to C<Repocafe> :

=over 4

=item * support for other versioning systems, like C<git>

=item * support for other database systems besides C<postgresql>

=item * support for authentication based on C<active directory>

=item * support for I<disk quota> ; C<lock> users who are exceeding their quota

A base quotum per user-class ; plus a quotum per user.

=back

=head1 AUTHOR

%AUTHOR%

=cut
