- initial import
5
AUTHORS
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
======================
|
||||||
|
Authors of WebDAVAdmin
|
||||||
|
======================
|
||||||
|
|
||||||
|
Jan Dittberner <jan@dittberner.info>
|
211
INSTALL
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
=======================================
|
||||||
|
WebDAVAdmin installation instructions
|
||||||
|
=======================================
|
||||||
|
:Author: Jan Dittberner
|
||||||
|
:Contact: jan@dittberner.info
|
||||||
|
:Version: 0.1
|
||||||
|
:Revision: $Revision$
|
||||||
|
:Date: $Date$
|
||||||
|
:Copyright: Copyright (C) 2007 Jan Dittberner
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Unpack WebDAVAdmin
|
||||||
|
==================
|
||||||
|
|
||||||
|
1. unpack the WebDAVAdmin distribution file somewhere::
|
||||||
|
|
||||||
|
cd ~/tmp/
|
||||||
|
tar xjf webdavadmin-0.1.tar.bz2
|
||||||
|
|
||||||
|
``~/tmp/`` is just an example to be able to reference it in these
|
||||||
|
installation instructions
|
||||||
|
|
||||||
|
Setup PostgreSQL and your database
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Install PostgreSQL by the means of your operating system. For
|
||||||
|
Debian GNU/Linux 4.0 Etch execute::
|
||||||
|
|
||||||
|
sudo aptitude install postgresql-8.1
|
||||||
|
|
||||||
|
2. Switch to user postgres::
|
||||||
|
|
||||||
|
sudo su - postgres
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
1) create a user for WebDAVAdmin::
|
||||||
|
|
||||||
|
createuser -SDRP myuser
|
||||||
|
|
||||||
|
when prompted type the password for the database user twice
|
||||||
|
|
||||||
|
2) create a database::
|
||||||
|
|
||||||
|
createdb --owner=myuser --encoding=UTF-8 mydb
|
||||||
|
|
||||||
|
3) exit the postgres shell
|
||||||
|
|
||||||
|
You may skip theese steps if you want to use an existing database
|
||||||
|
|
||||||
|
3. Import the schema for WebDAVAdmin::
|
||||||
|
|
||||||
|
psql -h localhost -U myuser mydb < ~/tmp/webdavadmin-0.1/setup/schema.sql
|
||||||
|
|
||||||
|
when prompted type the password for your database user.
|
||||||
|
|
||||||
|
Setup Apache
|
||||||
|
============
|
||||||
|
|
||||||
|
1. Install, enable and configure apache and the apache modules
|
||||||
|
|
||||||
|
- mod_dav
|
||||||
|
- mod_dav_fs
|
||||||
|
- mod_auth_pgsql
|
||||||
|
- libphp5
|
||||||
|
|
||||||
|
by the means of your operating system vendor. For Debian GNU/Linux 4.0
|
||||||
|
Etch this means [1]_::
|
||||||
|
|
||||||
|
sudo aptitude install apache2-mpm-prefork libapache2-mod-php5 libapache2-mod-auth-pgsql
|
||||||
|
sudo a2enmod php5
|
||||||
|
sudo a2enmod auth_pgsql
|
||||||
|
sudo a2enmod dav
|
||||||
|
sudo a2enmod dav_fs
|
||||||
|
|
||||||
|
.. [1] if you don't want to use ``sudo`` you may also switch to root.
|
||||||
|
|
||||||
|
2. Configure a VirtualHost to use WebDAV and PostgreSQL
|
||||||
|
authentication, this VirtualHost configuration could look like::
|
||||||
|
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName davhost.yourdomain.net
|
||||||
|
|
||||||
|
DavLockDb /var/run/apache2/davlock/davhost.yourdomain.net
|
||||||
|
DocumentRoot /var/www
|
||||||
|
|
||||||
|
<Directory /var/www/dav>
|
||||||
|
Options Indexes
|
||||||
|
Order allow,deny
|
||||||
|
allow from all
|
||||||
|
|
||||||
|
Dav on
|
||||||
|
|
||||||
|
# Authentication/Authorization
|
||||||
|
AuthType Basic
|
||||||
|
AuthName "WebDAVAdmin example"
|
||||||
|
AuthBasicAuthoritative Off
|
||||||
|
AuthUserFile /etc/apache2/auth/davhost.yourdomain.net.passwd
|
||||||
|
|
||||||
|
Auth_PG_host localhost
|
||||||
|
Auth_PG_port 5432
|
||||||
|
Auth_PG_user myuser
|
||||||
|
Auth_PG_pwd secret
|
||||||
|
Auth_PG_database mydb
|
||||||
|
Auth_PG_pwd_table dav_password
|
||||||
|
Auth_PG_uid_field username
|
||||||
|
Auth_PG_pwd_field password
|
||||||
|
Auth_PG_grp_table dav_group
|
||||||
|
Auth_PG_grp_user_field username
|
||||||
|
Auth_PG_grp_group_field groupname
|
||||||
|
Auth_PG_hash_type MD5
|
||||||
|
#Auth_PG_log_table dav_log
|
||||||
|
#Auth_PG_log_uname_field username
|
||||||
|
#Auth_PG_log_date_field reqdate
|
||||||
|
#Auth_PG_log_uri_field uri
|
||||||
|
#Auth_PG_log_addrs_field ipaddr
|
||||||
|
Auth_PG_authoritative on
|
||||||
|
|
||||||
|
require group davroot
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
ErrorLog /var/log/apache2/davhost.yourdomain.net_error.log
|
||||||
|
CustomLog /var/log/apache2/davhost.yourdomain.net_access.log combined
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
|
||||||
|
The directory specified for ``DavLockDb`` must be writable for the
|
||||||
|
user your apache processes run as. The ``AuthUserFile`` is
|
||||||
|
specified as a fallback if your PostgreSQL database is not
|
||||||
|
available.
|
||||||
|
|
||||||
|
Install required php modules and classes
|
||||||
|
========================================
|
||||||
|
|
||||||
|
WebDAVAdmin needs Smarty and a PostgreSQL PDO driver for PHP5. To
|
||||||
|
install these requirements perform the following step::
|
||||||
|
|
||||||
|
sudo aptitude install smarty php5-pgsql
|
||||||
|
|
||||||
|
on operating systems other then Debian GNU/Linux consult your system
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
Copy WebDAVAdmin files
|
||||||
|
======================
|
||||||
|
|
||||||
|
2. create a new document root directory or a subdirectory inside an
|
||||||
|
existing one
|
||||||
|
|
||||||
|
3. create a subdirectory which you'll later use for WebDAVAdmin::
|
||||||
|
|
||||||
|
mkdir /var/www/dav
|
||||||
|
|
||||||
|
4. copy the admin subdirectory of the unpacked webdavadmin distribution
|
||||||
|
file to the directory just created::
|
||||||
|
|
||||||
|
cp -R webdavadmin-0.1/admin /var/www/dav/
|
||||||
|
|
||||||
|
5. set the filesystem permissions of the dav directory to allow the
|
||||||
|
user apache is running as to write to the directory
|
||||||
|
|
||||||
|
Configure WebDAVAdmin
|
||||||
|
=====================
|
||||||
|
|
||||||
|
The WebDAVAdmin distribution contains a directory ``config`` with
|
||||||
|
configuration templates that you need to customize for your
|
||||||
|
environment.
|
||||||
|
|
||||||
|
1. ``dbsettings.inc.php``
|
||||||
|
|
||||||
|
This file contains the settings for your database connection. The
|
||||||
|
file should be placed outside the document root for security
|
||||||
|
reasons. A customized version of this file may look like::
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/** Data source name. */
|
||||||
|
$dsn = "pgsql:host=localhost port=5432 dbname=mydb";
|
||||||
|
/** Database user. */
|
||||||
|
$dbuser = "myuser";
|
||||||
|
/** Database password. */
|
||||||
|
$dbpass = "secret";
|
||||||
|
?>
|
||||||
|
|
||||||
|
2. ``config.inc.php``
|
||||||
|
|
||||||
|
This file contains the absolute path to your WebDAVAdmin
|
||||||
|
installation and to your ``dbsettings.inc.php``. A customized
|
||||||
|
version of this file could be::
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/** DAV area root directory. */
|
||||||
|
define(DAV_ROOT, '/var/www/dav');
|
||||||
|
|
||||||
|
/** Include the database settings. */
|
||||||
|
include_once('/etc/webdavadmin/dbsettings.inc.php');
|
||||||
|
?>
|
||||||
|
|
||||||
|
After adapting the contents to your environment put this file into
|
||||||
|
your WebDAVAdmin directory. For example::
|
||||||
|
|
||||||
|
cp config.inc.php /var/www/dav/admin/
|
||||||
|
|
||||||
|
Be sure to make the subdirectory templates_c of your WebDAVAdmin
|
||||||
|
directory writable for your apache user [2]_.
|
||||||
|
|
||||||
|
.. [2] you could use chown, chmod and/or ACLs to perform this task
|
||||||
|
|
||||||
|
Now you should be able to use your installation of WebDAVAdmin by
|
||||||
|
opening the URL http://davhost.yourdomain.net/dav/admin/ (if you just
|
||||||
|
followed this instructions).
|
||||||
|
|
18
Makefile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
.PHONY: apidoc
|
||||||
|
|
||||||
|
VERSION=0.1
|
||||||
|
PROJECT=webdavadmin
|
||||||
|
SRCFILES=admin/common.inc.php,admin/directories.php,admin/getgroups.php,admin/index.php,admin/users.php
|
||||||
|
|
||||||
|
apidoc:
|
||||||
|
if [ -d apidoc ]; then rm -r apidoc; fi
|
||||||
|
phpdoc -f $(SRCFILES) -t apidoc -s
|
||||||
|
|
||||||
|
clean:
|
||||||
|
find -name '*~' -type f -exec rm {} \;
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
if [ -d apidoc ]; then rm -r apidoc; fi
|
||||||
|
|
||||||
|
dist: distclean
|
||||||
|
cd .. ; tar cjf $(PROJECT)-$(VERSION).tar.bz2 $(PROJECT)-$(VERSION)
|
71
README
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
=============
|
||||||
|
WebDAVAdmin
|
||||||
|
=============
|
||||||
|
:Author: Jan Dittberner
|
||||||
|
:Contact: jan@dittberner.info
|
||||||
|
:Version: 0.1
|
||||||
|
:Revision: $Revision$
|
||||||
|
:Date: $Date$
|
||||||
|
:Copyright: Copyright (C) 2007 Jan Dittberner
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Goals
|
||||||
|
=====
|
||||||
|
|
||||||
|
The goal of this software is to provide an easy to use administration
|
||||||
|
interface for a WebDAV repository using mod-auth-pgsql as its
|
||||||
|
authentication and authorization source.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
============
|
||||||
|
|
||||||
|
To use this software you need an Apache webserver configured with the
|
||||||
|
dav module and mod-auth-pgsql, PHP 5 with PostgreSQL PDO driver, the
|
||||||
|
Smarty_ template engine and a PostgreSQL database. The software has
|
||||||
|
been developed using the versions contained in Debian GNU/Linux 4.0
|
||||||
|
Etch.
|
||||||
|
|
||||||
|
- Apache 2.2.3
|
||||||
|
- PostgreSQL 8.1.8
|
||||||
|
- mod-auth-pgsql 2.0.3
|
||||||
|
- PHP 5.2.0
|
||||||
|
- Smarty 2.6.14
|
||||||
|
|
||||||
|
.. _Smarty: http://smarty.php.net/
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Please see INSTALL_ for installation instructions.
|
||||||
|
|
||||||
|
.. _INSTALL: INSTALL
|
||||||
|
|
||||||
|
Used third party code
|
||||||
|
=====================
|
||||||
|
|
||||||
|
WebDAVAdmin uses the JQuery Javascript library for DOM manipulations
|
||||||
|
and AJAX calls.
|
||||||
|
|
||||||
|
.. _JQuery: http://www.jquery.com/
|
||||||
|
|
||||||
|
Version 1.1.3 of JQuery has been used for developing this software and
|
||||||
|
is bundled in the ``scripts`` directory as ``jquery.js``.
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
02110-1301 USA.
|
6
TODO
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
- create an installer
|
||||||
|
- setup admin user during installation
|
||||||
|
- better integration into existing databases
|
2
admin/.htaccess
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
DirectoryIndex index.php
|
||||||
|
require group davadmin
|
75
admin/common.inc.php
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Common code for WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Include configuration information. */
|
||||||
|
require_once('config.inc.php');
|
||||||
|
|
||||||
|
/** DAV administrator group name. */
|
||||||
|
define(ADMIN_GROUP, 'davadmin');
|
||||||
|
/** DAV administration application subdirectory. */
|
||||||
|
define(ADMIN_DIR, 'admin');
|
||||||
|
|
||||||
|
/** Include the Smarty template engine. */
|
||||||
|
require_once("smarty/libs/Smarty.class.php");
|
||||||
|
|
||||||
|
/** Global Smarty template engine instance. */
|
||||||
|
$smarty = new Smarty();
|
||||||
|
|
||||||
|
/** Handle invalid requests to the application. */
|
||||||
|
function invalidCall() {
|
||||||
|
header("Content-Type: text/plain; charset=UTF-8");
|
||||||
|
print("Ungültiger Aufruf!");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handle errors with an XML message. */
|
||||||
|
function errorAsXml($errormsg) {
|
||||||
|
header("Content-Type: text/xml; charset=UTF-8");
|
||||||
|
$GLOBALS['smarty']->assign("errormsg", $errormsg);
|
||||||
|
$GLOBALS['smarty']->display("error.xml");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handle errors with an HTML error page. */
|
||||||
|
function errorAsHtml($errormsg) {
|
||||||
|
header("Content-Type: text/html; charset=UTF-8");
|
||||||
|
$GLOBALS['smarty']->assign("errormsg", $errormsg);
|
||||||
|
$GLOBALS['smarty']->display("error.html");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a PDO statement error.
|
||||||
|
*
|
||||||
|
* @param PDOStatement $sth statement handle
|
||||||
|
*/
|
||||||
|
function statementErrorAsXml(&$sth) {
|
||||||
|
errorAsXml(utf8_encode(implode("\n", $sth->errorInfo())));
|
||||||
|
}
|
||||||
|
?>
|
331
admin/directories.php
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Directory administration code.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Include common code. */
|
||||||
|
include_once('common.inc.php');
|
||||||
|
|
||||||
|
/** Format string for group lines in .htaccess files. */
|
||||||
|
define('GROUPLINEFORMAT', "require group %s\n");
|
||||||
|
|
||||||
|
/** Regular expression for finding group lines in .htaccess files. */
|
||||||
|
define('GROUPLINERE', '/^require\s+group\s+(.*)$/i');
|
||||||
|
|
||||||
|
/** Regular expression matching legal directory names. */
|
||||||
|
define('DIRNAMERE', '/^[a-zA-Z0-9 -_.]+$/');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of mandatory groups. These groups are assigned to every new or
|
||||||
|
* changed directory.
|
||||||
|
*/
|
||||||
|
$mandatorygroups = array(ADMIN_GROUP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the group names allowed to access the given directory from its
|
||||||
|
* .htaccess file. Mandatory groups are excluded.
|
||||||
|
*
|
||||||
|
* @param string $dirname a fully qualified directory name
|
||||||
|
* @return an array of group names
|
||||||
|
*/
|
||||||
|
function getDirGroupsFromHtaccess($dirname) {
|
||||||
|
$htaccessname = $dirname . DIRECTORY_SEPARATOR . ".htaccess";
|
||||||
|
$groups = array();
|
||||||
|
if (false !== ($fh = fopen($htaccessname, "r"))) {
|
||||||
|
while (!feof($fh)) {
|
||||||
|
$buffer = fgets($fh);
|
||||||
|
if (preg_match_all(GROUPLINERE, trim($buffer), $matches)) {
|
||||||
|
$grouparr = explode(" ", $matches[1][0]);
|
||||||
|
foreach ($grouparr as $group) {
|
||||||
|
$group = trim($group);
|
||||||
|
if (!in_array($group, $GLOBALS['mandatorygroups'])) {
|
||||||
|
array_push($groups, $group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($fh);
|
||||||
|
return $groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the names of groups for a directory.
|
||||||
|
*
|
||||||
|
* @param string $dirname directory name relative to {@link DAV_ROOT}
|
||||||
|
* @return an array of group names
|
||||||
|
* @see #getDirGroupsFromHtaccess(string)
|
||||||
|
*/
|
||||||
|
function getDirGroups($dirname) {
|
||||||
|
return getDirGroupsFromHtaccess(DAV_ROOT . DIRECTORY_SEPARATOR . $dirname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the visible files and their accumulated size in a directory
|
||||||
|
* tree.
|
||||||
|
*
|
||||||
|
* @param string $dirname a fully qualified directory name
|
||||||
|
* @param array $retval a two component array index 0 is the file
|
||||||
|
* count, index 2 is the accumulated size of files
|
||||||
|
* @return array updated with the data from subdirectories and files
|
||||||
|
* of $dirname
|
||||||
|
*/
|
||||||
|
function countFilesRecursive($dirname, $retval = array(0, 0)) {
|
||||||
|
$dh = opendir($dirname);
|
||||||
|
while (false !== ($entry = readdir($dh))) {
|
||||||
|
$fullname = $dirname . DIRECTORY_SEPARATOR . $entry;
|
||||||
|
if (strpos($entry, '.') !== 0) {
|
||||||
|
if (is_dir($fullname)) {
|
||||||
|
$retval = countFilesRecursive($fullname, $retval);
|
||||||
|
} else if (is_file($fullname)) {
|
||||||
|
$retval = array($retval[0] + 1, $retval[1] + filesize($fullname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dh);
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data of a directory.
|
||||||
|
*
|
||||||
|
* @param string $dirname a fully qualified directory name
|
||||||
|
* @return array of containing directory data
|
||||||
|
*/
|
||||||
|
function getDirectoryData($dirname) {
|
||||||
|
$dir = array();
|
||||||
|
$dir['name'] = basename($dirname);
|
||||||
|
$dir['groups'] = getDirGroupsFromHtaccess($dirname);
|
||||||
|
list($dir['filecount'], $dir['filesize']) = countFilesRecursive($dirname);
|
||||||
|
$dir['maydelete'] = ($dir['filecount'] == 0) ? 1 : 0;
|
||||||
|
$dir['filesize'] = sprintf("%d kBytes", $dir['filesize'] / 1024);
|
||||||
|
return $dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets XML encoded data of a directory.
|
||||||
|
*
|
||||||
|
* @param string $dirname dirname relative to {@link DAV_ROOT}
|
||||||
|
* @return XML string
|
||||||
|
*/
|
||||||
|
function getDirectoryDataAsXml($dirname) {
|
||||||
|
if (is_dir(DAV_ROOT . $dirname)) {
|
||||||
|
$dirdata = getDirectoryData(DAV_ROOT . $dirname);
|
||||||
|
header("Content-Type: text/xml; charset=UTF-8");
|
||||||
|
return sprintf('<?xml version="1.0" encoding="utf8"?><directory><dirname>%s</dirname><groups>%s</groups><filecount>%d</filecount><filesize>%s</filesize><maydelete>%d</maydelete></directory>', $dirdata['name'], implode(", ", $dirdata['groups']), $dirdata['filecount'], $dirdata['filesize'], $dirdata['maydelete']);
|
||||||
|
} else {
|
||||||
|
errorAsXml(sprintf(_("Invalid directory name %s!"), $dirname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets XML encoded data of a deleted directory.
|
||||||
|
*
|
||||||
|
* @param string $dirname directory name relative to {@link DAV_ROOT}
|
||||||
|
* @return XML string
|
||||||
|
*/
|
||||||
|
function getDeletedDirectoryData($dirname) {
|
||||||
|
header("Content-Type: text/xml; charset=UTF-8");
|
||||||
|
return sprintf('<?xml version="1.0" encoding="utf8"?><directory><dirname>%s</dirname></directory>', $dirname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of directory data for all valid directories below
|
||||||
|
* {@link DAV_ROOT}.
|
||||||
|
*
|
||||||
|
* @return array of directory data arrays
|
||||||
|
* @see #getDirectoryData(string)
|
||||||
|
*/
|
||||||
|
function getDirectories() {
|
||||||
|
$dirs = array();
|
||||||
|
if (false !== ($entries = scandir(DAV_ROOT))) {
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if (is_dir(DAV_ROOT . $entry)) {
|
||||||
|
if (strpos($entry, '.') !== 0) {
|
||||||
|
if ($entry != ADMIN_DIR) {
|
||||||
|
array_push($dirs, getDirectoryData(DAV_ROOT . $entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the groups of a directory in its .htaccess file. Mandatory
|
||||||
|
* groups are added automatically.
|
||||||
|
*
|
||||||
|
* @param string $dirname directory name relative to {@link DAV_ROOT}
|
||||||
|
* @param array &$groups reference to a list of group names
|
||||||
|
*/
|
||||||
|
function setGroups($dirname, &$groups) {
|
||||||
|
$fullname = DAV_ROOT . $dirname;
|
||||||
|
foreach ($groups as $key => $value) {
|
||||||
|
$groups[$key] = trim($value);
|
||||||
|
}
|
||||||
|
foreach ($GLOBALS['mandatorygroups'] as $mgroup) {
|
||||||
|
if (!in_array($mgroup, $groups)) {
|
||||||
|
array_push($groups, $mgroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$found = false;
|
||||||
|
$lines = array();
|
||||||
|
$found = false;
|
||||||
|
if (is_dir($fullname)) {
|
||||||
|
$htaccess = $fullname . DIRECTORY_SEPARATOR . ".htaccess";
|
||||||
|
if (file_exists($htaccess) && (false !== ($fh = fopen($htaccess, "r")))) {
|
||||||
|
while (!feof($fh)) {
|
||||||
|
$buffer = fgets($fh);
|
||||||
|
if (preg_match(GROUPLINERE, $buffer)) {
|
||||||
|
array_push($lines, sprintf(GROUPLINEFORMAT, join(" ", $groups)));
|
||||||
|
$found = true;
|
||||||
|
} else {
|
||||||
|
array_push($lines, $buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($fh);
|
||||||
|
}
|
||||||
|
if (!$found) {
|
||||||
|
array_push($lines, sprintf(GROUPLINEFORMAT, join(" ", $groups)));
|
||||||
|
}
|
||||||
|
if (false !== ($fh = fopen($htaccess, "w"))) {
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
fwrite($fh, $line);
|
||||||
|
}
|
||||||
|
fclose($fh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a directory to be accessible by the given list of
|
||||||
|
* groups. The directory is created if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @param string $dirname directory name relative to {@link DAV_ROOT}
|
||||||
|
* @param array $groups a list of group names
|
||||||
|
*/
|
||||||
|
function updateDirectory($dirname, $groups) {
|
||||||
|
if (preg_match(DIRNAMERE, $dirname, $matches)) {
|
||||||
|
if ($dirname != ADMIN_DIR) {
|
||||||
|
$fullname = DAV_ROOT . $dirname;
|
||||||
|
if (file_exists($fullname)) {
|
||||||
|
if (!is_dir($fullname)) {
|
||||||
|
errorAsXml(sprintf(_("There already is a directory entry named %s, but it's not a directory!"), $dirname));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mkdir($fullname);
|
||||||
|
}
|
||||||
|
setGroups($dirname, $groups);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorAsXml(sprintf(_("Invalid directory name %s!"), $dirname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively deletes the given directory.
|
||||||
|
*
|
||||||
|
* @param string $fullname fully qualified directory name
|
||||||
|
*/
|
||||||
|
function delrecursive($fullname) {
|
||||||
|
$dh = opendir($fullname);
|
||||||
|
while (false !== ($entry = readdir($dh))) {
|
||||||
|
if ($entry != "." && $entry != "..") {
|
||||||
|
$entryname = $fullname . DIRECTORY_SEPARATOR . $entry;
|
||||||
|
if (is_dir($entryname)) {
|
||||||
|
delrecursive($entryname);
|
||||||
|
} else {
|
||||||
|
unlink($entryname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dh);
|
||||||
|
rmdir($fullname);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the given directory if it has a valid name and is not the
|
||||||
|
* administration interface directory.
|
||||||
|
*
|
||||||
|
* @param string $dirname directory name relative to {@link DAV_ROOT}
|
||||||
|
*/
|
||||||
|
function deleteDirectory($dirname) {
|
||||||
|
if (preg_match(DIRNAMERE, $dirname, $matches)) {
|
||||||
|
if ($dirname != ADMIN_DIR) {
|
||||||
|
$fullname = DAV_ROOT . $dirname;
|
||||||
|
if (is_dir($fullname)) {
|
||||||
|
return delrecursive($fullname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorAsXml(_("Tried to delete the administration interface directory!"));
|
||||||
|
}
|
||||||
|
errorAsXml(sprintf(_("Invalid directory name %s!"), $dirname));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_GET) {
|
||||||
|
// handle get requests with data
|
||||||
|
if ($_GET['method']) {
|
||||||
|
switch ($_GET['method']) {
|
||||||
|
case 'getdirectorydata':
|
||||||
|
print getDirectoryDataAsXml($_GET['dirname']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_GET)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
invalidCall();
|
||||||
|
}
|
||||||
|
} elseif ($_POST) {
|
||||||
|
// handle post requests with data
|
||||||
|
if ($_POST['method']) {
|
||||||
|
switch ($_POST['method']) {
|
||||||
|
case 'submitdirectory':
|
||||||
|
updateDirectory($_POST['dirname'], explode(",", $_POST['groups']));
|
||||||
|
print getDirectoryDataAsXml($_POST['dirname']);
|
||||||
|
break;
|
||||||
|
case 'deletedirectory':
|
||||||
|
if (deleteDirectory($_POST['dirname'])) {
|
||||||
|
print getDeletedDirectoryData($_POST['dirname']);
|
||||||
|
} else {
|
||||||
|
errorAsXml(_("Delete failed!"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_POST)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
invalidCall();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// handle requests without data
|
||||||
|
header("Content-Type: text/html; charset=UTF-8");
|
||||||
|
$smarty->assign("directories", getDirectories());
|
||||||
|
$smarty->display("directories.html");
|
||||||
|
}
|
||||||
|
?>
|
47
admin/dynaform.css
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#usereditor {
|
||||||
|
display:none;
|
||||||
|
z-index:10;
|
||||||
|
position:absolute;
|
||||||
|
top:10px;
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynaform {
|
||||||
|
border:2px solid black;
|
||||||
|
background-color:#fffbed;
|
||||||
|
color:#2b2b26;
|
||||||
|
width:380px;
|
||||||
|
padding:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynaform .formelement {
|
||||||
|
padding:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynaform .formelement label {
|
||||||
|
display:block;
|
||||||
|
width:171px;
|
||||||
|
float:left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynaform .formactions {
|
||||||
|
margin-top:5px;
|
||||||
|
border-top:1px solid #ffd436;
|
||||||
|
padding:5px;
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynaform input, .dynaform select
|
||||||
|
{
|
||||||
|
padding:0;
|
||||||
|
width:200px;
|
||||||
|
background-color:#fffbed;
|
||||||
|
color:#2b2b26;
|
||||||
|
border:1px solid #ffd436;
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynaform input[type=submit] {
|
||||||
|
width:auto;
|
||||||
|
}
|
88
admin/format.css
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
html
|
||||||
|
{
|
||||||
|
font-family: Verdana,Helvetica,Arial,sans-serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
background-color:white;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#usertable, #dirtable {
|
||||||
|
border-collapse:collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
#usertable #hcol-username {
|
||||||
|
width:120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#usertable #hcol-name {
|
||||||
|
width:264px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dirtable #hcol-directory {
|
||||||
|
width:120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dirtable #hcol-groups {
|
||||||
|
width:200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dirtable #hcol-files {
|
||||||
|
width:150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#usertable th, #usertable td, #dirtable th, #dirtable td {
|
||||||
|
border:1px solid black;
|
||||||
|
text-align:left;
|
||||||
|
padding:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
display:block;
|
||||||
|
float:left;
|
||||||
|
width:20px;
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
display:block;
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Autocomplete styles
|
||||||
|
*/
|
||||||
|
/* Suggestion list */
|
||||||
|
#autocomplete {
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
#autocomplete ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#autocomplete li {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
white-space: pre;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
#autocomplete li.selected {
|
||||||
|
background: #0072b9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
/* Animated throbber */
|
||||||
|
input.form-autocomplete {
|
||||||
|
background-image: url(images/throbber.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 100% 2px;
|
||||||
|
}
|
||||||
|
input.throbbing {
|
||||||
|
background-position: 100% -18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a img.actionicon {
|
||||||
|
border:0;
|
||||||
|
}
|
69
admin/getgroups.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AJAX autocompletion code for group names.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Include configuration information. */
|
||||||
|
require_once('config.inc.php');
|
||||||
|
|
||||||
|
// output is plain text (JSON or an error message)
|
||||||
|
header("Content-Type: text/plain; charset=UTF-8");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets group names for autocompletion.
|
||||||
|
*
|
||||||
|
* @param string $part Comma separated list of groups and beginning of
|
||||||
|
* a new group entry
|
||||||
|
* @return list of Comma separated lists of groups
|
||||||
|
*/
|
||||||
|
function getGroups($part) {
|
||||||
|
$regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
|
||||||
|
preg_match_all($regexp, $part, $matches);
|
||||||
|
$array = $matches[1];
|
||||||
|
$last_string = trim(array_pop($array));
|
||||||
|
if ($last_string != '') {
|
||||||
|
try {
|
||||||
|
$dbh = new PDO($GLOBALS['dsn'], $GLOBALS['dbuser'], $GLOBALS['dbpass']);
|
||||||
|
$sth = $dbh->prepare("SELECT DISTINCT groupname FROM dav_group WHERE LOWER(groupname) LIKE LOWER(?) ORDER BY groupname");
|
||||||
|
$sth->execute(array("%" . $last_string . "%"));
|
||||||
|
$prefix = count($array) ? implode(",", $array) . ", " : '';
|
||||||
|
$retval = array();
|
||||||
|
foreach ($sth->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
||||||
|
$retval[$prefix . $row['groupname']] = $row['groupname'];
|
||||||
|
}
|
||||||
|
$dbh = null;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json_encode($retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// split group list part from requested URL.
|
||||||
|
$parts = substr($_SERVER['PHP_SELF'], strrpos($_SERVER['PHP_SELF'], "/") + 1);
|
||||||
|
print getGroups($parts);
|
||||||
|
?>
|
BIN
admin/images/assign.png
Normal file
After Width: | Height: | Size: 876 B |
BIN
admin/images/delete.png
Normal file
After Width: | Height: | Size: 841 B |
BIN
admin/images/directory.png
Normal file
After Width: | Height: | Size: 575 B |
BIN
admin/images/edit.png
Normal file
After Width: | Height: | Size: 710 B |
BIN
admin/images/groups.png
Normal file
After Width: | Height: | Size: 847 B |
BIN
admin/images/newdirectory.png
Normal file
After Width: | Height: | Size: 600 B |
BIN
admin/images/newuser.png
Normal file
After Width: | Height: | Size: 751 B |
BIN
admin/images/throbber.gif
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
admin/images/x.png
Normal file
After Width: | Height: | Size: 752 B |
48
admin/index.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Start page code.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Include common code. */
|
||||||
|
include_once('common.inc.php');
|
||||||
|
|
||||||
|
header("Content-Type: text/html; charset=UTF-8");
|
||||||
|
try {
|
||||||
|
$dbh = new PDO($dsn, $dbuser, $dbpass);
|
||||||
|
$query = $dbh->prepare("SELECT firstname, lastname FROM dav_password WHERE username=:username");
|
||||||
|
$currentuser = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
$query->execute(array(":username" => $currentuser));
|
||||||
|
$row = $query->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$smarty->assign("firstname", $row['firstname']);
|
||||||
|
$smarty->assign("lastname", $row['lastname']);
|
||||||
|
$smarty->display("start.html");
|
||||||
|
$dbh = null;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$smarty->setErrorMsg($e->getMessage());
|
||||||
|
$smarty->display("error.html");
|
||||||
|
}
|
||||||
|
?>
|
305
admin/scripts/autocomplete.js
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Autocompletion for input fields, ideas from Drupal autocompletion
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches the autocomplete behaviour to all required fields
|
||||||
|
*/
|
||||||
|
DAV.autocompleteAutoAttach = function () {
|
||||||
|
var acdb = [];
|
||||||
|
$('input.autocomplete').each(function () {
|
||||||
|
var uri = this.value;
|
||||||
|
if (!acdb[uri]) {
|
||||||
|
acdb[uri] = new DAV.ACDB(uri);
|
||||||
|
}
|
||||||
|
var input = $('#' + this.id.substr(0, this.id.length - 13))
|
||||||
|
.attr('autocomplete', 'OFF')[0];
|
||||||
|
$(input.form).submit(DAV.autocompleteSubmit);
|
||||||
|
new DAV.jsAC(input, acdb[uri]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevents the form from submitting if the suggestions popup is open
|
||||||
|
* and closes the suggestions popup when doing so.
|
||||||
|
*/
|
||||||
|
DAV.autocompleteSubmit = function () {
|
||||||
|
return $('#autocomplete').each(function () {
|
||||||
|
this.owner.hidePopup();
|
||||||
|
}).size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An AutoComplete object
|
||||||
|
*/
|
||||||
|
DAV.jsAC = function (input, db) {
|
||||||
|
var ac = this;
|
||||||
|
this.input = input;
|
||||||
|
this.db = db;
|
||||||
|
|
||||||
|
$(this.input)
|
||||||
|
.keydown(function (event) { return ac.onkeydown(this, event); })
|
||||||
|
.keyup(function (event) { ac.onkeyup(this, event) })
|
||||||
|
.blur(function () { ac.hidePopup(); ac.db.cancel(); });
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "keydown" event
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.onkeydown = function (input, e) {
|
||||||
|
if (!e) {
|
||||||
|
e = window.event;
|
||||||
|
}
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 40: // down arrow
|
||||||
|
this.selectDown();
|
||||||
|
return false;
|
||||||
|
case 38: // up arrow
|
||||||
|
this.selectUp();
|
||||||
|
return false;
|
||||||
|
default: // all other keys
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the "keyup" event
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.onkeyup = function (input, e) {
|
||||||
|
if (!e) {
|
||||||
|
e = window.event;
|
||||||
|
}
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 16: // shift
|
||||||
|
case 17: // ctrl
|
||||||
|
case 18: // alt
|
||||||
|
case 20: // caps lock
|
||||||
|
case 33: // page up
|
||||||
|
case 34: // page down
|
||||||
|
case 35: // end
|
||||||
|
case 36: // home
|
||||||
|
case 37: // left arrow
|
||||||
|
case 38: // up arrow
|
||||||
|
case 39: // right arrow
|
||||||
|
case 40: // down arrow
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 9: // tab
|
||||||
|
case 13: // enter
|
||||||
|
case 27: // esc
|
||||||
|
this.hidePopup(e.keyCode);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default: // all other keys
|
||||||
|
if (input.value.length > 0)
|
||||||
|
this.populatePopup();
|
||||||
|
else
|
||||||
|
this.hidePopup(e.keyCode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the currently highlighted suggestion into the autocomplete field
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.select = function (node) {
|
||||||
|
this.input.value = node.autocompleteValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlights the next suggestion
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.selectDown = function () {
|
||||||
|
if (this.selected && this.selected.nextSibling) {
|
||||||
|
this.highlight(this.selected.nextSibling);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var lis = $('li', this.popup);
|
||||||
|
if (lis.size() > 0) {
|
||||||
|
this.highlight(lis.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlights the previous suggestion
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.selectUp = function () {
|
||||||
|
if (this.selected && this.selected.previousSibling) {
|
||||||
|
this.highlight(this.selected.previousSibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlights a suggestion
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.highlight = function (node) {
|
||||||
|
if (this.selected) {
|
||||||
|
$(this.selected).removeClass('selected');
|
||||||
|
}
|
||||||
|
$(node).addClass('selected');
|
||||||
|
this.selected = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unhighlights a suggestion
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.unhighlight = function (node) {
|
||||||
|
$(node).removeClass('selected');
|
||||||
|
this.selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the autocomplete suggestions
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.hidePopup = function (keycode) {
|
||||||
|
// Select item if the right key or mousebutton was pressed
|
||||||
|
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
|
||||||
|
this.input.value = this.selected.autocompleteValue;
|
||||||
|
}
|
||||||
|
// Hide popup
|
||||||
|
var popup = this.popup;
|
||||||
|
if (popup) {
|
||||||
|
this.popup = null;
|
||||||
|
$(popup).fadeOut('fast', function() { $(popup).remove(); });
|
||||||
|
}
|
||||||
|
this.selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Positions the suggestions popup and starts a search
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.populatePopup = function () {
|
||||||
|
// Show popup
|
||||||
|
if (this.popup) {
|
||||||
|
$(this.popup).remove();
|
||||||
|
}
|
||||||
|
this.selected = false;
|
||||||
|
this.popup = document.createElement('div');
|
||||||
|
this.popup.id = 'autocomplete';
|
||||||
|
this.popup.owner = this;
|
||||||
|
$(this.popup).css({
|
||||||
|
marginTop: this.input.offsetHeight +'px',
|
||||||
|
width: (this.input.offsetWidth - 4) +'px',
|
||||||
|
display: 'none'
|
||||||
|
});
|
||||||
|
$(this.input).before(this.popup);
|
||||||
|
|
||||||
|
// Do search
|
||||||
|
this.db.owner = this;
|
||||||
|
this.db.search(this.input.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the suggestion popup with any matches received
|
||||||
|
*/
|
||||||
|
DAV.jsAC.prototype.found = function (matches) {
|
||||||
|
// If no value in the textfield, do not show the popup.
|
||||||
|
if (!this.input.value.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare matches
|
||||||
|
var ul = document.createElement('ul');
|
||||||
|
var ac = this;
|
||||||
|
for (key in matches) {
|
||||||
|
var li = document.createElement('li');
|
||||||
|
$(li)
|
||||||
|
.html('<div>'+ matches[key] +'</div>')
|
||||||
|
.mousedown(function () { ac.select(this); })
|
||||||
|
.mouseover(function () { ac.highlight(this); })
|
||||||
|
.mouseout(function () { ac.unhighlight(this); });
|
||||||
|
li.autocompleteValue = key;
|
||||||
|
$(ul).append(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show popup with matches, if any
|
||||||
|
if (this.popup) {
|
||||||
|
if (ul.childNodes.length > 0) {
|
||||||
|
$(this.popup).empty().append(ul).show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$(this.popup).css({visibility: 'hidden'});
|
||||||
|
this.hidePopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DAV.jsAC.prototype.setStatus = function (status) {
|
||||||
|
switch (status) {
|
||||||
|
case 'begin':
|
||||||
|
$(this.input).addClass('throbbing');
|
||||||
|
break;
|
||||||
|
case 'cancel':
|
||||||
|
case 'error':
|
||||||
|
case 'found':
|
||||||
|
$(this.input).removeClass('throbbing');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An AutoComplete DataBase object
|
||||||
|
*/
|
||||||
|
DAV.ACDB = function (uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
this.delay = 300;
|
||||||
|
this.cache = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a cached and delayed search
|
||||||
|
*/
|
||||||
|
DAV.ACDB.prototype.search = function (searchString) {
|
||||||
|
var db = this;
|
||||||
|
this.searchString = searchString;
|
||||||
|
|
||||||
|
// See if this key has been searched for before
|
||||||
|
if (this.cache[searchString]) {
|
||||||
|
return this.owner.found(this.cache[searchString]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate delayed search
|
||||||
|
if (this.timer) {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
}
|
||||||
|
this.timer = setTimeout(function() {
|
||||||
|
db.owner.setStatus('begin');
|
||||||
|
|
||||||
|
// Ajax GET request for autocompletion
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: db.uri +'/'+ DAV.encodeURIComponent(searchString),
|
||||||
|
success: function (data) {
|
||||||
|
// Parse back result
|
||||||
|
var matches = DAV.parseJson(data);
|
||||||
|
if (typeof matches['status'] == 'undefined' || matches['status'] != 0) {
|
||||||
|
db.cache[searchString] = matches;
|
||||||
|
// Verify if these are still the matches the user wants to see
|
||||||
|
if (db.searchString == searchString) {
|
||||||
|
db.owner.found(matches);
|
||||||
|
}
|
||||||
|
db.owner.setStatus('found');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (xmlhttp) {
|
||||||
|
alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ db.uri);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, this.delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the current autocomplete request
|
||||||
|
*/
|
||||||
|
DAV.ACDB.prototype.cancel = function() {
|
||||||
|
if (this.owner) this.owner.setStatus('cancel');
|
||||||
|
if (this.timer) clearTimeout(this.timer);
|
||||||
|
this.searchString = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign autocomplete
|
||||||
|
$(document).ready(DAV.autocompleteAutoAttach);
|
148
admin/scripts/directories.js
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
function handleerror(xmldata) {
|
||||||
|
if ($('error', xmldata).size()) {
|
||||||
|
var msg = 'Es ist ein Fehler aufgetreten:\n';
|
||||||
|
$('error', xmldata).find('errormsg').each(function(i) {
|
||||||
|
msg += $(this).text();
|
||||||
|
});
|
||||||
|
alert(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
$('#content').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDirectories(xmldata) {
|
||||||
|
var dirname = $('dirname', xmldata).text();
|
||||||
|
var groups = $('groups', xmldata).text();
|
||||||
|
var filecount = $('filecount', xmldata).text();
|
||||||
|
var filesize = $('filesize', xmldata).text();
|
||||||
|
var maydelete = $('maydelete', xmldata).text();
|
||||||
|
var htmltext = '<td>' + dirname + '</td><td>' + groups + '</td><td>' + filecount + ', ' + filesize + '</td><td><a id="edit' + dirname + '" class="editlink" href="#" title="Die Gruppenzuordnungen dieses Verzeichnisses bearbeiten"><img class="actionicon" src="images/groups.png" width="16" height="16" alt="Gruppen"/></a>';
|
||||||
|
if (maydelete == '1') {
|
||||||
|
htmltext = htmltext + '<a id="delete' + dirname + '" class="deletelink" href="#" title="Dieses Verzeichnis löschen"><img class="actionicon" src="images/delete.png" width="16" height="16" alt="löschen" /></a>';
|
||||||
|
}
|
||||||
|
htmltext = htmltext + '</td>';
|
||||||
|
$('#dirtable').find('tr#dir' + dirname).empty().append(htmltext);
|
||||||
|
if (!($('#dirtable').find('tr#dir' + dirname).size())) {
|
||||||
|
var rows = $('#dirtable').find('tr');
|
||||||
|
var inserted = false;
|
||||||
|
for (var i = 0; !inserted && i < rows.length; i++) {
|
||||||
|
if ($(rows[i]).find('td:first').text() > dirname) {
|
||||||
|
$(rows[i]).before(
|
||||||
|
'<tr id="dir' + dirname + '">' + htmltext + '</tr>');
|
||||||
|
inserted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inserted) {
|
||||||
|
$(rows[rows.length-1]).before(
|
||||||
|
'<tr id="dir' + dirname + '">' + htmltext + '</tr>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#dirtable').find('tr#dir' + dirname).find('a.editlink').click(function() {
|
||||||
|
editdirectory(this.id.substr(4));
|
||||||
|
});
|
||||||
|
$('#dirtable').find('tr#dir' + dirname).find('a.deletelink').click(function() {
|
||||||
|
removedirectory(this.id.substr(6));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDirectoryForm(title, dirname, groups) {
|
||||||
|
return '<form action="#" id="dirform"><fieldset class="dynaform"><legend><img id="closer" src="images/x.png" width="16" height="16" alt="Schließen" /> ' + title + '</legend><div class="formelement"><label for="dirname">Verzeichnisname:</label><input type="text" name="dirname" id="input-dirname" value="' + dirname + '" /></div><div class="formelement"><label for="groups">Gruppen:</label><input type="text" name="groups" class="form-autocomplete" id="input-groups" value="' + groups + '" /><input type="hidden" class="autocomplete" id="input-groups-autocomplete" value="getgroups.php" /></div><div class="formactions"><input type="submit" name="submit" value="Absenden" /></div></div></fieldset></form>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function displaydirectoryeditor(title, dirname, groups) {
|
||||||
|
$('#content').hide();
|
||||||
|
$('#direditor').hide().empty().append(getDirectoryForm(title, dirname,
|
||||||
|
groups)).show();
|
||||||
|
DAV.autocompleteAutoAttach();
|
||||||
|
$('#dirform').find('#input-dirname').focus();
|
||||||
|
$('#closer').click(function() {
|
||||||
|
$('#direditor').hide().empty();
|
||||||
|
$('#content').show();
|
||||||
|
});
|
||||||
|
$('#dirform').submit(function() {
|
||||||
|
if (!this.dirname.value.match(/^[a-zA-Z0-9 -_.]+$/)) {
|
||||||
|
alert("Ungültiger Verzeichnisname.");
|
||||||
|
this.dirname.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$.post(
|
||||||
|
"/dav/admin/directories.php",
|
||||||
|
{method : 'submitdirectory',
|
||||||
|
dirname : this.dirname.value,
|
||||||
|
groups : this.groups.value},
|
||||||
|
function(retval) {
|
||||||
|
$('div#direditor').hide().empty();
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
updateDirectories(retval);
|
||||||
|
$('#content').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function editdirectory(dirname) {
|
||||||
|
$.get(
|
||||||
|
"directories.php",
|
||||||
|
{dirname : dirname,
|
||||||
|
method : 'getdirectorydata'},
|
||||||
|
function(retval) {
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
var dirname, groups;
|
||||||
|
dirname = $("dirname:first", retval).text();
|
||||||
|
groups = $("groups:first", retval).text();
|
||||||
|
displaydirectoryeditor("Verzeichnisdaten bearbeiten",
|
||||||
|
dirname, groups);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function newdirectory() {
|
||||||
|
displaydirectoryeditor('Neues Verzeichnis anlegen', '', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function deletedirectorydialog(dirname) {
|
||||||
|
$("#direditor").hide().empty();
|
||||||
|
var msg = 'Soll das Verzeichnis ' + dirname +
|
||||||
|
' wirklich gelöscht werden?';
|
||||||
|
if (confirm(msg) == true) {
|
||||||
|
$.post(
|
||||||
|
"directories.php",
|
||||||
|
{method : 'deletedirectory',
|
||||||
|
dirname : dirname},
|
||||||
|
function(retval) {
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
var dirname = $('dirname:first', retval).text();
|
||||||
|
$('#dirtable').find('tr#dir' + dirname).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removedirectory(dirname) {
|
||||||
|
$.get(
|
||||||
|
"directories.php",
|
||||||
|
{dirname : dirname,
|
||||||
|
method : 'getdirectorydata'},
|
||||||
|
function(retval) {
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
var username, lastname, firstname;
|
||||||
|
var dirname, groups;
|
||||||
|
dirname = $("dirname:first", retval).text();
|
||||||
|
deletedirectorydialog(dirname);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$("a.editlink").each(function(i) {
|
||||||
|
$(this).click(function() { editdirectory(this.id.substr(4)); });
|
||||||
|
});
|
||||||
|
$("a.newlink").each(function(i) {
|
||||||
|
$(this).click(function() { newdirectory(); });
|
||||||
|
});
|
||||||
|
$("a.deletelink").each(function(i) {
|
||||||
|
$(this).click(function() { removedirectory(this.id.substr(6)); });
|
||||||
|
});
|
||||||
|
});
|
29
admin/scripts/helper.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper code. Ideas from Drupal.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var DAV = DAV || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON response.
|
||||||
|
*
|
||||||
|
* The result is either the JSON object, or an object with 'status' 0 and
|
||||||
|
* 'data' an error message.
|
||||||
|
*/
|
||||||
|
DAV.parseJson = function (data) {
|
||||||
|
if ((data.substring(0, 1) != '{') && (data.substring(0, 1) != '[')) {
|
||||||
|
return { status: 0, data: data.length ? data : 'Unspecified error' };
|
||||||
|
}
|
||||||
|
return eval('(' + data + ');');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper to address the mod_rewrite url encoding bug.
|
||||||
|
*/
|
||||||
|
DAV.encodeURIComponent = function (item, uri) {
|
||||||
|
uri = uri || location.href;
|
||||||
|
item = encodeURIComponent(item).replace('%2F', '/');
|
||||||
|
return uri.indexOf('?q=') ? item : item.replace('%26', '%2526').replace('%23', '%2523');
|
||||||
|
};
|
1
admin/scripts/jquery.js
vendored
Normal file
189
admin/scripts/users.js
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
function handleerror(xmldata) {
|
||||||
|
if ($('error', xmldata).size()) {
|
||||||
|
var msg = 'Es ist ein Fehler aufgetreten:\n';
|
||||||
|
$('error', xmldata).find('errormsg').each(function(i) {
|
||||||
|
msg += $(this).text();
|
||||||
|
});
|
||||||
|
alert(msg);
|
||||||
|
$('#content').show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateusers(xmldata) {
|
||||||
|
var uid = $(xmldata).find('uid').text();
|
||||||
|
var username = $(xmldata).find('username').text();
|
||||||
|
var firstname = $(xmldata).find('firstname').text();
|
||||||
|
var lastname = $(xmldata).find('lastname').text();
|
||||||
|
var loggedin = $(xmldata).find('loggedin').text();
|
||||||
|
var htmltext = '<td>' + username + '</td><td>' + lastname + ', ' + firstname + '</td><td><a id="edit' + uid + '" class="editlink" href="#" title="Die Daten dieses Nutzers bearbeiten"><img class="actionicon" src="images/edit.png" width="16" height="16" alt="bearbeiten"/></a>';
|
||||||
|
if (loggedin == '0') {
|
||||||
|
htmltext = htmltext + '<a id="delete' + uid + '" class="deletelink" href="#" title="Die Daten dieses Nutzers löschen"><img class="actionicon" src="images/delete.png" width="16" height="16" alt="löschen" /></a>';
|
||||||
|
}
|
||||||
|
htmltext = htmltext + '</td>';
|
||||||
|
$('#usertable').find('tr#uid' + uid).empty().append(htmltext);
|
||||||
|
if (!($('#usertable').find('tr#uid' + uid).size())) {
|
||||||
|
var rows = $('#usertable').find('tr');
|
||||||
|
var inserted = false;
|
||||||
|
for (var i = 0; !inserted && i < rows.length; i++) {
|
||||||
|
if ($(rows[i]).find('td:first').text() > username) {
|
||||||
|
$(rows[i]).before(
|
||||||
|
'<tr id="uid' + uid + '">' + htmltext + '</tr>');
|
||||||
|
inserted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inserted) {
|
||||||
|
$(rows[rows.length-1]).before(
|
||||||
|
'<tr id="uid' + uid + '">' + htmltext + '</tr>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#usertable').find('tr#uid' + uid).find('a.editlink').click(function() {
|
||||||
|
edituser(this.id.substr(4));
|
||||||
|
});
|
||||||
|
$('#usertable').find('tr#uid' + uid).find('a.deletelink').click(function() {
|
||||||
|
deleteuser(this.id.substr(6));
|
||||||
|
});
|
||||||
|
$('#content').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEditUserForm(title, username, firstname, lastname, groups, userid) {
|
||||||
|
var retval;
|
||||||
|
retval = '<form action="#" id="userform"><fieldset class="dynaform"><legend><img id="closer" src="images/x.png" width="16" height="16" alt="Schließen" /> ' + title + '</legend><div class="formelement"><label for="input-username">Nutzername:</label><input id="input-username" type="text" name="username" value="' + username + '" ';
|
||||||
|
if (userid != null) {
|
||||||
|
retval = retval + ' readonly="readonly"';
|
||||||
|
}
|
||||||
|
retval = retval + '/></div><div class="formelement"><label for="input-firstname">Vorname:</label><input id="input-firstname" type="text" name="firstname" value="' + firstname + '" /></div><div class="formelement"><label for="input-lastname">Nachname:</label><input id="input-lastname" type="text" name="lastname" value="' + lastname + '" /></div><div class="formelement"><label for="pwd1">Passwort:</label><input type="password" name="pwd1" /></div><div class="formelement"><label for="pwd2">Wiederholung:</label><input type="password" name="pwd2" /></div><div class="formelement"><label for="groups">Gruppen:</label><input type="text" name="groups" class="form-autocomplete" id="input-groups" value="' + groups + '" /><input type="hidden" class="autocomplete" id="input-groups-autocomplete" value="getgroups.php" /></div><div class="formactions"><input type="submit" name="submit" value="Absenden" /></div></fieldset></form>';
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayusereditor(title, userid, username, firstname, lastname, groups) {
|
||||||
|
$('#content').hide();
|
||||||
|
$('#usereditor').hide().empty().append(getEditUserForm(title, username, firstname, lastname, groups, userid)).show();
|
||||||
|
DAV.autocompleteAutoAttach();
|
||||||
|
$('#closer').click(function() {
|
||||||
|
$('#usereditor').hide().empty();
|
||||||
|
$('#content').show();
|
||||||
|
});
|
||||||
|
$('#userform').find('#input-username').focus();
|
||||||
|
$('#userform').submit(function() {
|
||||||
|
var params;
|
||||||
|
if (userid == null) {
|
||||||
|
if (!this.username.value.match(/^[a-zA-Z0-9]{2,}$/)) {
|
||||||
|
alert('Der Nutzername muss aus mindestens 2 Buchstaben oder Ziffern bestehen und darf keine sonstigen Zeichen enthalten.');
|
||||||
|
this.username.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userid == null || this.pwd1.value.length > 0) {
|
||||||
|
if (this.pwd1.value.length < 8) {
|
||||||
|
alert('Das Passwort muss mindestens 8 Zeichen lang sein!');
|
||||||
|
this.pwd1.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.pwd1.value != this.pwd2.value) {
|
||||||
|
alert('Passwort und Wiederholung müssen übereinstimmen!');
|
||||||
|
this.pwd2.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.groups.value.match(/^([0-9a-zA-z]+[,\s]*)+$/)) {
|
||||||
|
alert('Die Gruppenangabe muss eine durch Kommata getrennte Liste von Gruppennamen, die aus Buchstaben und Ziffern zusammengesetzt sein können, sein.');
|
||||||
|
this.groups.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (userid == null) {
|
||||||
|
params = {method : 'submituser',
|
||||||
|
username : this.username.value,
|
||||||
|
firstname : this.firstname.value,
|
||||||
|
lastname : this.lastname.value,
|
||||||
|
password : this.pwd1.value,
|
||||||
|
groups : this.groups.value};
|
||||||
|
} else {
|
||||||
|
params = {method : 'submituser',
|
||||||
|
uid : userid,
|
||||||
|
username : this.username.value,
|
||||||
|
firstname : this.firstname.value,
|
||||||
|
lastname : this.lastname.value,
|
||||||
|
password : this.pwd1.value,
|
||||||
|
groups : this.groups.value};
|
||||||
|
}
|
||||||
|
$.post(
|
||||||
|
"users.php", params,
|
||||||
|
function(retval) {
|
||||||
|
$('div#usereditor').hide().empty();
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
updateusers(retval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteuserdialog(userid, username, firstname, lastname) {
|
||||||
|
$("#usereditor").hide().empty();
|
||||||
|
var msg = 'Soll der Nutzer ' + firstname + ' ' + lastname +
|
||||||
|
' mit dem Login ' + username + ' wirklich gelöscht werden?';
|
||||||
|
if (confirm(msg) == true) {
|
||||||
|
$.post(
|
||||||
|
"users.php",
|
||||||
|
{method : 'deleteuser',
|
||||||
|
uid : userid},
|
||||||
|
function(retval) {
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
var deluid = $('uid:first', retval).text();
|
||||||
|
$('#usertable').find('tr#uid' + deluid).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteuser(userid) {
|
||||||
|
$.get(
|
||||||
|
"users.php",
|
||||||
|
{uid : userid,
|
||||||
|
method : 'getuserdata'},
|
||||||
|
function(retval) {
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
var username, lastname, firstname;
|
||||||
|
username = $("username:first", retval).text();
|
||||||
|
lastname = $("lastname:first", retval).text();
|
||||||
|
firstname = $("firstname:first", retval).text();
|
||||||
|
deleteuserdialog(userid, username, firstname, lastname);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function edituser(userid) {
|
||||||
|
$.get(
|
||||||
|
"users.php",
|
||||||
|
{uid : userid,
|
||||||
|
method : 'getuserdata'},
|
||||||
|
function(retval) {
|
||||||
|
if (!handleerror(retval)) {
|
||||||
|
var username, lastname, firstname, groups;
|
||||||
|
username = $("username:first", retval).text();
|
||||||
|
lastname = $("lastname:first", retval).text();
|
||||||
|
firstname = $("firstname:first", retval).text();
|
||||||
|
groups = $("groups:first", retval).text();
|
||||||
|
displayusereditor('Nutzerdaten bearbeiten', userid, username,
|
||||||
|
firstname, lastname, groups);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function newuser() {
|
||||||
|
displayusereditor('Neuen Nutzer anlegen', null, '', '', '', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$("a.editlink").each(function(i) {
|
||||||
|
$(this).click(function() { edituser(this.id.substr(4)); });
|
||||||
|
});
|
||||||
|
$("a.newlink").each(function(i) {
|
||||||
|
$(this).click(function() { newuser(); });
|
||||||
|
});
|
||||||
|
$("a.deletelink").each(function(i) {
|
||||||
|
$(this).click(function() { deleteuser(this.id.substr(6)); });
|
||||||
|
});
|
||||||
|
});
|
39
admin/templates/directories.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{include file="header.html" title="Verzeichnisverwaltung"}
|
||||||
|
<script type="text/javascript" src="/dav/admin/scripts/helper.js"></script>
|
||||||
|
<script type="text/javascript" src="/dav/admin/scripts/autocomplete.js"></script>
|
||||||
|
<script type="text/javascript" src="/dav/admin/scripts/directories.js"></script><div id="content">
|
||||||
|
<h1>WebDAV-Verwaltung</h1>
|
||||||
|
<h2>Verzeichnisverwaltung</h2>
|
||||||
|
<table id="dirtable">
|
||||||
|
<thead>
|
||||||
|
<tr><th id="hcol-directory">Verzeichnis</th><th id="hcol-groups">Gruppen</th><th id="hcol-files">enthaltene Dateien (Anzahl und Größe)</th><th /></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach item=dir from=$directories}
|
||||||
|
<tr id="dir{$dir.name}">
|
||||||
|
<td>{$dir.name}</td>
|
||||||
|
<td>{foreach item=group from=$dir.groups name=dirloop}{$group}{if !$smarty.foreach.dirloop.last}, {/if}{/foreach}</td>
|
||||||
|
<td>{$dir.filecount}, {$dir.filesize}</td>
|
||||||
|
<td><a id="edit{$dir.name}" class="editlink" href="#" title="Die Gruppenzuordnungen dieses Verzeichnisses bearbeiten"><img class="actionicon" src="images/groups.png" width="16" height="16" alt="Gruppen"/></a>{if $dir.maydelete}<a id="delete{$dir.name}" class="deletelink" href="#" title="Dieses Verzeichnis löschen"><img class="actionicon" src="images/delete.png" width="16" height="16" alt="löschen" /></a>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
{foreachelse}
|
||||||
|
<tr><td colspan="4">keine Verzeichnisse vorhanden</td></tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr><td colspan="4"><a id="newdir" class="newlink" href="#" title="Neues Verzeichnis anlegen"><img class="actionicon" src="images/newdirectory.png" width="16" height="16" alt="neu" /></a></td></tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
<h3>Symbolerklärung</h3>
|
||||||
|
<dl>
|
||||||
|
<dt><img src="images/groups.png" width="16" height="16" alt="Gruppen" /></dt>
|
||||||
|
<dd>Die Gruppenberechtigungen dieses Verzeichnisses bearbeiten</dd>
|
||||||
|
<dt><img src="images/delete.png" width="16" height="16" alt="löschen" /></dt>
|
||||||
|
<dd>Diese Verzeichnis löschen</dd>
|
||||||
|
<dt><img src="images/newdirectory.png" width="16" height="16" alt="neu" /></dt>
|
||||||
|
<dd>Neues Verzeichnis anlegen</dd>
|
||||||
|
</dl>
|
||||||
|
<div id="footer"><a href="index.php">Zurück</a></div>
|
||||||
|
</div>
|
||||||
|
<div id="direditor"></div>
|
||||||
|
{include file="footer.html"}
|
1
admin/templates/error.xml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><error><errormsg>{$errormsg}</errormsg></error>
|
1
admin/templates/footer.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
</body></html>
|
8
admin/templates/header.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
|
||||||
|
<head><title>{$smarty.server.SERVER_NAME} - WebDAV Verwaltung{if $title} - {$title}{/if}</title></head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="format.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="dynaform.css" />
|
||||||
|
<script type="text/javascript" src="scripts/jquery.js"></script>
|
||||||
|
<body>
|
10
admin/templates/start.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{include file="header.html"}
|
||||||
|
<h1>WebDAV-Verwaltung</h1>
|
||||||
|
<p>Hallo {$firstname} {$lastname},<br />
|
||||||
|
willkommen zur WebDAV-Verwaltung für {$smarty.server.SERVER_NAME}. Ihnen
|
||||||
|
stehen folgende Möglichkeiten zur Verfügung.</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="directories.php">Verzeichnisse verwalten</a></li>
|
||||||
|
<li><a href="users.php">Nutzeraccounts verwalten</a></li>
|
||||||
|
</ul>
|
||||||
|
{include file="footer.html"}
|
37
admin/templates/users.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{include file="header.html" title="Nutzerverwaltung"}
|
||||||
|
<script type="text/javascript" src="/dav/admin/scripts/helper.js"></script>
|
||||||
|
<script type="text/javascript" src="/dav/admin/scripts/autocomplete.js"></script>
|
||||||
|
<script type="text/javascript" src="/dav/admin/scripts/users.js"></script>
|
||||||
|
<div id="content">
|
||||||
|
<h1>WebDAV-Verwaltung</h1>
|
||||||
|
<h2>Nutzerverwaltung</h2>
|
||||||
|
<table id="usertable">
|
||||||
|
<thead>
|
||||||
|
<tr><th id="hcol-username">Nutzername</th><th id="hcol-name">Name, Vorname</th><th /></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{foreach item=user from=$users}
|
||||||
|
<tr id="uid{$user.uid}">
|
||||||
|
<td>{$user.username}</td>
|
||||||
|
<td>{$user.lastname}, {$user.firstname}</td>
|
||||||
|
<td><a id="edit{$user.uid}" class="editlink" href="#" title="Die Daten dieses Nutzers bearbeiten"><img class="actionicon" src="images/edit.png" width="16" height="16" alt="bearbeiten"/></a>{if !$user.loggedin}<a id="delete{$user.uid}" class="deletelink" href="#" title="Die Daten dieses Nutzers löschen"><img class="actionicon" src="images/delete.png" width="16" height="16" alt="löschen" /></a>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
{/foreach}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr><td colspan="3"><a id="newuser" class="newlink" href="#" title="Neuen Nutzer anlegen"><img class="actionicon" src="images/newuser.png" width="16" height="16" alt="neu" /></a></td></tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
<h3>Symbolerklärung</h3>
|
||||||
|
<dl>
|
||||||
|
<dt><img src="images/edit.png" width="16" height="16" alt="bearbeiten" /></dt>
|
||||||
|
<dd>Die Daten dieses Nutzers bearbeiten</dd>
|
||||||
|
<dt><img src="images/delete.png" width="16" height="16" alt="löschen" /></dt>
|
||||||
|
<dd>Die Daten dieses Nutzers löschen</dd>
|
||||||
|
<dt><img src="images/newuser.png" width="16" height="16" alt="neu" /></dt>
|
||||||
|
<dd>Neuen Nutzer anlegen</dd>
|
||||||
|
</dl>
|
||||||
|
<div id="footer"><a href="index.php">Zurück</a></div>
|
||||||
|
</div>
|
||||||
|
<div id="usereditor"></div>
|
||||||
|
{include file="footer.html"}
|
317
admin/users.php
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* User administration code.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Include common code. */
|
||||||
|
include_once('common.inc.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets XML encoded data for a user.
|
||||||
|
*
|
||||||
|
* @param int $uid user id
|
||||||
|
* @return XML string
|
||||||
|
*/
|
||||||
|
function getUserData($uid) {
|
||||||
|
if (!is_numeric($uid)) {
|
||||||
|
errorAsXml(sprintf(_("Invalid user id %s"), $uid));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$currentuser = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
|
||||||
|
$dbh = new PDO($GLOBALS['dsn'], $GLOBALS['dbuser'], $GLOBALS['dbpass']);
|
||||||
|
$sth = $dbh->prepare("SELECT groupname FROM dav_group, dav_password WHERE dav_group.username=dav_password.username AND dav_password.uid=:uid");
|
||||||
|
if (!$sth->execute(array(':uid' => $uid))) {
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
$groups = array();
|
||||||
|
while ($grouprow = $sth->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
array_push($groups, $grouprow['groupname']);
|
||||||
|
}
|
||||||
|
$sth = $dbh->prepare("SELECT username, firstname, lastname FROM dav_password WHERE uid=:uid");
|
||||||
|
if (!$sth->execute(array(':uid' => $uid))) {
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
$row = $sth->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$retval = sprintf('<?xml version="1.0" encoding="utf8"?><userdata><uid>%d</uid><username>%s</username><firstname>%s</firstname><lastname>%s</lastname><groups>%s</groups><loggedin>%d</loggedin></userdata>',
|
||||||
|
$uid, $row['username'], $row['firstname'],
|
||||||
|
$row['lastname'], implode(", ", $groups),
|
||||||
|
($currentuser == $row['username']) ? 1 : 0);
|
||||||
|
$dbh = null;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
errorAsXml($e->getMessage());
|
||||||
|
}
|
||||||
|
header("Content-Type: text/xml; charset=UTF-8");
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets XML encoded data for a deleted user.
|
||||||
|
*
|
||||||
|
* @param int $uid user id
|
||||||
|
* @return XML string
|
||||||
|
*/
|
||||||
|
function getDeletedUserData($uid) {
|
||||||
|
if (!is_numeric($uid)) {
|
||||||
|
errorAsXml(sprintf(_("Invalid user id %s"), $uid));
|
||||||
|
}
|
||||||
|
return sprintf('<?xml version="1.0" encoding="utf8"?><userdata><uid>%d</uid></userdata>', $uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given user data array for correctness.
|
||||||
|
*
|
||||||
|
* @param array &$userdata reference to an user data array
|
||||||
|
* @param boolean $forinsert if this is true the check skips field
|
||||||
|
* that will be created during insert
|
||||||
|
* @return an array with validation error messages or an empty array
|
||||||
|
*/
|
||||||
|
function validateUserData(&$userdata, $forinsert) {
|
||||||
|
$errormsgs = array();
|
||||||
|
// normalize the user data array
|
||||||
|
foreach ($userdata as $key => $value) {
|
||||||
|
$userdata[$key] = trim($value);
|
||||||
|
}
|
||||||
|
if (!$forinsert) {
|
||||||
|
if (!is_numeric($userdata['uid'])) {
|
||||||
|
array_push($errormsgs, _("Uid must be numeric."));
|
||||||
|
}
|
||||||
|
if (!empty($userdata['password']) && strlen($userdata['password']) < 8) {
|
||||||
|
array_push($errormsgs, _("Password must be at least 8 characters long."));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9]{2,}$/', $userdata['username'])) {
|
||||||
|
array_push($errormsgs, _("Username must be at least 2 characters long and must contain letters and digits only."));
|
||||||
|
}
|
||||||
|
if (empty($userdata['password']) || strlen($userdata['password']) < 8) {
|
||||||
|
array_push($errormsgs, _("Password must be at least 8 characters long."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty($userdata['firstname'])) {
|
||||||
|
$userdata['firstname'] = null;
|
||||||
|
}
|
||||||
|
if (empty($userdata['lastname'])) {
|
||||||
|
$userdata['lastname'] = null;
|
||||||
|
}
|
||||||
|
if (!preg_match('/^([0-9a-zA-z]+[,\s]*)+$/', $userdata['groups'])) {
|
||||||
|
array_push($errormsgs, _('Groups must be a list of group names separated by commas. Group names must consist of letters and digits.'));
|
||||||
|
}
|
||||||
|
return $errormsgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the data of a user in the database.
|
||||||
|
*
|
||||||
|
* @param array &$userdata reference to a user data array
|
||||||
|
*/
|
||||||
|
function updateUser(&$userdata) {
|
||||||
|
$validation = validateUserData($userdata, false);
|
||||||
|
if (!empty($validation)) {
|
||||||
|
errorAsXml(implode("\n", $validation));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$dbh = new PDO($GLOBALS['dsn'], $GLOBALS['dbuser'], $GLOBALS['dbpass']);
|
||||||
|
$dbh->beginTransaction();
|
||||||
|
if ($userdata['password']) {
|
||||||
|
$sth = $dbh->prepare("UPDATE dav_password SET firstname=:firstname, lastname=:lastname, password=md5(:password) WHERE uid=:uid");
|
||||||
|
if (!$sth->execute(array(':firstname' => $userdata['firstname'],
|
||||||
|
':lastname' => $userdata['lastname'],
|
||||||
|
':password' => $userdata['password'],
|
||||||
|
':uid' => $userdata['uid']))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$sth = $dbh->prepare("UPDATE dav_password SET firstname=:firstname, lastname=:lastname WHERE uid=:uid");
|
||||||
|
if (!$sth->execute(array(':firstname' => $userdata['firstname'],
|
||||||
|
':lastname' => $userdata['lastname'],
|
||||||
|
':uid' => $userdata['uid']))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($userdata['groups']) {
|
||||||
|
$groups = array();
|
||||||
|
$sth = $dbh->prepare("DELETE FROM dav_group WHERE username=:username");
|
||||||
|
if (!$sth->execute(array(':username' => $userdata['username']))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
$sth = $dbh->prepare("INSERT INTO dav_group (username, groupname) VALUES (:username, :groupname)");
|
||||||
|
foreach (explode(",", $userdata['groups']) as $group) {
|
||||||
|
$group = trim($group);
|
||||||
|
if (!in_array($group, $groups)) {
|
||||||
|
array_push($groups, $group);
|
||||||
|
if (!$sth->execute(array(':username' => $userdata['username'],
|
||||||
|
':groupname' => $group))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
$sth->closeCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dbh->commit();
|
||||||
|
$dbh = null;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
errorAsXml($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a new user and its group assignments into the database.
|
||||||
|
*
|
||||||
|
* @param array &$userdata reference to an user data array
|
||||||
|
*/
|
||||||
|
function insertUser(&$userdata) {
|
||||||
|
$validation = validateUserData($userdata, true);
|
||||||
|
if (!empty($validation)) {
|
||||||
|
errorAsXml(implode("\n", $validation));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$dbh = new PDO($GLOBALS['dsn'], $GLOBALS['dbuser'], $GLOBALS['dbpass']);
|
||||||
|
$dbh->beginTransaction();
|
||||||
|
$sth = $dbh->prepare("INSERT INTO dav_password (username, firstname, lastname, password) VALUES (:username, :firstname, :lastname, md5(:password))");
|
||||||
|
if (!$sth->execute(array(':username' => $userdata['username'],
|
||||||
|
':firstname' => $userdata['firstname'],
|
||||||
|
':lastname' => $userdata['lastname'],
|
||||||
|
':password' => $userdata['password']))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
$uid = $dbh->lastInsertId('dav_password_uid_seq');
|
||||||
|
$groups = array();
|
||||||
|
$sth = $dbh->prepare("INSERT INTO dav_group (username, groupname) VALUES (:username, :groupname)");
|
||||||
|
foreach (split(",", $userdata['groups']) as $group) {
|
||||||
|
$group = trim($group);
|
||||||
|
if (!in_array($group, $groups)) {
|
||||||
|
array_push($groups, $group);
|
||||||
|
if (!$sth->execute(array(':username' => $userdata['username'],
|
||||||
|
':groupname' => $group))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($sth);
|
||||||
|
}
|
||||||
|
$sth->closeCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dbh->commit();
|
||||||
|
$dbh = null;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
errorAsXml($e->getMessage);
|
||||||
|
}
|
||||||
|
return $uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the user with the given user id and its group assignments
|
||||||
|
* from the database.
|
||||||
|
*
|
||||||
|
* @param int $uid user id
|
||||||
|
*/
|
||||||
|
function deleteUser($uid) {
|
||||||
|
if (!is_numeric($uid)) {
|
||||||
|
errorAsXml(sprintf(_("Invalid user id %s"), $uid));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$dbh = new PDO($GLOBALS['dsn'], $GLOBALS['dbuser'], $GLOBALS['dbpass']);
|
||||||
|
$dbh->beginTransaction();
|
||||||
|
$query = $dbh->prepare("DELETE FROM dav_group WHERE username IN (SELECT username FROM dav_password WHERE uid=:uid)");
|
||||||
|
if (!$query->execute(array(':uid' => $uid))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($query);
|
||||||
|
}
|
||||||
|
$query = $dbh->prepare("DELETE FROM dav_password WHERE uid=:uid");
|
||||||
|
if (!$query->execute(array(':uid' => $uid))) {
|
||||||
|
$dbh->rollback();
|
||||||
|
statementErrorAsXml($query);
|
||||||
|
}
|
||||||
|
$dbh->commit();
|
||||||
|
$dbh = null;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
errorAsXml($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_GET) {
|
||||||
|
if ($_GET['method']) {
|
||||||
|
switch ($_GET['method']) {
|
||||||
|
case 'getuserdata':
|
||||||
|
if ($_GET['uid']) {
|
||||||
|
print getUserData($_GET['uid']);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_GET)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
invalidCall();
|
||||||
|
}
|
||||||
|
} elseif ($_POST) {
|
||||||
|
if ($_POST['method']) {
|
||||||
|
switch ($_POST['method']) {
|
||||||
|
case 'submituser':
|
||||||
|
if ($_POST['uid']) {
|
||||||
|
updateUser($_POST);
|
||||||
|
print getUserData($_POST['uid']);
|
||||||
|
} else {
|
||||||
|
print getUserData(insertUser($_POST));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'deleteuser':
|
||||||
|
if ($_POST['uid']) {
|
||||||
|
deleteUser($_POST['uid']);
|
||||||
|
print getDeletedUserData($_POST['uid']);
|
||||||
|
} else {
|
||||||
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_POST)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_POST)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
invalidCall();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$currentuser = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
|
||||||
|
header("Content-Type: text/html; charset=UTF-8");
|
||||||
|
try {
|
||||||
|
$dbh = new PDO($dsn, $dbuser, $dbpass);
|
||||||
|
$query = $dbh->prepare("SELECT uid, username, firstname, lastname FROM dav_password ORDER BY username");
|
||||||
|
$query->execute();
|
||||||
|
$rows = $query->fetchall(PDO::FETCH_ASSOC);
|
||||||
|
foreach ($rows as $key => $value) {
|
||||||
|
$value['loggedin'] = ($value['username'] == $currentuser);
|
||||||
|
$rows[$key] = $value;
|
||||||
|
}
|
||||||
|
$smarty->assign("users", $rows);
|
||||||
|
$smarty->display("users.html");
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
errorAsHtml($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
35
config/config.inc.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Global configuration for WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAVAdmin.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Absolute path to DAV area root directory with a trailing slash. */
|
||||||
|
define(DAV_ROOT, '@davrootdirectory@');
|
||||||
|
|
||||||
|
/** Include the database settings. */
|
||||||
|
require_once('@path.to.dbsettings@/dbsettings.inc.php');
|
||||||
|
?>
|
36
config/dbsettings.inc.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Database settings.
|
||||||
|
*
|
||||||
|
* @author Jan Dittberner <jan@dittberner.info>
|
||||||
|
* @version $Id$
|
||||||
|
* @license GPL
|
||||||
|
* @package WebDAVAdmin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007 Jan Dittberner
|
||||||
|
*
|
||||||
|
* This file is part of WebDAV administration.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Data source name. */
|
||||||
|
$dsn = "pgsql:host=localhost port=5432 dbname=@dbname@";
|
||||||
|
/** Database user. */
|
||||||
|
$dbuser = "@dbuser@";
|
||||||
|
/** Database password. */
|
||||||
|
$dbpass = "@dbpass@";
|
||||||
|
?>
|
25
setup/schema.sql
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
CREATE TABLE dav_password (
|
||||||
|
uid SERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(16) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(34) NOT NULL,
|
||||||
|
firstname VARCHAR(64),
|
||||||
|
lastname VARCHAR(64)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE dav_group (
|
||||||
|
gid SERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(16) NOT NULL REFERENCES dav_password(username),
|
||||||
|
groupname VARCHAR(32) NOT NULL,
|
||||||
|
UNIQUE(username, groupname)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE dav_log (
|
||||||
|
logid SERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(16),
|
||||||
|
reqdate VARCHAR(20),
|
||||||
|
uri TEXT,
|
||||||
|
ipaddr VARCHAR(16)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO dav_password (username, password) VALUES ('admin', md5('secret'));
|
||||||
|
INSERT INTO dav_group (username, groupname) VALUES ('admin', 'davadmin');
|
52
setup/webdavadmin.vhost
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerAdmin webmaster@davhost.yourdomain.net
|
||||||
|
ServerName davhost.yourdomain.net
|
||||||
|
|
||||||
|
DavLockDb /var/run/apache2/davlock/davhost.yourdomain.net
|
||||||
|
DocumentRoot /home/www/usr29/html
|
||||||
|
|
||||||
|
php_admin_value allow_call_time_pass_reference 1
|
||||||
|
<Directory /var/www/dav>
|
||||||
|
Dav on
|
||||||
|
AllowOverride AuthConfig Indexes
|
||||||
|
Order Allow,Deny
|
||||||
|
allow from all
|
||||||
|
|
||||||
|
AuthType Basic
|
||||||
|
AuthName "WebDAV on davhost"
|
||||||
|
AuthBasicAuthoritative Off
|
||||||
|
AuthUserFile /etc/apache2/auth/davhost.yourdomain.net
|
||||||
|
|
||||||
|
Auth_PG_host localhost
|
||||||
|
Auth_PG_port 5432
|
||||||
|
Auth_PG_user @dbuser@
|
||||||
|
Auth_PG_pwd @dbpassword@
|
||||||
|
Auth_PG_database @dbname@
|
||||||
|
|
||||||
|
Auth_PG_pwd_table dav_password
|
||||||
|
Auth_PG_uid_field username
|
||||||
|
Auth_PG_pwd_field password
|
||||||
|
|
||||||
|
Auth_PG_grp_table dav_group
|
||||||
|
Auth_PG_grp_user_field username
|
||||||
|
Auth_PG_grp_group_field groupname
|
||||||
|
Auth_PG_hash_type MD5
|
||||||
|
|
||||||
|
#Auth_PG_log_table dav_log
|
||||||
|
#Auth_PG_log_uname_field username
|
||||||
|
#Auth_PG_log_date_field reqdate
|
||||||
|
#Auth_PG_log_uri_field uri
|
||||||
|
#Auth_PG_log_addrs_field ipaddr
|
||||||
|
Auth_PG_authoritative on
|
||||||
|
|
||||||
|
require group davroot
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
ErrorLog /var/log/apache2/davhost.yourdomain.net_error.log
|
||||||
|
|
||||||
|
# Possible values include: debug, info, notice, warn, error, crit,
|
||||||
|
# alert, emerg.
|
||||||
|
LogLevel warn
|
||||||
|
|
||||||
|
CustomLog /var/log/apache2/davhost.yourdomain.net_access.log combined
|
||||||
|
</VirtualHost>
|