Initial revision
This commit is contained in:
parent
e1a7e00d08
commit
2126f59e09
|
@ -0,0 +1,3 @@
|
|||
include po/Makefile
|
||||
include po/*.po
|
||||
include po/*.pot
|
|
@ -0,0 +1,2 @@
|
|||
authentic
|
||||
files
|
|
@ -0,0 +1,6 @@
|
|||
wcs (0.0.0-0) unstable; urgency=low
|
||||
|
||||
* Initial package.
|
||||
|
||||
-- Frederic Peters <fpeters@debian.org> Sat, 23 Apr 2005 20:48:19 +0200
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
Source: wcs
|
||||
Section: web
|
||||
Priority: optional
|
||||
Maintainer: Frederic Peters <fpeters@debian.org>
|
||||
Build-Depends: debhelper (>> 4.0.0)
|
||||
Standards-Version: 3.6.5.0
|
||||
|
||||
Package: wcs
|
||||
Architecture: all
|
||||
Depends: python2.3, quixote (>= 2.0), libapache2-mod-scgi | libapache-mod-scgi, python2.3-scgi
|
||||
Description: w.c.s. (1st draft)
|
||||
.
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
This package was debianized by Frederic Peters <fpeters@debian.org> on
|
||||
Wed, 20 Apr 2005 11:10:00 +0200.
|
||||
|
||||
Upstream Author: Frederic Peters <fpeters@entrouvert.com>
|
||||
|
||||
Copyright (c) 2005 Entr'ouvert;
|
||||
copyright (c) 2003-2005 dotclear for the graphics.
|
||||
|
||||
License is GNU GPL v2 or later plus OpenSSL exception clause.
|
||||
|
||||
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., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
On Debian GNU/Linux systems, the complete text of the GNU General Public
|
||||
License can be found in `/usr/share/common-licenses/GPL'.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
etc/apache2/sites-available
|
||||
usr
|
|
@ -0,0 +1 @@
|
|||
README
|
|
@ -0,0 +1,54 @@
|
|||
#! /bin/sh
|
||||
# postinst script for wcs
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
#
|
||||
# quoting from the policy:
|
||||
# Any necessary prompting should almost always be confined to the
|
||||
# post-installation script, and should be protected with a conditional
|
||||
# so that unnecessary prompting doesn't happen if a package's
|
||||
# installation fails and the `postinst' is called with `abort-upgrade',
|
||||
# `abort-remove' or `abort-deconfigure'.
|
||||
|
||||
PACKAGE=wcs
|
||||
VERSION=2.3
|
||||
LIB="/usr/lib/python$VERSION"
|
||||
DIRLIST="$LIB/site-packages/wcs"
|
||||
|
||||
case "$1" in
|
||||
configure|abort-upgrade|abort-remove|abort-deconfigure)
|
||||
for i in $DIRLIST ; do
|
||||
/usr/bin/python$VERSION -O $LIB/compileall.py -q $i
|
||||
/usr/bin/python$VERSION $LIB/compileall.py -q $i
|
||||
done
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#! /bin/sh
|
||||
# prerm script for wcs
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <prerm> `remove'
|
||||
# * <old-prerm> `upgrade' <new-version>
|
||||
# * <new-prerm> `failed-upgrade' <old-version>
|
||||
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
|
||||
# * <deconfigured's-prerm> `deconfigure' `in-favour'
|
||||
# <package-being-installed> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
PACKAGE=wcs
|
||||
|
||||
case "$1" in
|
||||
remove|upgrade|deconfigure)
|
||||
dpkg --listfiles $PACKAGE |
|
||||
awk '$0~/\.py$/ {print $0"c\n" $0"o"}' |
|
||||
xargs rm -f >&2
|
||||
;;
|
||||
failed-upgrade)
|
||||
;;
|
||||
*)
|
||||
echo "prerm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/make -f
|
||||
# GNU copyright 1997 to 1999 by Joey Hess.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# This is the debhelper compatibility version to use.
|
||||
export DH_COMPAT=3
|
||||
|
||||
|
||||
PYTHON=/usr/bin/python2.3
|
||||
|
||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
INSTALL_PROGRAM += -s
|
||||
endif
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp:
|
||||
dh_testdir
|
||||
touch build-stamp
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
python setup.py install --prefix=$(CURDIR)/debian/wcs/usr --no-compile
|
||||
cd po && make install prefix=$(CURDIR)/debian/wcs/
|
||||
cp debian/vhost-apache-wcs $(CURDIR)/debian/wcs/etc/apache2/sites-available
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installdocs
|
||||
dh_installinit
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install
|
|
@ -0,0 +1,21 @@
|
|||
<VirtualHost *>
|
||||
ServerAdmin webmaster@locahost
|
||||
ServerName www.example.com
|
||||
DocumentRoot /usr/share/wcs/web/
|
||||
|
||||
### <LocationMatch "^/wcs(/|$)">
|
||||
### SetHandler python-program
|
||||
### PythonHandler quixote.server.mod_python_handler
|
||||
### PythonOption quixote-publisher-factory wcs.create_publisher
|
||||
### PythonDebug On
|
||||
### </LocationMatch>
|
||||
|
||||
<Location /wcs>
|
||||
SCGIServer 127.0.0.1:3001
|
||||
SCGIHandler On
|
||||
</Location>
|
||||
|
||||
CustomLog /var/log/apache2/wcs-access.log combined
|
||||
ErrorLog /var/log/apache2/wcs-error.log
|
||||
|
||||
</VirtualHost>
|
|
@ -0,0 +1,87 @@
|
|||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DESC="wcs"
|
||||
NAME=wcs
|
||||
DAEMON=/usr/bin/wcs_scgi_server.py
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
# Gracefully exit if the package has been removed.
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
# Read config file if it is present.
|
||||
if [ -r /etc/default/$NAME ]
|
||||
then
|
||||
. /etc/default/$NAME
|
||||
fi
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service.
|
||||
#
|
||||
d_start() {
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE \
|
||||
--chuid www-data:www-data --make-pidfile --background --exec $DAEMON
|
||||
}
|
||||
|
||||
#
|
||||
# Function that stops the daemon/service.
|
||||
#
|
||||
d_stop() {
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE
|
||||
}
|
||||
|
||||
#
|
||||
# Function that sends a SIGHUP to the daemon/service.
|
||||
#
|
||||
d_reload() {
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
|
||||
--make-pidfile --background --signal 1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $DESC: $NAME"
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: $NAME"
|
||||
d_stop
|
||||
echo "."
|
||||
;;
|
||||
#reload)
|
||||
#
|
||||
# If the daemon can reload its configuration without
|
||||
# restarting (for example, when it is sent a SIGHUP),
|
||||
# then implement that here.
|
||||
#
|
||||
# If the daemon responds to changes in its config file
|
||||
# directly anyway, make this an "exit 0".
|
||||
#
|
||||
# echo -n "Reloading $DESC configuration..."
|
||||
# d_reload
|
||||
# echo "done."
|
||||
#;;
|
||||
restart|force-reload)
|
||||
#
|
||||
# If the "reload" option is implemented, move the "force-reload"
|
||||
# option to the "reload" entry above. If not, "force-reload" is
|
||||
# just the same as "restart".
|
||||
#
|
||||
echo -n "Restarting $DESC: $NAME"
|
||||
d_stop
|
||||
sleep 1
|
||||
d_start
|
||||
echo "."
|
||||
;;
|
||||
*)
|
||||
# echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,38 @@
|
|||
POFILES=$(wildcard *.po)
|
||||
MOFILES=$(POFILES:.po=.mo)
|
||||
PYFILES=$(shell find ../wcs -name '*.py' -or -name '*.ptl')
|
||||
|
||||
all: $(MOFILES)
|
||||
|
||||
install: all
|
||||
for file in $(MOFILES); do \
|
||||
lang=`echo $$file | sed 's/\.mo//'`; \
|
||||
install -d $(prefix)/usr/share/locale/$$lang/LC_MESSAGES/; \
|
||||
install -m 0644 $$file $(prefix)/usr/share/locale/$$lang/LC_MESSAGES/wcs.mo; \
|
||||
done
|
||||
|
||||
wcs.pot: $(PYFILES)
|
||||
@echo "Rebuilding the pot file"
|
||||
rm -f wcs.pot tmp.*.pot
|
||||
cnt=0;
|
||||
for file in $(PYFILES); do \
|
||||
cnt=$$(expr $$cnt + 1); \
|
||||
bn=$$cnt.`basename $$file`; \
|
||||
xgettext --keyword=N_ -c -L Python -o tmp.$$bn.pot $$file; \
|
||||
done
|
||||
msgcat tmp.*.pot > wcs.pot
|
||||
rm tmp.*.pot
|
||||
|
||||
%.mo: %.po
|
||||
msgfmt -o $@ $<
|
||||
|
||||
%.po: wcs.pot
|
||||
@echo -n "Merging wcs.pot and $@"
|
||||
@msgmerge $@ wcs.pot -o $@.new
|
||||
@if [ "`diff $@ $@.new | grep '[<>]' | wc -l`" -ne 2 ]; then \
|
||||
mv -f $@.new $@; \
|
||||
else \
|
||||
rm -f $@.new; \
|
||||
fi
|
||||
@msgfmt --statistics $@
|
||||
|
|
@ -0,0 +1,436 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: wcs 0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2005-05-19 16:00+0200\n"
|
||||
"PO-Revision-Date: 2005-04-29 12:27+0200\n"
|
||||
"Last-Translator: Frederic Peters <fpeters@entrouvert.com>\n"
|
||||
"Language-Team: french\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n>1;\n"
|
||||
|
||||
#: ../wcs/admin/users.ptl:32 ../wcs/admin/users.ptl:49
|
||||
msgid "User Id"
|
||||
msgstr "Identifiant de l'utilisateur"
|
||||
|
||||
#: ../wcs/admin/users.ptl:34 ../wcs/admin/users.ptl:51
|
||||
msgid "User Name"
|
||||
msgstr "Nom de l'utilisateur"
|
||||
|
||||
#: ../wcs/admin/users.ptl:36 ../wcs/admin/users.ptl:53
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: ../wcs/admin/users.ptl:38 ../wcs/admin/users.ptl:55 ../wcs/admin/menu.ptl:6
|
||||
msgid "Roles"
|
||||
msgstr "Rôles"
|
||||
|
||||
#: ../wcs/admin/users.ptl:39 ../wcs/admin/users.ptl:56
|
||||
msgid "Add Role"
|
||||
msgstr "Ajouter un rôle"
|
||||
|
||||
#: ../wcs/admin/users.ptl:43 ../wcs/admin/users.ptl:61
|
||||
#: ../wcs/admin/users.ptl:97 ../wcs/admin/settings.ptl:53
|
||||
#: ../wcs/admin/settings.ptl:125 ../wcs/admin/settings.ptl:141
|
||||
#: ../wcs/admin/forms.ptl:72 ../wcs/admin/forms.ptl:105
|
||||
#: ../wcs/admin/forms.ptl:234 ../wcs/admin/roles.ptl:28
|
||||
#: ../wcs/admin/roles.ptl:38 ../wcs/admin/roles.ptl:73
|
||||
msgid "Submit"
|
||||
msgstr "Valider"
|
||||
|
||||
#: ../wcs/admin/users.ptl:44 ../wcs/admin/users.ptl:60
|
||||
#: ../wcs/admin/users.ptl:96 ../wcs/admin/users.ptl:111
|
||||
#: ../wcs/admin/settings.ptl:142 ../wcs/admin/forms.ptl:73
|
||||
#: ../wcs/admin/forms.ptl:106 ../wcs/admin/forms.ptl:235
|
||||
#: ../wcs/admin/roles.ptl:29 ../wcs/admin/roles.ptl:39
|
||||
#: ../wcs/admin/roles.ptl:74
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: ../wcs/admin/users.ptl:83 ../wcs/admin/users.ptl:84
|
||||
msgid "Edit User"
|
||||
msgstr "Éditer l'utilisateur"
|
||||
|
||||
#: ../wcs/admin/users.ptl:95
|
||||
msgid "You are about to irrevocably delete this user."
|
||||
msgstr "Vous allez définitivement supprimer cet utilisateur."
|
||||
|
||||
#: ../wcs/admin/users.ptl:101
|
||||
msgid "Delete User"
|
||||
msgstr "Supprimer l'utilisateur"
|
||||
|
||||
#: ../wcs/admin/users.ptl:102
|
||||
msgid "Deleting User:"
|
||||
msgstr "Suppression de l'utilisateur :"
|
||||
|
||||
#: ../wcs/admin/users.ptl:112
|
||||
msgid "Generate"
|
||||
msgstr "Générer"
|
||||
|
||||
#: ../wcs/admin/users.ptl:118 ../wcs/admin/users.ptl:119
|
||||
#: ../wcs/admin/users.ptl:127 ../wcs/admin/users.ptl:167
|
||||
msgid "Identification Token"
|
||||
msgstr "Jeton d'identification"
|
||||
|
||||
#: ../wcs/admin/users.ptl:122
|
||||
#, python-format
|
||||
msgid "Note that user has already been issued an identification token: %s"
|
||||
msgstr "À noter que l'utilisateur a déjà un jeton d'identification : %s"
|
||||
|
||||
#: ../wcs/admin/users.ptl:133
|
||||
#, python-format
|
||||
msgid "Identification Token for %s:"
|
||||
msgstr "Jeton d'identification pour %s :"
|
||||
|
||||
#: ../wcs/admin/users.ptl:137
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:139
|
||||
msgid "Send by email"
|
||||
msgstr "Envoyer par email"
|
||||
|
||||
#: ../wcs/admin/users.ptl:157 ../wcs/admin/settings.ptl:27
|
||||
#: ../wcs/admin/forms.ptl:268 ../wcs/admin/roles.ptl:96
|
||||
msgid "New"
|
||||
msgstr "Nouveau"
|
||||
|
||||
#: ../wcs/admin/users.ptl:168 ../wcs/admin/settings.ptl:38
|
||||
#: ../wcs/admin/forms.ptl:166 ../wcs/admin/forms.ptl:278
|
||||
#: ../wcs/admin/roles.ptl:103
|
||||
msgid "Edit"
|
||||
msgstr "Modifier"
|
||||
|
||||
#: ../wcs/admin/users.ptl:169 ../wcs/admin/settings.ptl:39
|
||||
#: ../wcs/admin/forms.ptl:280 ../wcs/admin/roles.ptl:104
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: ../wcs/admin/users.ptl:181 ../wcs/admin/users.ptl:182
|
||||
msgid "New User"
|
||||
msgstr "Nouvel utilisateur"
|
||||
|
||||
#: ../wcs/forms/root.ptl:49 ../wcs/forms/root.ptl:71 ../wcs/forms/root.ptl:157
|
||||
#, python-format
|
||||
msgid "The form has been recorded on %s with the number %s."
|
||||
msgstr "Le formulaire a été enregistré le %s avec le numéro %s."
|
||||
|
||||
#: ../wcs/forms/root.ptl:53
|
||||
msgid "Your case is handled by:"
|
||||
msgstr "Votre dossier est pris en charge par :"
|
||||
|
||||
#: ../wcs/forms/root.ptl:64 ../wcs/forms/root.ptl:79 ../wcs/forms/root.ptl:174
|
||||
msgid "Back Home"
|
||||
msgstr "Retour à l'accueil"
|
||||
|
||||
#: ../wcs/forms/root.ptl:95
|
||||
msgid "Filling"
|
||||
msgstr "Je remplis ma demande"
|
||||
|
||||
#: ../wcs/forms/root.ptl:95
|
||||
msgid "Validating"
|
||||
msgstr "Je confirme ma demande"
|
||||
|
||||
#: ../wcs/forms/root.ptl:95
|
||||
msgid "Receipt"
|
||||
msgstr "Justificatif"
|
||||
|
||||
#: ../wcs/forms/root.ptl:105 ../wcs/forms/root.ptl:116
|
||||
#: ../wcs/forms/root.ptl:146
|
||||
msgid "Next"
|
||||
msgstr "Suivant"
|
||||
|
||||
#: ../wcs/forms/root.ptl:115 ../wcs/forms/root.ptl:145
|
||||
msgid "Previous"
|
||||
msgstr "Précédent"
|
||||
|
||||
#: ../wcs/forms/root.ptl:142
|
||||
msgid "Check values then click next."
|
||||
msgstr "Vérifiez le contenu du formulaire puis cliquer sur 'Suivant'"
|
||||
|
||||
#: ../wcs/forms/root.ptl:161
|
||||
msgid "Your case will be handled by:"
|
||||
msgstr "Votre dossier sera pris en charge par :"
|
||||
|
||||
#: ../wcs/forms/root.ptl:187 ../wcs/admin/menu.ptl:4
|
||||
msgid "Forms"
|
||||
msgstr "Formulaires"
|
||||
|
||||
#: ../wcs/forms/root.ptl:207
|
||||
msgid "Your Current Forms"
|
||||
msgstr "Vos formulaires en cours"
|
||||
|
||||
#: ../wcs/forms/root.ptl:215
|
||||
msgid "Logout"
|
||||
msgstr "Se déconnecter"
|
||||
|
||||
#: ../wcs/forms/root.ptl:218
|
||||
msgid "Login"
|
||||
msgstr "S'identifier"
|
||||
|
||||
#: ../wcs/formdef.py:81
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Hi,\n"
|
||||
"\n"
|
||||
"A new form has been submitted on the website, you can consult it with this\n"
|
||||
"link: %(url)s\n"
|
||||
msgstr ""
|
||||
"Bonjour,\n"
|
||||
"\n"
|
||||
"Un nouveau formulaire a été enregistré sur le site web, vous pouvez en\n"
|
||||
"prendre connaissance en suivant ce lien :\n"
|
||||
"%(url)s\n"
|
||||
|
||||
#: ../wcs/formdef.py:92
|
||||
msgid "A new form has been submitted"
|
||||
msgstr "Un nouveau formulaire a été enregistré"
|
||||
|
||||
#: ../wcs/form.py:6
|
||||
msgid "required field"
|
||||
msgstr "champ obligatoire"
|
||||
|
||||
#: ../wcs/form.py:10
|
||||
msgid "There were errors processing your form. See below for details."
|
||||
msgstr ""
|
||||
"Il y a eu un problème à la soumission du formulaire. Regardez ci-dessous "
|
||||
"pour le détail."
|
||||
|
||||
#: ../wcs/admin/settings.ptl:25 ../wcs/admin/settings.ptl:26
|
||||
#: ../wcs/admin/settings.ptl:182
|
||||
msgid "Identity Providers"
|
||||
msgstr "Fournisseurs d'identités"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:37
|
||||
msgid "View"
|
||||
msgstr "Voir"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:50 ../wcs/admin/settings.ptl:113
|
||||
#: ../wcs/admin/settings.ptl:122
|
||||
msgid "Metadata"
|
||||
msgstr "Metadata"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:51 ../wcs/admin/settings.ptl:123
|
||||
#: ../wcs/admin/settings.ptl:210
|
||||
msgid "Public Key"
|
||||
msgstr "Clé publique"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:52 ../wcs/admin/settings.ptl:124
|
||||
msgid "CA Certificate Chain"
|
||||
msgstr "Chaîne de certification"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:56 ../wcs/admin/settings.ptl:57
|
||||
msgid "New Identity Provider"
|
||||
msgstr "Nouveau fournisseur d'identités"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:108 ../wcs/admin/settings.ptl:111
|
||||
#: ../wcs/admin/settings.ptl:146
|
||||
msgid "Identity Provider"
|
||||
msgstr "Fournisseur d'identités"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:128 ../wcs/admin/settings.ptl:129
|
||||
msgid "Edit Identity Provider"
|
||||
msgstr "Modifier le fournisseur d'identités"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:140
|
||||
msgid "You are about to irrevocably remove this identity provider."
|
||||
msgstr "Vous allez définitivement supprimer ce fournisseur d'identités."
|
||||
|
||||
#: ../wcs/admin/settings.ptl:147
|
||||
msgid "Deleting"
|
||||
msgstr "Suppression"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:176
|
||||
msgid "Service Provider"
|
||||
msgstr "Fournisseur de service"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:176
|
||||
msgid "Configure Liberty parameters"
|
||||
msgstr "Configurer les paramètres Liberty"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:179
|
||||
msgid "Service Provider Metadata"
|
||||
msgstr "Metadata du fournisseur de service"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:179
|
||||
msgid "Download Service Provider Metadata file"
|
||||
msgstr "Télécharger le fichier des metadata du fournisseur de service"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:182
|
||||
msgid "Add and remove identity providers"
|
||||
msgstr "Ajouter et supprimer des fournisseurs d'identités"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:203
|
||||
msgid "Provider ID"
|
||||
msgstr "Identifiant du fournisseur (Provider ID)"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:205
|
||||
msgid "Base URL"
|
||||
msgstr "URL de la racine"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:207
|
||||
msgid "Organization Name"
|
||||
msgstr "Nom de l'organisation"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:209
|
||||
msgid "Private Key"
|
||||
msgstr "Clé privée"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:213
|
||||
msgid "Identity Provider Introduction, Common Domain"
|
||||
msgstr "Domaine commun, pour 'Identity Provider Introduction'"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:214
|
||||
msgid "Disabled if empty"
|
||||
msgstr "Désactivé si vide"
|
||||
|
||||
#: ../wcs/admin/settings.ptl:217 ../wcs/admin/settings.ptl:218
|
||||
msgid "Service Provider Configuration"
|
||||
msgstr "Configuration du fournisseur de service"
|
||||
|
||||
#: ../wcs/admin/menu.ptl:5
|
||||
msgid "Users"
|
||||
msgstr "Utilisateurs"
|
||||
|
||||
#: ../wcs/admin/menu.ptl:7
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
#: ../wcs/admin/menu.ptl:8
|
||||
msgid "WCS Form Server"
|
||||
msgstr "Serveur de formulaires"
|
||||
|
||||
#: ../wcs/admin/menu.ptl:48
|
||||
msgid "WCS Administration"
|
||||
msgstr "Administration de WCS"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:24
|
||||
msgid "Text (line)"
|
||||
msgstr "Texte (ligne)"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:25
|
||||
msgid "Text (block)"
|
||||
msgstr "Bloc de texte"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:26
|
||||
msgid "Boolean"
|
||||
msgstr "Booléen"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:27
|
||||
msgid "Item from list"
|
||||
msgstr "Élément d'une liste"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:28
|
||||
msgid "Title"
|
||||
msgstr "Titre"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:29
|
||||
msgid "Subtitle"
|
||||
msgstr "Sous-titre"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:61
|
||||
msgid "Form Id"
|
||||
msgstr "Identifiant du formulaire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:63
|
||||
msgid "Form Name"
|
||||
msgstr "Nom du formulaire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:65 ../wcs/admin/forms.ptl:279
|
||||
msgid "Fields"
|
||||
msgstr "Champs"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:66
|
||||
msgid "Add Field"
|
||||
msgstr "Ajouter un champ"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:68
|
||||
msgid "Recipient"
|
||||
msgstr "Destinataire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:70
|
||||
msgid "Recipient Email"
|
||||
msgstr "Adresse email du destinataire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:92
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:94
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:97
|
||||
msgid "Required"
|
||||
msgstr "Obligatoire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:101
|
||||
msgid "Items"
|
||||
msgstr "Éléments"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:176
|
||||
msgid "Export to CSV format"
|
||||
msgstr "Exporter au format CSV"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:220 ../wcs/admin/forms.ptl:221
|
||||
msgid "Edit Form"
|
||||
msgstr "Éditer le formulaire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:233
|
||||
msgid "You are about to irrevocably delete this form."
|
||||
msgstr "Vous allez définitivement supprimer ce formulaire."
|
||||
|
||||
#: ../wcs/admin/forms.ptl:239
|
||||
msgid "Delete Form"
|
||||
msgstr "Supprimer le formulaire"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:240
|
||||
msgid "Deleting Form:"
|
||||
msgstr "Suppression du formulaire :"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:281
|
||||
msgid "Listing"
|
||||
msgstr "Listing"
|
||||
|
||||
#: ../wcs/admin/forms.ptl:297 ../wcs/admin/forms.ptl:298
|
||||
msgid "New Form"
|
||||
msgstr "Nouveau formulaire"
|
||||
|
||||
#: ../wcs/admin/roles.ptl:24 ../wcs/admin/roles.ptl:34
|
||||
msgid "Role Id"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:26 ../wcs/admin/roles.ptl:36
|
||||
msgid "Role Name"
|
||||
msgstr "Nom du rôle"
|
||||
|
||||
#: ../wcs/admin/roles.ptl:60 ../wcs/admin/roles.ptl:61
|
||||
msgid "Edit Role"
|
||||
msgstr "Éditer le rôle"
|
||||
|
||||
#: ../wcs/admin/roles.ptl:72
|
||||
msgid "You are about to irrevocably delete this role."
|
||||
msgstr "Vous allez définitivement supprimer ce rôle."
|
||||
|
||||
#: ../wcs/admin/roles.ptl:78
|
||||
msgid "Delete Role"
|
||||
msgstr "Supprimer le rôle"
|
||||
|
||||
#: ../wcs/admin/roles.ptl:79
|
||||
msgid "Deleting Role:"
|
||||
msgstr "Suppression du rôle :"
|
||||
|
||||
#: ../wcs/admin/roles.ptl:116 ../wcs/admin/roles.ptl:117
|
||||
msgid "New Role"
|
||||
msgstr "Nouveau rôle"
|
||||
|
||||
#~ msgid "Forms Management"
|
||||
#~ msgstr "Gestion des formulaires"
|
||||
|
||||
#~ msgid "Field Details"
|
||||
#~ msgstr "Détail des champs"
|
||||
|
||||
#~ msgid "List Item"
|
||||
#~ msgstr "Liste"
|
|
@ -0,0 +1,425 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2005-05-19 16:00+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../wcs/admin/users.ptl:32 ../wcs/admin/users.ptl:49
|
||||
msgid "User Id"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:34 ../wcs/admin/users.ptl:51
|
||||
msgid "User Name"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:36 ../wcs/admin/users.ptl:53
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:38 ../wcs/admin/users.ptl:55 ../wcs/admin/menu.ptl:6
|
||||
msgid "Roles"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:39 ../wcs/admin/users.ptl:56
|
||||
msgid "Add Role"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:43 ../wcs/admin/users.ptl:61
|
||||
#: ../wcs/admin/users.ptl:97 ../wcs/admin/settings.ptl:53
|
||||
#: ../wcs/admin/settings.ptl:125 ../wcs/admin/settings.ptl:141
|
||||
#: ../wcs/admin/forms.ptl:72 ../wcs/admin/forms.ptl:105
|
||||
#: ../wcs/admin/forms.ptl:234 ../wcs/admin/roles.ptl:28
|
||||
#: ../wcs/admin/roles.ptl:38 ../wcs/admin/roles.ptl:73
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:44 ../wcs/admin/users.ptl:60
|
||||
#: ../wcs/admin/users.ptl:96 ../wcs/admin/users.ptl:111
|
||||
#: ../wcs/admin/settings.ptl:142 ../wcs/admin/forms.ptl:73
|
||||
#: ../wcs/admin/forms.ptl:106 ../wcs/admin/forms.ptl:235
|
||||
#: ../wcs/admin/roles.ptl:29 ../wcs/admin/roles.ptl:39
|
||||
#: ../wcs/admin/roles.ptl:74
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:83 ../wcs/admin/users.ptl:84
|
||||
msgid "Edit User"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:95
|
||||
msgid "You are about to irrevocably delete this user."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:101
|
||||
msgid "Delete User"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:102
|
||||
msgid "Deleting User:"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:112
|
||||
msgid "Generate"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:118 ../wcs/admin/users.ptl:119
|
||||
#: ../wcs/admin/users.ptl:127 ../wcs/admin/users.ptl:167
|
||||
msgid "Identification Token"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:122
|
||||
#, python-format
|
||||
msgid "Note that user has already been issued an identification token: %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:133
|
||||
#, python-format
|
||||
msgid "Identification Token for %s:"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:137
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:139
|
||||
msgid "Send by email"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:157 ../wcs/admin/settings.ptl:27
|
||||
#: ../wcs/admin/forms.ptl:268 ../wcs/admin/roles.ptl:96
|
||||
msgid "New"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:168 ../wcs/admin/settings.ptl:38
|
||||
#: ../wcs/admin/forms.ptl:166 ../wcs/admin/forms.ptl:278
|
||||
#: ../wcs/admin/roles.ptl:103
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:169 ../wcs/admin/settings.ptl:39
|
||||
#: ../wcs/admin/forms.ptl:280 ../wcs/admin/roles.ptl:104
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/users.ptl:181 ../wcs/admin/users.ptl:182
|
||||
msgid "New User"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:49 ../wcs/forms/root.ptl:71 ../wcs/forms/root.ptl:157
|
||||
#, python-format
|
||||
msgid "The form has been recorded on %s with the number %s."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:53
|
||||
msgid "Your case is handled by:"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:64 ../wcs/forms/root.ptl:79 ../wcs/forms/root.ptl:174
|
||||
msgid "Back Home"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:95
|
||||
msgid "Filling"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:95
|
||||
msgid "Validating"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:95
|
||||
msgid "Receipt"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:105 ../wcs/forms/root.ptl:116
|
||||
#: ../wcs/forms/root.ptl:146
|
||||
msgid "Next"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:115 ../wcs/forms/root.ptl:145
|
||||
msgid "Previous"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:142
|
||||
msgid "Check values then click next."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:161
|
||||
msgid "Your case will be handled by:"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:187 ../wcs/admin/menu.ptl:4
|
||||
msgid "Forms"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:207
|
||||
msgid "Your Current Forms"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:215
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/forms/root.ptl:218
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/formdef.py:81
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Hi,\n"
|
||||
"\n"
|
||||
"A new form has been submitted on the website, you can consult it with this\n"
|
||||
"link: %(url)s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/formdef.py:92
|
||||
msgid "A new form has been submitted"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/form.py:6
|
||||
msgid "required field"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/form.py:10
|
||||
msgid "There were errors processing your form. See below for details."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:25 ../wcs/admin/settings.ptl:26
|
||||
#: ../wcs/admin/settings.ptl:182
|
||||
msgid "Identity Providers"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:37
|
||||
msgid "View"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:50 ../wcs/admin/settings.ptl:113
|
||||
#: ../wcs/admin/settings.ptl:122
|
||||
msgid "Metadata"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:51 ../wcs/admin/settings.ptl:123
|
||||
#: ../wcs/admin/settings.ptl:210
|
||||
msgid "Public Key"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:52 ../wcs/admin/settings.ptl:124
|
||||
msgid "CA Certificate Chain"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:56 ../wcs/admin/settings.ptl:57
|
||||
msgid "New Identity Provider"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:108 ../wcs/admin/settings.ptl:111
|
||||
#: ../wcs/admin/settings.ptl:146
|
||||
msgid "Identity Provider"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:128 ../wcs/admin/settings.ptl:129
|
||||
msgid "Edit Identity Provider"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:140
|
||||
msgid "You are about to irrevocably remove this identity provider."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:147
|
||||
msgid "Deleting"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:176
|
||||
msgid "Service Provider"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:176
|
||||
msgid "Configure Liberty parameters"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:179
|
||||
msgid "Service Provider Metadata"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:179
|
||||
msgid "Download Service Provider Metadata file"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:182
|
||||
msgid "Add and remove identity providers"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:203
|
||||
msgid "Provider ID"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:205
|
||||
msgid "Base URL"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:207
|
||||
msgid "Organization Name"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:209
|
||||
msgid "Private Key"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:213
|
||||
msgid "Identity Provider Introduction, Common Domain"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:214
|
||||
msgid "Disabled if empty"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/settings.ptl:217 ../wcs/admin/settings.ptl:218
|
||||
msgid "Service Provider Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/menu.ptl:5
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/menu.ptl:7
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/menu.ptl:8
|
||||
msgid "WCS Form Server"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/menu.ptl:48
|
||||
msgid "WCS Administration"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:24
|
||||
msgid "Text (line)"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:25
|
||||
msgid "Text (block)"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:26
|
||||
msgid "Boolean"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:27
|
||||
msgid "Item from list"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:28
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:29
|
||||
msgid "Subtitle"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:61
|
||||
msgid "Form Id"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:63
|
||||
msgid "Form Name"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:65 ../wcs/admin/forms.ptl:279
|
||||
msgid "Fields"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:66
|
||||
msgid "Add Field"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:68
|
||||
msgid "Recipient"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:70
|
||||
msgid "Recipient Email"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:92
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:94
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:97
|
||||
msgid "Required"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:101
|
||||
msgid "Items"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:176
|
||||
msgid "Export to CSV format"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:220 ../wcs/admin/forms.ptl:221
|
||||
msgid "Edit Form"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:233
|
||||
msgid "You are about to irrevocably delete this form."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:239
|
||||
msgid "Delete Form"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:240
|
||||
msgid "Deleting Form:"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:281
|
||||
msgid "Listing"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/forms.ptl:297 ../wcs/admin/forms.ptl:298
|
||||
msgid "New Form"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:24 ../wcs/admin/roles.ptl:34
|
||||
msgid "Role Id"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:26 ../wcs/admin/roles.ptl:36
|
||||
msgid "Role Name"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:60 ../wcs/admin/roles.ptl:61
|
||||
msgid "Edit Role"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:72
|
||||
msgid "You are about to irrevocably delete this role."
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:78
|
||||
msgid "Delete Role"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:79
|
||||
msgid "Deleting Role:"
|
||||
msgstr ""
|
||||
|
||||
#: ../wcs/admin/roles.ptl:116 ../wcs/admin/roles.ptl:117
|
||||
msgid "New Role"
|
||||
msgstr ""
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,260 @@
|
|||
@import url(wcs-common.css);
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background : white url(fond.jpg) repeat;
|
||||
}
|
||||
|
||||
div#main-content {
|
||||
clear: both;
|
||||
max-width: 700px;
|
||||
margin: 0 8em;
|
||||
background: white url(deg-top.png) top left repeat-x;
|
||||
border: 1px solid #999;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
div#main-content h1 {
|
||||
margin: 0 140px 1em 0;
|
||||
border: 1px solid #666;
|
||||
padding: 0 0.5ex;
|
||||
background: white url(bg-footer.png) top right repeat-y;
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
div.form, div.idp {
|
||||
border: 1px solid #aaa;
|
||||
margin-bottom: 1em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.form h3, div.idp h3 {
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
font-weight: normal;
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
div.form p, div.idp p {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
div.form span.data, div.idp span.data {
|
||||
float: left;
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
div.form span.cmds, div.idp span.cmds {
|
||||
font-size: 80%;
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#header {
|
||||
max-width: 700px;
|
||||
margin: 0 8em;
|
||||
padding: 0 1em;
|
||||
background-image : url(dot999.png);
|
||||
background-repeat : repeat-x;
|
||||
background-position : 0 100%;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
#header ul {
|
||||
margin : 0;
|
||||
padding : 0;
|
||||
list-style : none;
|
||||
}
|
||||
|
||||
#header li {
|
||||
float : left;
|
||||
margin : 0 -1px 0 0;
|
||||
padding : 0 0 0 8px;
|
||||
background-repeat : no-repeat;
|
||||
background-position : 0 -110px;
|
||||
background-image: url(onglet_left.png);
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
#header a {
|
||||
float : left;
|
||||
display : block;
|
||||
background-image : url(onglet_right.png);
|
||||
background-repeat : no-repeat;
|
||||
background-position : 100% -110px;
|
||||
padding : 10px 10px 4px 3px;
|
||||
font-weight : bold;
|
||||
text-decoration : none;
|
||||
color : #000;
|
||||
}
|
||||
|
||||
/* Commented Backslash Hack
|
||||
Cache des règles à IE5-Mac \*/
|
||||
#header a {float:none;}
|
||||
/* Fin du hack IE5-Mac */
|
||||
|
||||
#header li.active, #header li.active:hover {
|
||||
background-position : 0 0;
|
||||
}
|
||||
#header li.active a, #header li.active:hover a {
|
||||
background-position : 100% 0;
|
||||
}
|
||||
#header li:hover {
|
||||
background-position : 0 -220px;
|
||||
}
|
||||
#header li:hover a {
|
||||
background-position : 100% -220px;
|
||||
}
|
||||
|
||||
#header li.active {
|
||||
border-bottom: 1px solid #eceade;
|
||||
}
|
||||
|
||||
div#footer {
|
||||
max-width: 700px;
|
||||
margin: 0 8em;
|
||||
border: 1px solid #999;
|
||||
border-top: 0;
|
||||
background: #eceade;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
div#footer p {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
div#login-top,
|
||||
div#logout-top,
|
||||
div#identity-top {
|
||||
margin: 6em auto 1em auto;
|
||||
border: 1px solid #999;
|
||||
background: white;
|
||||
padding: 0.5ex 1em;
|
||||
}
|
||||
|
||||
div#login-top,
|
||||
div#login-form {
|
||||
width: 20em;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
div#logout-top,
|
||||
div#logout-sps,
|
||||
div#identity-top,
|
||||
div#identity-content {
|
||||
width: 40em;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
div#login-top h1,
|
||||
div#logout-top h1,
|
||||
div#identity-top h1 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#login-form,
|
||||
div#logout-sps,
|
||||
div#identity-content {
|
||||
margin: 0 auto;
|
||||
background: white url(deg-top.png) top left repeat-x;
|
||||
border: 1px solid #999;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
div#login-form br {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#login-form div.StringWidget {
|
||||
margin-bottom: 1ex;
|
||||
}
|
||||
|
||||
p#cookies {
|
||||
margin: 0 1em;
|
||||
text-align: center;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
form#login span.required {
|
||||
display: none
|
||||
}
|
||||
|
||||
div#logout-sps ul li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
div#logout-sps ul {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
div#logout-sps ul li img {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
ul.user-info {
|
||||
float : right;
|
||||
width : 102px;
|
||||
position : relative;
|
||||
margin : 0 0 1em 1em;
|
||||
padding : 5px 0 0 30px;
|
||||
background : transparent url(user_info_top.png) no-repeat top left;
|
||||
list-style : none;
|
||||
}
|
||||
li.ui-name {
|
||||
}
|
||||
li.ui-logout {
|
||||
display : block;
|
||||
background : transparent url(user_info_bottom.png) no-repeat bottom left;
|
||||
padding : 8px 0 10px 10px;
|
||||
margin : 0 0 0 -30px;
|
||||
}
|
||||
|
||||
li.ui-logout a {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
table {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
table th {
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding-right: 1ex;
|
||||
}
|
||||
|
||||
dl dt {
|
||||
margin : 0;
|
||||
padding : 0 0 0 0;
|
||||
}
|
||||
|
||||
dl dd {
|
||||
margin : 0.3em 0 1.5em 10px;
|
||||
}
|
||||
|
||||
div#identity-content hr {
|
||||
margin: 1em 2em;
|
||||
height: 1px;
|
||||
background: #999;
|
||||
border: 0;
|
||||
|
||||
}
|
||||
|
||||
div.FieldWidget div.StringWidget {
|
||||
float: left;
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
br.FieldWidget,
|
||||
div.FieldWidget br {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
a {
|
||||
color: #00a;
|
||||
}
|
||||
|
||||
div.content {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
div.TextWidget textarea,
|
||||
div.StringWidget input,
|
||||
div.PasswordWidget input {
|
||||
border: 1px inset #ccc;
|
||||
margin: 1px;
|
||||
padding: 1px 2px;
|
||||
}
|
||||
|
||||
div.StringWidget input[readonly=readonly] {
|
||||
border: 1px solid #ccc;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
div.StringWidget input:focus,
|
||||
div.PasswordWidget input:focus {
|
||||
border: 2px solid #ccf;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
div.AccountSettingWidget label {
|
||||
padding-right: 2em;
|
||||
}
|
||||
|
||||
div.SubmitWidget input, input[type=submit] {
|
||||
margin-top: 1em;
|
||||
border: 1px outset #ccc;
|
||||
}
|
||||
|
||||
div.form div.title, form.quixote div.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.errornotice {
|
||||
background: #fd6;
|
||||
border: 1px solid #ffae15;
|
||||
margin: 0em 1em 1em 1em;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
div.error {
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
background: white url(warning.png) top left no-repeat;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
div.buttons div.SubmitWidget,
|
||||
div.buttons div.SubmitWidget div.content {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.buttons br { display: none; }
|
||||
|
||||
div.widget {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
input[type="submit"][name="submit"] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.form pre {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
|
||||
div#error h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div#error {
|
||||
width: 40em;
|
||||
max-width: 500px;
|
||||
margin: 15% auto;
|
||||
background: white;
|
||||
border: 1px solid #999;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
div.hint {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
span.required {
|
||||
background: url(required.png) top right no-repeat;
|
||||
padding: 0 0 0 12px;
|
||||
font-size: 0%; /* hide star */
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.buttons {
|
||||
margin-top: 1em;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
@import url(wcs-common.css);
|
||||
|
||||
html, body {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
background: #eee;
|
||||
color: black;
|
||||
}
|
||||
|
||||
div#page {
|
||||
width: 800px;
|
||||
margin: 2em auto;
|
||||
text-align: justify;
|
||||
background: white url(img/page.png) repeat-y;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#top {
|
||||
color: #09F;
|
||||
background: #FFF url(img/top.jpg) no-repeat;
|
||||
}
|
||||
|
||||
#top h1 {
|
||||
margin: 0;
|
||||
padding-top: 30px;
|
||||
padding-left: 30px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
background: #FFF url(img/footer.jpg) no-repeat;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
div#main-content {
|
||||
margin: 0 2em;
|
||||
}
|
||||
|
||||
#steps {
|
||||
height: 32px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#steps ol {
|
||||
list-style: none;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
#steps li {
|
||||
display: inline;
|
||||
padding-right: 2em;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
|
||||
#steps span.marker {
|
||||
font-size: 26px;
|
||||
padding: 2px 9px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-align: center;
|
||||
background: #ddd;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#steps li.current span.marker {
|
||||
background: #ffa500;
|
||||
border: 1px solid #ffc400;
|
||||
}
|
||||
|
||||
#steps span.label {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
#steps li.current span.label {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#steps {
|
||||
background: #f0f0f0;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
form {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
p#receiver {
|
||||
margin: 0;
|
||||
margin-left: 2em;
|
||||
margin-top: -0.7em;
|
||||
margin-bottom: 1em;
|
||||
padding: 2px 5px;
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
background: #ffe;
|
||||
}
|
||||
|
||||
dl {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
p#login,
|
||||
p#logout {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
h2#submitted {
|
||||
margin-top: 2em;
|
||||
color: #09F;
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
ul li {
|
||||
list-style: circle;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>w.c.s.</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/wcs.css"/>
|
||||
<style type="text/css">
|
||||
p#wcs {
|
||||
margin-top: 30%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p id="wcs">
|
||||
w.c.s
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import os
|
||||
import glob
|
||||
import distutils.core
|
||||
import distutils.sysconfig
|
||||
import distutils.command
|
||||
from quixote.ptl.qx_distutils import qx_build_py
|
||||
|
||||
distutils.core.setup(
|
||||
name = 'wcs',
|
||||
version = "0.0.0",
|
||||
maintainer = "Frederic Peters",
|
||||
maintainer_email = "fpeters@entrouvert.com",
|
||||
url = "http://wcs.labs.libre-entreprise.org",
|
||||
package_dir = { 'wcs': 'wcs' },
|
||||
packages = ['wcs', 'wcs.admin', 'wcs.forms', 'wcs.liberty'],
|
||||
cmdclass = {'build_py': qx_build_py},
|
||||
scripts = ['wcs_scgi_server.py'],
|
||||
data_files = [('share/wcs/web/', ( 'root/index.html',)),
|
||||
('share/wcs/web/css', tuple(
|
||||
glob.glob('root/css/*.css') + \
|
||||
glob.glob('root/css/*.jpg') + \
|
||||
glob.glob('root/css/*.png'))),
|
||||
('share/wcs/web/css/img', tuple(
|
||||
glob.glob('root/css/img/*.jpg') + \
|
||||
glob.glob('root/css/img/*.png'))),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,74 @@
|
|||
APP_DIR = '/var/tmp/wcs'
|
||||
|
||||
import os
|
||||
import lasso
|
||||
import __builtin__
|
||||
|
||||
import storage
|
||||
import gettext, locale
|
||||
|
||||
gettext.install('wcs')
|
||||
_1 = _
|
||||
__builtin__.__dict__['_'] = lambda x: unicode(_1(str(x)), 'utf-8').encode('iso-8859-1')
|
||||
__builtin__.__dict__['N_'] = lambda x: x
|
||||
|
||||
if not os.path.exists(APP_DIR):
|
||||
os.mkdir(APP_DIR)
|
||||
|
||||
from quixote import enable_ptl, errors, get_session, redirect, get_session_manager
|
||||
from quixote.publish import Publisher
|
||||
from quixote.directory import Directory
|
||||
enable_ptl()
|
||||
|
||||
import wcs.misc
|
||||
|
||||
import sessions
|
||||
|
||||
import admin.root
|
||||
import forms.root
|
||||
import liberty.root
|
||||
|
||||
class RootDirectory(Directory):
|
||||
_q_exports = ["", "admin", "forms", "login", "logout", "liberty"]
|
||||
|
||||
def _q_index(self):
|
||||
return redirect('forms')
|
||||
|
||||
def login(self):
|
||||
return self.liberty.login()
|
||||
|
||||
def logout(self):
|
||||
get_session_manager().expire_session()
|
||||
redirect('.')
|
||||
|
||||
admin = admin.root.RootDirectory()
|
||||
forms = forms.root.RootDirectory()
|
||||
liberty = liberty.root.RootDirectory()
|
||||
|
||||
|
||||
class WcsPublisher(Publisher):
|
||||
def format_publish_error(self, exc):
|
||||
if isinstance(exc, errors.AccessError) and hasattr(exc, 'render'):
|
||||
return exc.render()
|
||||
return Publisher.format_publish_error(self, exc)
|
||||
|
||||
def try_publish(self, request):
|
||||
# called for each request, should set APP_DIR here for a kind of
|
||||
# virtual hosting (set it from HTTP header, hostname, uri, whatever)
|
||||
global app_dir
|
||||
app_dir = wcs.APP_DIR + '/_TEST'
|
||||
wcs.misc.filename = os.path.join(app_dir, 'config.pck')
|
||||
wcs.misc.reload_cfg()
|
||||
storage.FilesStorage.BASEDIR = app_dir
|
||||
return Publisher.try_publish(self, request)
|
||||
|
||||
|
||||
def create_publisher():
|
||||
session_manager = sessions.PickleSessionManager()
|
||||
|
||||
return WcsPublisher(RootDirectory(),
|
||||
session_manager = session_manager,
|
||||
session_cookie_name = 'wcs',
|
||||
display_exceptions = 'plain',
|
||||
#error_email = "fpeters@entrouvert.com",
|
||||
session_cookie_path = '/')
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,316 @@
|
|||
import re
|
||||
import os
|
||||
|
||||
from quixote import get_request, get_response, redirect
|
||||
from quixote.directory import Directory
|
||||
from quixote import errors
|
||||
from quixote.html import htmltext
|
||||
from quixote.util import dump_request
|
||||
|
||||
from menu import html_top, html_foot
|
||||
|
||||
import wcs.misc
|
||||
from wcs.formdef import FormDef
|
||||
from wcs import storage
|
||||
|
||||
from wcs.form import *
|
||||
|
||||
def ellipsize(s, length = 30):
|
||||
if not s or len(s) < length:
|
||||
return s
|
||||
return s[:length-5] + ' (...)'
|
||||
|
||||
def get_user_roles():
|
||||
l = []
|
||||
for role in storage.get_storage().values('roles'):
|
||||
l.append( (role.id, role.name) )
|
||||
return l
|
||||
|
||||
field_types = [ ('string', _('Text (line)')),
|
||||
('text', _('Text (block)')),
|
||||
('bool', _('Boolean')),
|
||||
('item', _('Item from list')),
|
||||
('title', _('Title')),
|
||||
('subtitle', _('Subtitle')),
|
||||
]
|
||||
|
||||
class FieldWidget(CompositeWidget):
|
||||
def __init__(self, name, value=None, **kwargs):
|
||||
CompositeWidget.__init__(self, name, value, **kwargs)
|
||||
if not value:
|
||||
value = {}
|
||||
self.value = value
|
||||
self.add(StringWidget, 'name', value.get('name', ''))
|
||||
self.add(SingleSelectWidget, 'type', value.get('type', ''), required=True,
|
||||
options = field_types)
|
||||
|
||||
def render_content [html] (self):
|
||||
name_widget = self.get_widget('name')
|
||||
name_widget.render()
|
||||
type_widget = self.get_widget('type')
|
||||
type_widget.render()
|
||||
|
||||
def _parse(self, request):
|
||||
for k in ('name', 'type'):
|
||||
self.value[k] = self.get(k)
|
||||
if not self.value.has_key('required'):
|
||||
self.value['required'] = True
|
||||
|
||||
|
||||
class FormDefUI:
|
||||
def __init__(self, formdef):
|
||||
self.formdef = formdef
|
||||
|
||||
def edit_form_ui [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "id", title = _('Form Id'), required = True, size=30,
|
||||
value = self.formdef.id)
|
||||
form.add(StringWidget, "name", title = _('Form Name'), required = True, size=30,
|
||||
value = self.formdef.name)
|
||||
form.add(WidgetList, 'fields', title = _('Fields'), element_type = FieldWidget,
|
||||
value = self.formdef.fields, add_element_label = _('Add Field'),
|
||||
element_kwargs = {str('render_br'): False})
|
||||
form.add(TextWidget, "receiver", title = _('Recipient'), required = True,
|
||||
value = self.formdef.receiver, rows = 3, cols = 40)
|
||||
form.add(StringWidget, "emailrcpt", title = _('Recipient Email'), size=30,
|
||||
value = self.formdef.emailrcpt)
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
hint = _('Only show this form to the given roles.'),
|
||||
value = self.formdef.roles, add_element_label = _('Add Role'),
|
||||
element_kwargs = {str('render_br'): False,
|
||||
str('options'): [('', '---')] + get_user_roles()})
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('id', 'name', 'emailrcpt', 'fields', 'receiver'):
|
||||
setattr(self.formdef, f, form.get_widget(f).parse())
|
||||
self.formdef.fields = [x for x in self.formdef.fields if x['name']] # remove empty names
|
||||
self.formdef.roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
|
||||
class FormDefFieldPage(Directory):
|
||||
_q_exports = [""]
|
||||
|
||||
def __init__(self, formdef, field_no):
|
||||
self.formdef = formdef
|
||||
self.field_no = field_no
|
||||
|
||||
def form(self):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, 'name', title = _('Name'), value = value.get('name', ''),
|
||||
readonly = "readonly")
|
||||
form.add(SingleSelectWidget, 'type', title = _('Type'),
|
||||
value = value.get('type', ''), required=True,
|
||||
options = field_types)
|
||||
form.add(CheckboxWidget, 'required', title = _('Required'),
|
||||
value = value.get('required', False))
|
||||
|
||||
if value.get('type') == 'item':
|
||||
form.add(WidgetList, 'items', title = _('Items'), element_type = StringWidget,
|
||||
value = value.get('items', []), required = True,
|
||||
element_kwargs = {str('render_br'): False})
|
||||
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
|
||||
return form
|
||||
|
||||
def _q_index [html] (self):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
form = self.form()
|
||||
redo = False
|
||||
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('../fields')
|
||||
|
||||
if form.get_widget('items') and form.get_widget('items').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
if redo or not form.is_submitted() or form.has_errors():
|
||||
html_top('forms', 'Form - %s' % self.formdef.name)
|
||||
'<h2>%s - %s</h2>' % (self.formdef.name, value['name'])
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.submit(form)
|
||||
if form.get_widget('items') is None and value['type'] == 'item':
|
||||
return redirect('.')
|
||||
return redirect('..')
|
||||
|
||||
def submit(self, form):
|
||||
value = self.formdef.fields[self.field_no]
|
||||
for f in ('name', 'type', 'required', 'items'):
|
||||
w = form.get_widget(f)
|
||||
if not w:
|
||||
if value.has_key(f):
|
||||
del value[f]
|
||||
continue
|
||||
value[f] = w.parse()
|
||||
storage.get_storage().store(self.formdef)
|
||||
|
||||
class FormDefPage(Directory):
|
||||
_q_exports = ["fields", "edit", "delete", "listing", "csv"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.formdef = storage.get_storage().retrieve('formdefs', component)
|
||||
self.formdefui = FormDefUI(self.formdef)
|
||||
|
||||
def fields [html] (self):
|
||||
html_top('forms', 'Form - %s' % self.formdef.name)
|
||||
'<h2>%s</h2>' % self.formdef.name
|
||||
'<table>'
|
||||
for i, field in enumerate(self.formdef.fields):
|
||||
'<tr>'
|
||||
if field['type'] in ('subtitle', 'title'):
|
||||
'<td colspan="4"><strong>%s</strong></td>' % field['name']
|
||||
else:
|
||||
type = [x[1] for x in field_types if x[0] == field['type']][0]
|
||||
if field.has_key('required') and field['required']:
|
||||
required = ''
|
||||
else:
|
||||
required = _('optional')
|
||||
'<td>%s</td> <td>%s</td> <td>%s</td> <td><a href="field-%d">%s</a></td>' % (
|
||||
field['name'], type, required, i, _('Edit'))
|
||||
'</tr>'
|
||||
'</table>'
|
||||
|
||||
html_foot()
|
||||
|
||||
def listing [html] (self):
|
||||
html_top('forms', 'Form - %s' % self.formdef.name)
|
||||
names = 'form-' + self.formdef.id
|
||||
'<h2>%s</h2>' % self.formdef.name
|
||||
"""<a href="csv">%s</a>""" % _('Export to CSV format')
|
||||
"""<table id="listing"><thead><tr>"""
|
||||
for f in self.formdef.fields:
|
||||
if f['type'] in ('title', 'subtitle'):
|
||||
continue
|
||||
"<th>%s</th>" % f['name']
|
||||
"</tr></thead>"
|
||||
"<tbody>"
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
"<tr>"
|
||||
for f in self.formdef.fields:
|
||||
if f['type'] in ('title', 'subtitle'):
|
||||
continue
|
||||
"<td>%s</td>" % filled.data.get(f['name'], '')
|
||||
"</tr>"
|
||||
"</tbody></table>"
|
||||
html_foot()
|
||||
|
||||
def csv [plain] (self):
|
||||
names = 'form-' + self.formdef.id
|
||||
|
||||
def fixcsv(s):
|
||||
if not s: return s
|
||||
return s.replace('\n', ' ').replace(';', ',')
|
||||
|
||||
for k in storage.get_storage().keys(names):
|
||||
filled = storage.get_storage().retrieve(names, k)
|
||||
';'.join([fixcsv(filled.data.get(x['name'])) for x in self.formdef.fields]) + '\r\n'
|
||||
response = get_response()
|
||||
response.set_content_type('text/csv')
|
||||
|
||||
def edit [html] (self):
|
||||
form = self.formdefui.edit_form_ui()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
redo = False
|
||||
if form.get_widget('fields').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
if redo or not form.is_submitted() or form.has_errors():
|
||||
form.get_widget('id').attrs[str('readonly')] = str('readonly')
|
||||
form.get_widget('id').required = False
|
||||
html_top('forms', title = _('Edit Form'))
|
||||
"""<h2>%s</h2>""" % _('Edit Form')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.formdefui.submit_form(form)
|
||||
storage.get_storage().store(self.formdef)
|
||||
return redirect('..')
|
||||
|
||||
def delete [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.widgets.append(HtmlWidget("""<p>%s</p>""" % _(
|
||||
"You are about to irrevocably delete this form.")))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('..')
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('forms', title = _('Delete Form'))
|
||||
"""<h2>%s %s</h2>""" % (_('Deleting Form:'), self.formdef.name)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('formdefs', self.formdef.id)
|
||||
storage.get_storage().remove_all('form-%s' % self.formdef.id)
|
||||
return redirect('..')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
if not component.startswith('field-'):
|
||||
raise TraversalError()
|
||||
try:
|
||||
field_no = int(component[6:])
|
||||
except ValueError:
|
||||
raise TraversalError()
|
||||
return FormDefFieldPage(self.formdef, field_no)
|
||||
|
||||
|
||||
|
||||
class FormsDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "new"]
|
||||
|
||||
def _q_index [html] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
html_top('forms', title = 'Forms')
|
||||
"""<ul id="nav-forms-admin">
|
||||
<li><a href="new">%s</a></li>
|
||||
</ul>""" % _('New')
|
||||
|
||||
for k in storage.get_storage().keys('formdefs'):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
"""<div class="form">"""
|
||||
"<h3>%s</h3>" % formdef.name
|
||||
"""<span class="data">
|
||||
<span class="name">%s</span>
|
||||
</span>""" % ellipsize(formdef.receiver, 50)
|
||||
"""<span class="cmds"> [ """
|
||||
"""<a href="%s/edit">%s</a> - """ % (k, _('Edit'))
|
||||
"""<a href="%s/fields">%s</a> - """ % (k, _('Fields'))
|
||||
"""<a href="%s/delete">%s</a> - """ % (k, _('Delete'))
|
||||
"""<a href="%s/listing">%s</a> """ % (k, _('Listing'))
|
||||
"]</span></p></div>"
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
formdef = FormDef()
|
||||
formdefui = FormDefUI(formdef)
|
||||
form = formdefui.edit_form_ui()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
redo = False
|
||||
if form.get_widget('fields').get_widget('add_element').parse():
|
||||
form.clear_errors()
|
||||
redo = True
|
||||
|
||||
if redo or not form.is_submitted() or form.has_errors():
|
||||
html_top('forms', title = _('New Form'))
|
||||
"""<h2>%s</h2>""" % _('New Form')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
formdefui.submit_form(form)
|
||||
storage.get_storage().store(formdef)
|
||||
return redirect(formdef.id + '/fields')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return FormDefPage(component)
|
|
@ -0,0 +1,51 @@
|
|||
import quixote
|
||||
|
||||
items = [
|
||||
('forms', N_('Forms')),
|
||||
('users', N_('Users')),
|
||||
('roles', N_('Roles')),
|
||||
('settings', N_('Settings')),
|
||||
('/', N_('WCS Form Server'))]
|
||||
|
||||
def header_menu [html] (selected = None):
|
||||
s = ["""<ul id="menu">\n"""]
|
||||
base_url = quixote.get_request().get_path(-1)
|
||||
for k, v in items:
|
||||
if k == '/':
|
||||
continue # skip root
|
||||
if k == selected:
|
||||
s.append('<li class="active">')
|
||||
else:
|
||||
s.append('<li>')
|
||||
s.append('<a href="%s/%s/">%s</a></li>\n' % (base_url, k, _(v)))
|
||||
s.append('</ul>\n')
|
||||
return ''.join(s)
|
||||
|
||||
def user_info [html] ():
|
||||
return ''
|
||||
|
||||
|
||||
def html_top [html] (section, title = None):
|
||||
subtitle = ''
|
||||
for s in items:
|
||||
if s[0] == section:
|
||||
subtitle = _(s[1])
|
||||
if not title:
|
||||
title = ''
|
||||
else:
|
||||
title = ' - ' + title
|
||||
return """<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>%s%s</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/wcs-admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">%s</div>
|
||||
<div id="main-content">
|
||||
%s
|
||||
<h1>%s</h1>
|
||||
|
||||
""" % (_('WCS Administration'), title, header_menu(section), user_info(), subtitle)
|
||||
|
||||
def html_foot [html] ():
|
||||
return """</div><div id="footer"><p id="lasso">Powered by Lasso</p></div></body></html>"""
|
|
@ -0,0 +1,126 @@
|
|||
import re
|
||||
import os
|
||||
|
||||
from quixote import get_request, get_response, redirect
|
||||
from quixote.directory import Directory
|
||||
from quixote import errors
|
||||
from quixote.html import htmltext
|
||||
from quixote.util import dump_request
|
||||
|
||||
from menu import html_top, html_foot
|
||||
|
||||
import wcs.misc
|
||||
from wcs.roles import Role
|
||||
from wcs import storage
|
||||
|
||||
from wcs.form import *
|
||||
|
||||
class RoleUI:
|
||||
def __init__(self, role):
|
||||
self.role = role
|
||||
|
||||
def form_new(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "id", title = _('Role Id'), required = True, size=30,
|
||||
value = self.role.id)
|
||||
form.add(StringWidget, "name", title = _('Role Name'), required = True, size=30,
|
||||
value = self.role.name)
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def form_edit(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "id", title = _('Role Id'), required = False, size=30,
|
||||
value = self.role.id, readonly = 'readonly')
|
||||
form.add(StringWidget, "name", title = _('Role Name'), required = True, size=30,
|
||||
value = self.role.name)
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('id', 'name'):
|
||||
setattr(self.role, f, form.get_widget(f).parse())
|
||||
|
||||
|
||||
class RolePage(Directory):
|
||||
_q_exports = ["edit", "delete"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.role = storage.get_storage().retrieve('roles', component)
|
||||
self.role_ui = RoleUI(self.role)
|
||||
|
||||
def edit [html] (self):
|
||||
form = self.role_ui.form_edit()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('roles', title = _('Edit Role'))
|
||||
"""<h2>%s</h2>""" % _('Edit Role')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.role_ui.submit_form(form)
|
||||
storage.get_storage().store(self.role)
|
||||
return redirect('..')
|
||||
|
||||
def delete [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.widgets.append(HtmlWidget("""<p>%s</p>""" % _(
|
||||
"You are about to irrevocably delete this role.")))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('..')
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('roles', title = _('Delete Role'))
|
||||
"""<h2>%s %s</h2>""" % (_('Deleting Role:'), self.role.name)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('roles', self.role.id)
|
||||
return redirect('..')
|
||||
|
||||
|
||||
class RolesDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "new"]
|
||||
|
||||
def _q_index [html] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
html_top('roles', title = 'Roles')
|
||||
"""<ul id="nav-roles-admin">
|
||||
<li><a href="new">%s</a></li>
|
||||
</ul>""" % _('New')
|
||||
|
||||
for k in storage.get_storage().keys('roles'):
|
||||
role = storage.get_storage().retrieve('roles', k)
|
||||
"""<div class="form">"""
|
||||
"<h3>%s</h3>" % role.name
|
||||
"""<span class="cmds"> [ """
|
||||
"""<a href="%s/edit">%s</a> - """ % (k, _('Edit'))
|
||||
"""<a href="%s/delete">%s</a> """ % (k, _('Delete'))
|
||||
"]</span></p></div>"
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
role = Role()
|
||||
role_ui = RoleUI(role)
|
||||
form = role_ui.form_new()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('roles', title = _('New Role'))
|
||||
"""<h2>%s</h2>""" % _('New Role')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
role_ui.submit_form(form)
|
||||
storage.get_storage().store(role)
|
||||
return redirect('.')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return RolePage(component)
|
|
@ -0,0 +1,43 @@
|
|||
from quixote import get_response, get_session
|
||||
from quixote.directory import Directory, AccessControlled
|
||||
|
||||
import settings
|
||||
import forms
|
||||
import roles
|
||||
import users
|
||||
|
||||
from menu import html_top, html_foot
|
||||
|
||||
import wcs.errors
|
||||
|
||||
def gpl [html] ():
|
||||
"""<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.</p>
|
||||
"""
|
||||
|
||||
|
||||
class RootDirectory(AccessControlled, Directory): #, AccessControlled):
|
||||
|
||||
_q_exports = ["", "settings", "forms", "roles", "users"]
|
||||
|
||||
def _q_index [html] (self):
|
||||
html_top('/')
|
||||
gpl()
|
||||
html_foot()
|
||||
|
||||
settings = settings.SettingsDirectory()
|
||||
forms = forms.FormsDirectory()
|
||||
roles = roles.RolesDirectory()
|
||||
users = users.UsersDirectory()
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
import cPickle
|
||||
import re
|
||||
import os
|
||||
import lasso
|
||||
|
||||
from quixote import get_request, get_response, redirect
|
||||
from quixote.directory import Directory
|
||||
from quixote import errors
|
||||
from quixote.form import *
|
||||
from quixote.form.widget import Widget
|
||||
from quixote.html import htmltext
|
||||
from quixote.util import dump_request
|
||||
|
||||
from menu import html_top, html_foot
|
||||
|
||||
import wcs.misc
|
||||
from wcs.form import *
|
||||
|
||||
|
||||
class LibertyIDPDir(Directory):
|
||||
_q_exports = ["", "new"]
|
||||
|
||||
def _q_index [html] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
html_top('settings', title = _('Identity Providers'))
|
||||
"<h2>%s</h2>" % _('Identity Providers')
|
||||
"""<ul id="nav-idp-admin"> <li><a href="new">%s</a></li> </ul>""" % _('New')
|
||||
|
||||
'<div id="idp-list">'
|
||||
for kidp, idp in wcs.misc.cfg.get('idp', {}).items():
|
||||
p = lasso.Provider(lasso.PROVIDER_ROLE_IDP, idp['metadata'], idp['publickey'], None)
|
||||
|
||||
"""<div class="idp">"""
|
||||
"<h3>%s</h3>" % wcs.misc.get_provider_label(p)
|
||||
'<p><span class="data">%s</span>' % p.providerId
|
||||
"""<span class="cmds">[ """
|
||||
"""<a href="%s">%s</a> - """ % (kidp, _('View'))
|
||||
"""<a href="%s/edit">%s</a> - """ % (kidp, _('Edit'))
|
||||
"""<a href="%s/delete">%s</a> """ % (kidp, _('Delete'))
|
||||
"""]</span></p></div>"""
|
||||
'</div>'
|
||||
html_foot()
|
||||
|
||||
def _q_lookup(self, component):
|
||||
wcs.misc.reload_cfg()
|
||||
return LibertyIDPUI(component)
|
||||
|
||||
def new [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(FileWidget, "metadata", title = _("Metadata"), required=True)
|
||||
form.add(FileWidget, "publickey", title = _("Public Key"), required=True)
|
||||
form.add(FileWidget, "cacertchain", title = _("CA Certificate Chain"), required=False)
|
||||
form.add_submit("submit", _("Submit"))
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('settings', title = _('New Identity Provider'))
|
||||
"<h2>%s</h2>" % _('New Identity Provider')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.submit_new(form)
|
||||
|
||||
def submit_new(self, form, key_provider_id = None):
|
||||
wcs.misc.reload_cfg()
|
||||
d = wcs.misc.cfg.get('idp', {})
|
||||
wcs.misc.cfg['idp'] = d
|
||||
|
||||
metadata, publickey, cacertchain = None, None, None
|
||||
if form.get_widget('metadata').parse():
|
||||
metadata = form.get_widget('metadata').parse().fp.read()
|
||||
if form.get_widget('publickey').parse():
|
||||
publickey = form.get_widget('publickey').parse().fp.read()
|
||||
if form.get_widget('cacertchain').parse():
|
||||
cacertchain = form.get_widget('cacertchain').parse().fp.read()
|
||||
|
||||
if not key_provider_id:
|
||||
provider_id = re.findall(r'providerID="(.*?)"', metadata)[0]
|
||||
key_provider_id = provider_id.replace(str('://'), str('-')).replace(str('/'), str('-'))
|
||||
|
||||
metadata_fn = os.path.join(wcs.app_dir, 'idp-%s-metadata.xml' % key_provider_id)
|
||||
publickey_fn = os.path.join(wcs.app_dir, 'idp-%s-publickey.pem' % key_provider_id)
|
||||
cacertchain_fn = os.path.join(wcs.app_dir, 'idp-%s-cacertchain.pem' % key_provider_id)
|
||||
|
||||
if metadata:
|
||||
file(metadata_fn, 'w').write(metadata)
|
||||
if publickey:
|
||||
file(publickey_fn, 'w').write(publickey)
|
||||
if cacertchain:
|
||||
file(cacertchain_fn, 'w').write(cacertchain)
|
||||
|
||||
wcs.misc.cfg['idp'][key_provider_id] = {
|
||||
'metadata': metadata_fn,
|
||||
'publickey': publickey_fn,
|
||||
'cacertchain': cacertchain_fn
|
||||
}
|
||||
wcs.misc.write_cfg()
|
||||
redirect('.')
|
||||
|
||||
|
||||
class LibertyIDPUI(Directory):
|
||||
_q_exports = ["", "delete", "edit"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.idp = wcs.misc.cfg['idp'][component]
|
||||
self.idpk = component
|
||||
|
||||
def _q_index [html] (self):
|
||||
html_top('settings', title = _('Identity Provider'))
|
||||
p = lasso.Provider(lasso.PROVIDER_ROLE_SP,
|
||||
self.idp['metadata'], self.idp['publickey'], self.idp.get('cacertchain', None))
|
||||
'<h2>%s - %s</h2>' % (_('Identity Provider'), p.providerId)
|
||||
'<div class="form">'
|
||||
'<h3>%s</h3>' % _('Metadata')
|
||||
'<pre>'
|
||||
file(self.idp['metadata']).read()
|
||||
'</pre>'
|
||||
'</div>'
|
||||
html_foot()
|
||||
|
||||
def edit [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(FileWidget, "metadata", title = _("Metadata"))
|
||||
form.add(FileWidget, "publickey", title = _("Public Key"))
|
||||
form.add(FileWidget, "cacertchain", title = _("CA Certificate Chain"))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('settings', title = _('Edit Identity Provider'))
|
||||
"<h2>%s</h2>" % _('Edit Identity Provider')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
t = LibertyIDPDir()
|
||||
t.submit_new(form, self.idpk)
|
||||
|
||||
def delete [html] (self):
|
||||
p = lasso.Provider(lasso.PROVIDER_ROLE_SP, self.idp['metadata'], self.idp['publickey'], None)
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.widgets.append(HtmlWidget("<p>%s</p>" % _(
|
||||
"You are about to irrevocably remove this identity provider.")))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('..')
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('settings', title = _('Identity Provider'))
|
||||
"""<h2>%s %s</h2>""" % (_('Deleting'), p.providerId)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.delete_submitted()
|
||||
|
||||
def delete_submitted(self):
|
||||
del wcs.misc.cfg['idp'][self.idpk]
|
||||
metadata_fn = os.path.join(wcs.app_dir, 'idp-%s-metadata.xml' % self.idpk)
|
||||
publickey_fn = os.path.join(wcs.app_dir, 'idp-%s-publickey.pem' % self.idpk)
|
||||
cacertchain_fn = os.path.join(wcs.app_dir, 'idp-%s-cacertchain.pem' % self.idpk)
|
||||
os.unlink(metadata_fn)
|
||||
os.unlink(publickey_fn)
|
||||
os.unlink(cacertchain_fn)
|
||||
wcs.misc.write_cfg()
|
||||
return redirect('..')
|
||||
|
||||
|
||||
|
||||
class SettingsDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "liberty_idp", "liberty_sp", ("metadata.xml", "metadata")]
|
||||
|
||||
def _q_index [html] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
html_top('settings', title = 'Settings')
|
||||
"""<h2>Liberty Alliance</h2>
|
||||
<dl>"""
|
||||
"""<dt><a href="liberty_sp">%s</a></dt> <dd>%s</dd>""" % (
|
||||
_('Service Provider'), _('Configure Liberty parameters'))
|
||||
if wcs.misc.cfg.has_key(str('sp')):
|
||||
"""<dt><a href="metadata.xml">%s</a></dt> <dd>%s</dd>""" % (
|
||||
_('Service Provider Metadata'), _('Download Service Provider Metadata file'))
|
||||
|
||||
"""<dt><a href="liberty_idp">%s</a></dt> <dd>%s</dd> </dl>""" % (
|
||||
_('Identity Providers'), _('Add and remove identity providers'))
|
||||
|
||||
"</dl>"
|
||||
|
||||
html_foot()
|
||||
|
||||
def liberty_sp [html] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
base_url = wcs.misc.cfg.get("sp", {}).get('base_url', None)
|
||||
common_domain = wcs.misc.cfg.get("sp", {}).get("common_domain", None)
|
||||
req = get_request()
|
||||
|
||||
if not common_domain and not base_url: # probably the first time we get here
|
||||
domain_parts = req.get_server().split(str('.'))
|
||||
if len(domain_parts) >= 2:
|
||||
common_domain = '.'.join(domain_parts[-2:])
|
||||
|
||||
if not base_url:
|
||||
base_url = "%s://%s%s" % (req.get_scheme(), req.get_server(),
|
||||
req.get_path(-1).replace(str('/admin'), str('/liberty')))
|
||||
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "providerid", title=_("Provider ID"), size=50, required=True,
|
||||
value = wcs.misc.cfg.get("sp", {}).get('providerid', None))
|
||||
form.add(StringWidget, "base_url", title=_("Base URL"), size=50, required=True,
|
||||
value = base_url)
|
||||
form.add(StringWidget, "organization_name", title=_("Organization Name"), size=50,
|
||||
value = wcs.misc.cfg.get("sp", {}).get('organization_name', None))
|
||||
form.add(FileWidget, "privatekey", title = _("Private Key"))
|
||||
form.add(FileWidget, "publickey", title = _("Public Key"))
|
||||
|
||||
form.add(StringWidget, "common_domain",
|
||||
title = _("Identity Provider Introduction, Common Domain"),
|
||||
hint = _("Disabled if empty"), value = common_domain)
|
||||
form.add_submit("submit", "Submit")
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('settings', title = _('Service Provider Configuration'))
|
||||
'<h2>%s</h2>' % _('Service Provider Configuration')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.liberty_sp_save(form)
|
||||
redirect('.')
|
||||
|
||||
def liberty_sp_save(self, form):
|
||||
wcs.misc.reload_cfg()
|
||||
if not wcs.misc.cfg.has_key('sp'):
|
||||
wcs.misc.cfg['sp'] = {}
|
||||
for k in ('providerid', 'base_url', 'organization_name', 'common_domain'):
|
||||
wcs.misc.cfg['sp'][k] = form.get_widget(k).parse()
|
||||
|
||||
privatekey_fn = os.path.join(wcs.app_dir, 'private-key.pem')
|
||||
value = form.get_widget('privatekey').parse()
|
||||
if value:
|
||||
file(privatekey_fn, 'w').write(value.fp.read())
|
||||
if os.path.exists(privatekey_fn):
|
||||
wcs.misc.cfg['sp']['privatekey'] = privatekey_fn
|
||||
|
||||
publickey_fn = os.path.join(wcs.app_dir, 'public-key.pem')
|
||||
value = form.get_widget('publickey').parse()
|
||||
if value:
|
||||
file(publickey_fn, 'w').write(value.fp.read())
|
||||
if os.path.exists(publickey_fn):
|
||||
wcs.misc.cfg['sp']['publickey'] = publickey_fn
|
||||
|
||||
metadata_fn = os.path.join(wcs.app_dir, 'metadata.xml')
|
||||
file(metadata_fn, 'w').write(self.get_metadata())
|
||||
wcs.misc.cfg['sp']['metadata'] = metadata_fn
|
||||
wcs.misc.write_cfg()
|
||||
|
||||
def get_metadata(self):
|
||||
return """<?xml version="1.0"?>
|
||||
<EntityDescriptor
|
||||
providerID="%(providerid)s"
|
||||
xmlns="urn:liberty:metadata:2003-08">
|
||||
<SPDescriptor protocolSupportEnumeration="urn:liberty:iff:2003-08">
|
||||
|
||||
<SoapEndpoint>%(base_url)s/soapEndpoint</SoapEndpoint>
|
||||
|
||||
<SingleLogoutServiceURL>%(base_url)s/singleLogout</SingleLogoutServiceURL>
|
||||
<SingleLogoutServiceReturnURL>%(base_url)s/singleLogoutReturn</SingleLogoutServiceReturnURL>
|
||||
|
||||
<FederationTerminationServiceURL>%(base_url)s/federationTermination</FederationTerminationServiceURL>
|
||||
<FederationTerminationServiceReturnURL>%(base_url)s/federationTerminationReturn</FederationTerminationServiceReturnURL>
|
||||
<FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-idp-soap</FederationTerminationNotificationProtocolProfile>
|
||||
<FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-idp-http</FederationTerminationNotificationProtocolProfile>
|
||||
<FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-sp-soap</FederationTerminationNotificationProtocolProfile>
|
||||
<FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-sp-http</FederationTerminationNotificationProtocolProfile>
|
||||
|
||||
<SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-idp-soap</SingleLogoutProtocolProfile>
|
||||
<SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-idp-http</SingleLogoutProtocolProfile>
|
||||
<SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-sp-soap</SingleLogoutProtocolProfile>
|
||||
<SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-sp-http</SingleLogoutProtocolProfile>
|
||||
|
||||
<RegisterNameIdentifierServiceURL>%(base_url)s/registerNameIdentifier</RegisterNameIdentifierServiceURL>
|
||||
<RegisterNameIdentifierServiceReturnURL>%(base_url)s/registerNameIdentifierReturn</RegisterNameIdentifierServiceReturnURL>
|
||||
<RegisterNameIdentifierProtocolProfile>http://projectliberty.org/profiles/rni-idp-soap</RegisterNameIdentifierProtocolProfile>
|
||||
<RegisterNameIdentifierProtocolProfile>http://projectliberty.org/profiles/rni-idp-http</RegisterNameIdentifierProtocolProfile>
|
||||
<RegisterNameIdentifierProtocolProfile>http://projectliberty.org/profiles/rni-sp-soap</RegisterNameIdentifierProtocolProfile>
|
||||
<RegisterNameIdentifierProtocolProfile>http://projectliberty.org/profiles/rni-sp-http</RegisterNameIdentifierProtocolProfile>
|
||||
|
||||
<AuthnRequestsSigned>true</AuthnRequestsSigned>
|
||||
|
||||
<AssertionConsumerServiceURL id="AssertionConsumerServiceURL1" isDefault="true">%(base_url)s/assertionConsumer</AssertionConsumerServiceURL>
|
||||
|
||||
|
||||
</SPDescriptor>
|
||||
|
||||
<Organization>
|
||||
<OrganizationName>%(organization_name)s</OrganizationName>
|
||||
</Organization>
|
||||
|
||||
</EntityDescriptor>""" % wcs.misc.cfg['sp']
|
||||
|
||||
|
||||
def metadata [plain] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
response = get_response()
|
||||
response.set_content_type('text/xml')
|
||||
self.get_metadata()
|
||||
|
||||
liberty_idp = LibertyIDPDir()
|
|
@ -0,0 +1,191 @@
|
|||
import random
|
||||
import re
|
||||
import os
|
||||
|
||||
from quixote import get_request, get_response, redirect
|
||||
from quixote.directory import Directory
|
||||
from quixote import errors
|
||||
from quixote.html import htmltext
|
||||
from quixote.util import dump_request
|
||||
|
||||
from menu import html_top, html_foot
|
||||
|
||||
import wcs.misc
|
||||
from wcs.users import User
|
||||
from wcs import storage
|
||||
|
||||
from wcs.form import *
|
||||
|
||||
def get_user_roles():
|
||||
l = []
|
||||
for role in storage.get_storage().values('roles'):
|
||||
l.append( (role.id, role.name) )
|
||||
return l
|
||||
|
||||
|
||||
class UserUI:
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
|
||||
def form_new(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "id", title = _('User Id'), required = True, size=30,
|
||||
value = self.user.id)
|
||||
form.add(StringWidget, "name", title = _('User Name'), required = True, size=30,
|
||||
value = self.user.name)
|
||||
form.add(StringWidget, "email", title = _('Email'), required = False, size=30,
|
||||
value = self.user.email)
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
value = self.user.roles, add_element_label = _('Add Role'),
|
||||
element_kwargs = {str('render_br'): False,
|
||||
str('options'): [('', '---')] + get_user_roles()})
|
||||
|
||||
form.add_submit("submit", _("Submit"))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
return form
|
||||
|
||||
def form_edit(self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "id", title = _('User Id'), required = False, size=30,
|
||||
value = self.user.id, readonly = 'readonly')
|
||||
form.add(StringWidget, "name", title = _('User Name'), required = True, size=30,
|
||||
value = self.user.name)
|
||||
form.add(StringWidget, "email", title = _('Email'), required = False, size=30,
|
||||
value = self.user.email)
|
||||
form.add(WidgetList, 'roles', title = _('Roles'), element_type = SingleSelectWidget,
|
||||
value = self.user.roles, add_element_label = _('Add Role'),
|
||||
element_kwargs = {str('render_br'): False,
|
||||
str('options'): [('', '---')] + get_user_roles()})
|
||||
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
return form
|
||||
|
||||
def submit_form(self, form):
|
||||
for f in ('id', 'name', 'email'):
|
||||
setattr(self.user, f, form.get_widget(f).parse())
|
||||
self.user.roles = [x for x in form.get_widget('roles').parse() if x]
|
||||
|
||||
|
||||
class UserPage(Directory):
|
||||
_q_exports = ["edit", "delete", "token"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.user = storage.get_storage().retrieve('users', component)
|
||||
self.user_ui = UserUI(self.user)
|
||||
|
||||
def edit [html] (self):
|
||||
form = self.user_ui.form_edit()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('..')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('users', title = _('Edit User'))
|
||||
"""<h2>%s</h2>""" % _('Edit User')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
self.user_ui.submit_form(form)
|
||||
storage.get_storage().store(self.user)
|
||||
return redirect('..')
|
||||
|
||||
def delete [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.widgets.append(HtmlWidget("""<p>%s</p>""" % _(
|
||||
"You are about to irrevocably delete this user.")))
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('..')
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('users', title = _('Delete User'))
|
||||
"""<h2>%s %s</h2>""" % (_('Deleting User:'), self.user.name)
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
storage.get_storage().remove_id('users', self.user.id)
|
||||
return redirect('..')
|
||||
|
||||
def token [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
form.add_submit("submit", _("Generate"))
|
||||
request = get_request()
|
||||
if request.form.has_key('cancel') or request.form.has_key('done'):
|
||||
return redirect('..')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('users', title = _('Identification Token'))
|
||||
"<h2>%s</h2>" % _('Identification Token')
|
||||
"<p>bla bla bla (explanation)</p>"
|
||||
if self.user.identification_token:
|
||||
"<p>%s</p>" % _('Note that user has already been issued an identification token: %s') % self.user.identification_token
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
if request.form.has_key('submit'):
|
||||
html_top('users', title = _('Identification Token'))
|
||||
token = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)])
|
||||
self.user.identification_token = str(token)
|
||||
storage.get_storage().store(self.user)
|
||||
|
||||
"<p>"
|
||||
_('Identification Token for %s:') % self.user.name
|
||||
" %s</p>" % self.user.identification_token
|
||||
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add_submit('done', _('Done'))
|
||||
if self.user.email:
|
||||
form.add_submit("submit-email", _("Send by email"))
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
pass # send by email
|
||||
|
||||
|
||||
|
||||
|
||||
class UsersDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "new"]
|
||||
|
||||
def _q_index [html] (self):
|
||||
wcs.misc.reload_cfg()
|
||||
html_top('users', title = 'Users')
|
||||
"""<ul id="nav-users-admin">
|
||||
<li><a href="new">%s</a></li>
|
||||
</ul>""" % _('New')
|
||||
|
||||
users = storage.get_storage().values('users')
|
||||
users.sort(lambda x,y: cmp(x.name, y.name))
|
||||
|
||||
for user in users:
|
||||
"""<div class="form">"""
|
||||
"<h3>%s</h3>" % user.name
|
||||
"""<span class="cmds"> [ """
|
||||
if not user.name_identifiers:
|
||||
"""<a href="%s/token">%s</a> - """ % (user.id, _('Identification Token'))
|
||||
"""<a href="%s/edit">%s</a> - """ % (user.id, _('Edit'))
|
||||
"""<a href="%s/delete">%s</a> """ % (user.id, _('Delete'))
|
||||
"]</span></p></div>"
|
||||
html_foot()
|
||||
|
||||
def new [html] (self):
|
||||
user = User()
|
||||
user_ui = UserUI(user)
|
||||
form = user_ui.form_new()
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top('users', title = _('New User'))
|
||||
"""<h2>%s</h2>""" % _('New User')
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
user_ui.submit_form(form)
|
||||
storage.get_storage().store(user)
|
||||
return redirect('.')
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return UserPage(component)
|
|
@ -0,0 +1,14 @@
|
|||
import quixote
|
||||
from quixote.errors import *
|
||||
|
||||
class AccessUnauthorizedError(AccessError):
|
||||
def render(self):
|
||||
session = quixote.get_session()
|
||||
request = quixote.get_request()
|
||||
session.after_url = request.environ['SCRIPT_NAME'] + request.environ['PATH_INFO']
|
||||
quixote.redirect('/wcs/login')
|
||||
|
||||
class AccessForbiddenError(AccessError):
|
||||
def render [html] (self):
|
||||
"AccessForbiddenError"
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
from quixote.form import *
|
||||
from quixote.html import htmltext
|
||||
|
||||
QuixoteForm = Form
|
||||
|
||||
Widget.REQUIRED_ERROR = _('required field')
|
||||
|
||||
class Form(QuixoteForm):
|
||||
ERROR_NOTICE = htmltext('<div class="errornotice">%s</div>' % _(
|
||||
"There were errors processing your form. See below for details."))
|
||||
|
||||
def add(self, widget_class, name, *args, **kwargs):
|
||||
if kwargs and not kwargs.has_key('render_br'):
|
||||
kwargs['render_br'] = False
|
||||
return QuixoteForm.add(self, widget_class, name, *args, **kwargs)
|
||||
|
||||
def _render_submit_widgets(self):
|
||||
return htmltext('<div class="buttons">%s</div>' % QuixoteForm._render_submit_widgets(self))
|
||||
|
||||
|
||||
class HtmlWidget:
|
||||
def __init__(self, string):
|
||||
self.string = string
|
||||
|
||||
def render(self):
|
||||
return self.string
|
|
@ -0,0 +1,13 @@
|
|||
import storage
|
||||
|
||||
class FormData(storage.Storable):
|
||||
key = 'id'
|
||||
names = 'forms'
|
||||
user_id = None
|
||||
|
||||
def __init__(self):
|
||||
self.id = None
|
||||
self.data = None
|
||||
self.receipt_date = None
|
||||
self.user_id = None
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
from email.MIMEText import MIMEText
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
import smtplib
|
||||
|
||||
try:
|
||||
import docutils
|
||||
import docutils.core
|
||||
except ImportError:
|
||||
docutils = None
|
||||
|
||||
from quixote import get_request
|
||||
|
||||
import storage
|
||||
|
||||
from form import *
|
||||
|
||||
widget_classes = {
|
||||
'string': StringWidget,
|
||||
'text': TextWidget,
|
||||
'bool': CheckboxWidget,
|
||||
'item': SingleSelectWidget,
|
||||
}
|
||||
|
||||
|
||||
class FormDef(storage.Storable):
|
||||
key = 'id'
|
||||
names = 'formdefs'
|
||||
receiver = None
|
||||
roles = None
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
self.fields = []
|
||||
self.receiver = ''
|
||||
self.emailrcpt = ''
|
||||
self.roles = []
|
||||
|
||||
def create_form(self): # XXX: merge create_form and create_view_form
|
||||
form = Form(enctype = "multipart/form-data")
|
||||
for i, field in enumerate(self.fields):
|
||||
if field['type'] == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h3>%s</h3>" % field['name'])))
|
||||
continue
|
||||
if field['type'] == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h4>%s</h4>" % field['name'])))
|
||||
continue
|
||||
kwargs = {'required': field.get('required', True)}
|
||||
if field['type'] == 'item':
|
||||
kwargs['options'] = field.get('items', ['---'])
|
||||
form.add(widget_classes[field['type']], "f%d" % i, title = field['name'],
|
||||
**kwargs)
|
||||
return form
|
||||
|
||||
def create_view_form(self, dict = {}):
|
||||
form = Form(enctype = "multipart/form-data")
|
||||
for i, field in enumerate(self.fields):
|
||||
kwargs = {}
|
||||
if field['type'] == 'title':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h3>%s</h3>" % field['name'])))
|
||||
continue
|
||||
if field['type'] == 'subtitle':
|
||||
form.widgets.append(HtmlWidget(htmltext("<h4>%s</h4>" % field['name'])))
|
||||
continue
|
||||
if field['type'] == 'item':
|
||||
kwargs['options'] = field.get('items', ['---'])
|
||||
form.add(widget_classes[field['type']], "f%d" % i, title = field['name'],
|
||||
readonly = "readonly", value = dict.get(field['name'], ''), **kwargs)
|
||||
return form
|
||||
|
||||
def get_data(self, form):
|
||||
d = {}
|
||||
for i, field in enumerate(self.fields):
|
||||
if field['type'] in ('title', 'subtitle'):
|
||||
continue
|
||||
d[field['name']] = form.get_widget('f%d' % i).parse()
|
||||
return d
|
||||
|
||||
def notify_new(self, formdata):
|
||||
if not self.emailrcpt:
|
||||
return
|
||||
url = '%s/%s/status' % (get_request().get_url(1), formdata.id)
|
||||
mail_body = _("""Hi,
|
||||
|
||||
A new form has been submitted on the website, you can consult it with this
|
||||
link: %(url)s
|
||||
""") % {'url': url}
|
||||
try:
|
||||
htmlmail = docutils.core.publish_string(mail_body, writer_name="html")
|
||||
except IOError:
|
||||
htmlmail = None
|
||||
|
||||
msg = MIMEText(mail_body, _charset = 'iso-8859-15')
|
||||
msg['Subject'] = _("A new form has been submitted")
|
||||
msg['To'] = self.emailrcpt
|
||||
msg['From'] = 'WCS <noreply@entrouvert.com>'
|
||||
msg['X-Mailer'] = 'w.c.s.'
|
||||
|
||||
s = smtplib.SMTP()
|
||||
s.connect()
|
||||
s.sendmail('noreply@entrouvert.com', [msg['To']], msg.as_string())
|
||||
s.close()
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,297 @@
|
|||
import time
|
||||
import os
|
||||
|
||||
from quixote import get_response, get_session, redirect
|
||||
from quixote.directory import Directory
|
||||
|
||||
import wcs.errors
|
||||
from wcs.form import *
|
||||
import wcs.misc
|
||||
|
||||
import wcs.formdata
|
||||
from wcs import storage
|
||||
|
||||
|
||||
def html_top [html] (title = None):
|
||||
return """<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>%s</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/wcs.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="top">
|
||||
<h1>%s</h1>
|
||||
</div>
|
||||
<div id="main-content">""" % (title, title)
|
||||
|
||||
def html_foot [html] ():
|
||||
return """</div><div id="footer"><p id="lasso">Powered by Lasso</p></div></div></body></html>"""
|
||||
|
||||
class FormStatusPage(Directory):
|
||||
_q_exports = ["", "status"]
|
||||
|
||||
def __init__(self, formdef, component):
|
||||
self.formdef = formdef
|
||||
try:
|
||||
self.filled = storage.get_storage().retrieve("form-" + formdef.id, component)
|
||||
except KeyError:
|
||||
raise wcs.errors.TraversalError()
|
||||
|
||||
def _q_index [html] (self):
|
||||
session = get_session()
|
||||
if not session or self.filled.user_id != session.user:
|
||||
raise wcs.errors.AccessError()
|
||||
html_top(self.formdef.name + ' - ' + self.filled.id)
|
||||
tm = time.strftime(str("%Y-%m-%d %H:%M"), self.filled.receipt_time)
|
||||
"<p>"
|
||||
_('The form has been recorded on %s with the number %s.') % (tm, self.filled.id)
|
||||
"</p>"
|
||||
if self.formdef.receiver:
|
||||
"<p>"
|
||||
_('Your case is handled by:')
|
||||
"</p>"
|
||||
'<p id="receiver">'
|
||||
htmltext(self.formdef.receiver.replace(str('\n'), str('<br />')))
|
||||
"</p>"
|
||||
"""<dl id="receipt">"""
|
||||
for f in self.formdef.fields:
|
||||
if self.filled.data.has_key(f['name']):
|
||||
"<dt>%s</dt>" % f['name']
|
||||
"<dd>%s</dd>" % self.filled.data[f['name']]
|
||||
"</dl>"
|
||||
'<a href="../..">%s</a>' % _("Back Home")
|
||||
html_foot()
|
||||
|
||||
def status [html] (self):
|
||||
html_top(self.formdef.name + ' - ' + self.filled.id)
|
||||
tm = time.strftime(str("%Y-%m-%d %H:%M"), self.filled.receipt_time)
|
||||
"<p>"
|
||||
_('The form has been recorded on %s with the number %s.') % (tm, self.filled.id)
|
||||
"</p>"
|
||||
"""<dl id="receipt">"""
|
||||
for f in self.formdef.fields:
|
||||
if self.filled.data.has_key(f['name']):
|
||||
"<dt>%s</dt>" % f['name']
|
||||
"<dd>%s</dd>" % self.filled.data[f['name']]
|
||||
"</dl>"
|
||||
'<a href="../..">%s</a>' % _("Back Home")
|
||||
html_foot()
|
||||
|
||||
|
||||
class FormPage(Directory):
|
||||
_q_exports = ["", "submit"]
|
||||
|
||||
def __init__(self, component):
|
||||
self.component = component
|
||||
try:
|
||||
self.formdef = storage.get_storage().retrieve('formdefs', component)
|
||||
except KeyError:
|
||||
raise wcs.errors.TraversalError()
|
||||
|
||||
session = get_session()
|
||||
user = None
|
||||
if session:
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
except KeyError:
|
||||
pass
|
||||
if self.formdef.roles:
|
||||
if not user:
|
||||
raise wcs.errors.AccessForbiddenError()
|
||||
for q in user.roles or []:
|
||||
if q in self.formdef.roles:
|
||||
break
|
||||
else:
|
||||
raise wcs.errors.AccessForbiddenError()
|
||||
|
||||
|
||||
def step [html] (self, no):
|
||||
"""<div id="steps"><ol>"""
|
||||
for i, l in enumerate([_("Filling"), _("Validating"), _("Receipt")]):
|
||||
if no == i:
|
||||
'<li class="current step-%d">' % i
|
||||
else:
|
||||
'<li class="step-%d">' % i
|
||||
'<span class="marker">%d</span> <span class="label">%s</span></li>' % (i+1, l)
|
||||
"</ol></div>"
|
||||
|
||||
def _q_index [html] (self):
|
||||
form = self.formdef.create_form()
|
||||
form.add_submit("submit", _("Next"))
|
||||
html_top(self.formdef.name)
|
||||
self.step(0)
|
||||
form.action = 'submit'
|
||||
form.add_hidden('step', '0')
|
||||
form.render()
|
||||
html_foot()
|
||||
|
||||
def submit(self):
|
||||
form = self.formdef.create_form()
|
||||
form.add_submit("previous", _("Previous"))
|
||||
form.add_submit("submit", _("Next"))
|
||||
form.add_hidden('step', '-1')
|
||||
|
||||
step = form.get_widget('step').parse()
|
||||
if step == '1':
|
||||
if form.get_widget('previous').parse():
|
||||
return self._q_index()
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
return self._q_index()
|
||||
if step == '0':
|
||||
return self.validating()
|
||||
else:
|
||||
filled = wcs.formdata.FormData()
|
||||
filled.names = 'form-' + self.component
|
||||
filled.data = self.formdef.get_data(form)
|
||||
filled.receipt_time = time.localtime()
|
||||
session = get_session()
|
||||
if session and session.user:
|
||||
filled.user_id = session.user
|
||||
storage.get_storage().store(filled)
|
||||
self.formdef.notify_new(filled)
|
||||
return self.receipt(filled)
|
||||
|
||||
def validating [html] (self):
|
||||
html_top(self.formdef.name)
|
||||
self.step(1)
|
||||
"""<p>%s</p>""" % _("Check values then click next.")
|
||||
form = self.formdef.create_view_form()
|
||||
form.action = 'submit'
|
||||
form.add_submit("previous", _("Previous"))
|
||||
form.add_submit("submit", _("Next"))
|
||||
form.add_hidden('step', '1')
|
||||
form.render()
|
||||
html_foot()
|
||||
|
||||
def receipt [html] (self, filled):
|
||||
html_top(self.formdef.name)
|
||||
self.step(2)
|
||||
|
||||
tm = time.strftime(str("%Y-%m-%d %H:%M"), filled.receipt_time)
|
||||
"<p>"
|
||||
_('The form has been recorded on %s with the number %s.') % (tm, filled.id)
|
||||
"</p>"
|
||||
if self.formdef.receiver:
|
||||
"<p>"
|
||||
_('Your case will be handled by:')
|
||||
"</p>"
|
||||
'<p id="receiver">'
|
||||
htmltext(self.formdef.receiver.replace(str('\n'), str('<br />')))
|
||||
"</p>"
|
||||
|
||||
|
||||
"""<dl id="receipt">"""
|
||||
for f in self.formdef.fields:
|
||||
if filled.data.has_key(f['name']):
|
||||
"<dt>%s</dt>" % f['name']
|
||||
"<dd>%s</dd>" % filled.data[f['name']]
|
||||
"</dl>"
|
||||
'<a href="..">%s</a>' % _("Back Home")
|
||||
html_foot()
|
||||
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return FormStatusPage(self.formdef, component)
|
||||
|
||||
|
||||
class RootDirectory(Directory):
|
||||
|
||||
_q_exports = ["", "token"]
|
||||
|
||||
def _q_index [html] (self):
|
||||
html_top(_("Forms"))
|
||||
|
||||
session = get_session()
|
||||
if session and session.user and not session.user.startswith(str('anonymous-')):
|
||||
try:
|
||||
user = storage.get_storage().retrieve('users', session.user)
|
||||
"<p>%s</p>" % _('You are logged in as %s.') % user.name
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
user = None
|
||||
|
||||
|
||||
"<ul>"
|
||||
for k in storage.get_storage().keys(str('formdefs')):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
if formdef.roles:
|
||||
if not user:
|
||||
continue
|
||||
for q in user.roles or []:
|
||||
if q in formdef.roles:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
"""<li><a href="%s/">%s</a></li>""" % (k, formdef.name)
|
||||
"</ul>"
|
||||
|
||||
if session and session.user:
|
||||
l = []
|
||||
for k in storage.get_storage().keys('formdefs'):
|
||||
formdef = storage.get_storage().retrieve('formdefs', k)
|
||||
formnames = "form-" + formdef.id
|
||||
for q in storage.get_storage().keys(formnames):
|
||||
filled = storage.get_storage().retrieve(formnames, q)
|
||||
filled.formdef = formdef
|
||||
if filled.user_id == session.user:
|
||||
l.append(filled)
|
||||
if l:
|
||||
"""<h2 id="submitted">%s</h2>""" % _('Your Current Forms')
|
||||
"<ul>"
|
||||
l.sort(lambda x,y: -cmp(x.receipt_time, y.receipt_time))
|
||||
for f in l:
|
||||
"""<li><a href="%s/%s">%s</a>, %s</li>""" % (
|
||||
f.formdef.id, f.id, f.formdef.name,
|
||||
time.strftime(str("%Y-%m-%d %H:%M"), f.receipt_time))
|
||||
|
||||
"""<p id="logout">"""
|
||||
if session.user.startswith(str('anonymous-')):
|
||||
"""<a href="token">%s</a> - """ % _('Enter Identification Token')
|
||||
"""<a href="../logout">%s</a></p>""" % _('Logout')
|
||||
|
||||
elif wcs.misc.cfg.has_key('sp'):
|
||||
"""<p id="login"><a href="../login">%s</a></p>""" % _('Login')
|
||||
|
||||
html_foot()
|
||||
|
||||
def _q_lookup(self, component):
|
||||
return FormPage(component)
|
||||
|
||||
def token [html] (self):
|
||||
form = Form(enctype="multipart/form-data")
|
||||
form.add(StringWidget, "token", title = _('Identification Token'),
|
||||
required = True, size = 30)
|
||||
form.add_submit("cancel", _("Cancel"))
|
||||
form.add_submit("submit", _("Submit"))
|
||||
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
||||
if not form.is_submitted() or form.has_errors():
|
||||
html_top(_("Forms"))
|
||||
"<p>"
|
||||
_("Bla bla bla")
|
||||
"</p>"
|
||||
form.render()
|
||||
html_foot()
|
||||
else:
|
||||
token = form.get_widget('token').parse()
|
||||
for user in storage.get_storage().values('users'):
|
||||
if user.identification_token == token:
|
||||
user.identification_token = None
|
||||
user.name_identifiers = [str(get_session().name_identifier)]
|
||||
old_name = get_session().user
|
||||
get_session().set_user(user.id)
|
||||
storage.get_storage().store(user)
|
||||
|
||||
for formdef in storage.get_storage().values('formdefs'):
|
||||
formnames = "form-" + formdef.id
|
||||
for filled in storage.get_storage().values(formnames):
|
||||
if filled.user_id == old_name:
|
||||
filled.user_id = user.id
|
||||
storage.get_storage().store(filled)
|
||||
break
|
||||
return redirect('.')
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import os
|
||||
import urllib
|
||||
import urlparse
|
||||
import httplib
|
||||
|
||||
from quixote import get_request, get_response, redirect, get_field
|
||||
from quixote.directory import Directory
|
||||
from quixote.form import *
|
||||
from quixote.html import htmltext
|
||||
|
||||
from quixote.http_request import parse_header
|
||||
|
||||
from quixote import get_user, get_session, get_session_manager, get_field
|
||||
|
||||
import lasso
|
||||
|
||||
import wcs.misc
|
||||
from wcs import storage
|
||||
|
||||
class RootDirectory(Directory):
|
||||
_q_exports = ["", "login", "assertionConsumer"]
|
||||
|
||||
def login(self):
|
||||
server = wcs.misc.get_lasso_server()
|
||||
login = lasso.Login(server)
|
||||
idps = wcs.misc.cfg.get('idp', {}).values()
|
||||
if len(idps) > 1:
|
||||
# XXX: form to select idp
|
||||
pass
|
||||
login.initAuthnRequest(None, lasso.HTTP_METHOD_REDIRECT)
|
||||
login.request.nameIdPolicy = "federated"
|
||||
login.request.forceAuthn = False
|
||||
login.request.isPassive = False
|
||||
login.request.consent = "urn:liberty:consent:obtained"
|
||||
login.buildAuthnRequestMsg()
|
||||
return redirect(login.msgUrl)
|
||||
|
||||
def assertionConsumer(self):
|
||||
server = wcs.misc.get_lasso_server()
|
||||
login = lasso.Login(server)
|
||||
request = get_request()
|
||||
if request.get_method() == 'GET' or get_field('LAREQ'):
|
||||
if request.get_method() == 'GET':
|
||||
login.initRequest(request.get_query(), lasso.HTTP_METHOD_REDIRECT)
|
||||
else:
|
||||
login.initRequest(get_field('LAREQ'), lasso.HTTP_METHOD_POST)
|
||||
|
||||
login.buildRequestMsg()
|
||||
soap_answer = soap_call(login.msgUrl, login.msgBody)
|
||||
login.processResponseMsg(soap_answer)
|
||||
else:
|
||||
login.processAuthnResponseMsg(get_field('LARES'))
|
||||
login.acceptSso()
|
||||
session = get_session()
|
||||
ni = login.nameIdentifier.content
|
||||
for user in storage.get_storage().values('users'):
|
||||
if ni in user.name_identifiers:
|
||||
session.name_identifier = ni
|
||||
session.set_user(user.id)
|
||||
break
|
||||
else:
|
||||
session.name_identifier = ni
|
||||
session.set_user('anonymous-%s' % ni)
|
||||
response = get_response()
|
||||
response.set_status(303)
|
||||
response.headers['location'] = urlparse.urljoin(request.get_url(), str('..'))
|
||||
response.content_type = 'text/plain'
|
||||
return "Your browser should redirect you"
|
||||
|
||||
def soap_call(url, msg):
|
||||
if url.startswith('http://'):
|
||||
host, query = urllib.splithost(url[5:])
|
||||
conn = httplib.HTTPConnection(host)
|
||||
else:
|
||||
host, query = urllib.splithost(url[6:])
|
||||
conn = httplib.HTTPSConnection(host)
|
||||
conn.request("POST", query, msg, {'Content-Type': 'text/xml'})
|
||||
response = conn.getresponse()
|
||||
data = response.read()
|
||||
conn.close()
|
||||
if response.status not in (200, 204): # 204 ok for federation termination
|
||||
raise "SOAPError"
|
||||
return data
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import cPickle
|
||||
import re
|
||||
import lasso
|
||||
|
||||
import wcs
|
||||
|
||||
def get_lasso_server():
|
||||
reload_cfg()
|
||||
if not cfg.has_key('sp'):
|
||||
return None
|
||||
server = lasso.Server(
|
||||
cfg['sp']['metadata'],
|
||||
cfg['sp']['privatekey'],
|
||||
None, None)
|
||||
for idp in cfg.get('idp', {}).values():
|
||||
server.addProvider(
|
||||
lasso.PROVIDER_ROLE_IDP,
|
||||
idp['metadata'],
|
||||
idp['publickey'],
|
||||
None)
|
||||
return server
|
||||
|
||||
def write_cfg():
|
||||
s = cPickle.dumps(cfg)
|
||||
file(filename, 'w').write(s)
|
||||
|
||||
def reload_cfg():
|
||||
global cfg
|
||||
try:
|
||||
cfg = cPickle.load(file(filename))
|
||||
except:
|
||||
cfg = {}
|
||||
|
||||
def get_provider_label(provider):
|
||||
if not hasattr(provider, str('getOrganization')):
|
||||
return provider.providerId
|
||||
|
||||
organization = provider.getOrganization()
|
||||
if not organization:
|
||||
return provider.providerId
|
||||
|
||||
name = re.findall("<OrganizationDisplayName.*>(.*?)</OrganizationDisplayName>", organization)
|
||||
if not name:
|
||||
name = re.findall("<OrganizationName.*>(.*?)</OrganizationName>", organization)
|
||||
if not name:
|
||||
return provider.providerId
|
||||
return name[0]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
from quixote import get_request
|
||||
|
||||
import storage
|
||||
|
||||
class Role(storage.Storable):
|
||||
key = 'id'
|
||||
names = 'roles'
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import os
|
||||
import cPickle
|
||||
from quixote.session import Session, SessionManager
|
||||
import storage
|
||||
|
||||
class BasicSession(Session, storage.Storable):
|
||||
key = 'id'
|
||||
names = 'sessions'
|
||||
|
||||
def __init__(self, id):
|
||||
Session.__init__(self, id)
|
||||
self.name_identifier = None
|
||||
|
||||
def has_info(self):
|
||||
return self.name_identifier or Session.has_info(self)
|
||||
is_dirty = has_info
|
||||
|
||||
|
||||
class PickleSessionManager(SessionManager):
|
||||
def __init__(self):
|
||||
self.storage = storage.get_storage()
|
||||
SessionManager.__init__(self, session_class=BasicSession)
|
||||
|
||||
def forget_changes(self, session):
|
||||
pass
|
||||
|
||||
def __getitem__(self, session_id):
|
||||
try:
|
||||
return storage.get_storage().retrieve('sessions', session_id)
|
||||
except IOError:
|
||||
raise KeyError
|
||||
|
||||
def get(self, session_id, default = None):
|
||||
try:
|
||||
return storage.get_storage().retrieve('sessions', session_id)
|
||||
except KeyError:
|
||||
return default
|
||||
|
||||
def commit_changes(self, session):
|
||||
if session and session.id:
|
||||
storage.get_storage().store(session)
|
||||
|
||||
def keys(self):
|
||||
return storage.get_storage().keys('sessions')
|
||||
|
||||
def values(self):
|
||||
return [self.get(k) for k in self.keys()]
|
||||
|
||||
def items(self):
|
||||
return [(k, self.get(k)) for k in self.keys()]
|
||||
|
||||
def has_key(self, session_id):
|
||||
return session_id in self.keys()
|
||||
|
||||
def __setitem__(self, session_id, session):
|
||||
storage.get_storage().store(session)
|
||||
|
||||
def __delitem__(self, session_id):
|
||||
try:
|
||||
storage.get_storage().remove_id('sessions', session_id)
|
||||
except OSError:
|
||||
raise KeyError
|
|
@ -0,0 +1,81 @@
|
|||
import os
|
||||
import cPickle
|
||||
|
||||
class Storage:
|
||||
pass
|
||||
|
||||
|
||||
class Storable:
|
||||
def get_table_name(self):
|
||||
if hasattr(self, 'names'):
|
||||
return self.names
|
||||
return self.__class__.__name__.lower()
|
||||
|
||||
def fixkey(k):
|
||||
# insure key can be inserted in filesystem
|
||||
if not k: return k
|
||||
return str(k).replace('/', '-')
|
||||
|
||||
class FilesStorage:
|
||||
BASEDIR = None # must be initialized
|
||||
|
||||
def __init__(self):
|
||||
if self.BASEDIR and not os.path.exists(self.BASEDIR):
|
||||
os.mkdir(self.BASEDIR)
|
||||
|
||||
def keys(self, obname):
|
||||
dirname = os.path.join(self.BASEDIR, str(obname))
|
||||
if not os.path.exists(dirname):
|
||||
return []
|
||||
return os.listdir(dirname)
|
||||
|
||||
def store(self, object):
|
||||
obname = object.get_table_name()
|
||||
dirname = os.path.join(self.BASEDIR, obname)
|
||||
if not os.path.exists(dirname):
|
||||
os.mkdir(dirname)
|
||||
if not getattr(object, object.key):
|
||||
keys = self.keys(obname)
|
||||
key = len(keys) + 1
|
||||
while str(key) in keys:
|
||||
key += 1
|
||||
key = str(key)
|
||||
setattr(object, object.key, key)
|
||||
s = cPickle.dumps(object)
|
||||
file(os.path.join(dirname, fixkey(getattr(object, object.key))), 'w').write(s)
|
||||
|
||||
def retrieve(self, obname, key):
|
||||
if key is None:
|
||||
raise KeyError()
|
||||
dirname = os.path.join(self.BASEDIR, str(obname))
|
||||
try:
|
||||
return cPickle.load(open(os.path.join(dirname, fixkey(key))))
|
||||
except IOError:
|
||||
raise KeyError()
|
||||
|
||||
def values(self, obname):
|
||||
return [self.retrieve(obname, k) for k in self.keys(obname)]
|
||||
|
||||
def items(self, obname):
|
||||
return [(k, self.retrieve(obname, k)) for k in self.keys(obname)]
|
||||
|
||||
def remove(self, object = None):
|
||||
obname = object.get_table_name()
|
||||
return self.remove_id(obname, fixkey(getattr(object, object.key)))
|
||||
|
||||
def remove_id(self, obname, key):
|
||||
dirname = os.path.join(self.BASEDIR, str(obname))
|
||||
os.unlink(os.path.join(dirname, fixkey(key)))
|
||||
|
||||
def remove_all(self, obname):
|
||||
dirname = os.path.join(self.BASEDIR, str(obname))
|
||||
if not os.path.exists(dirname):
|
||||
return
|
||||
for k in os.listdir(dirname):
|
||||
os.unlink(os.path.join(dirname, k))
|
||||
os.rmdir(dirname)
|
||||
|
||||
|
||||
def get_storage():
|
||||
return FilesStorage()
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import storage
|
||||
|
||||
class User(storage.Storable):
|
||||
key = 'id'
|
||||
names = 'users'
|
||||
|
||||
def __init__(self):
|
||||
self.id = ''
|
||||
self.name = ''
|
||||
self.email = ''
|
||||
self.roles = []
|
||||
self.name_identifiers = []
|
||||
self.identification_token = None
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
from quixote.server.scgi_server import run
|
||||
import wcs
|
||||
|
||||
run(wcs.create_publisher, port=3001, script_name = '')
|
Loading…
Reference in New Issue