- 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>
|