1
0
Fork 0

Code style changes

* make code PEP8 clean (addresses #18)
 * add copyright information to all python files


git-svn-id: file:///home/www/usr01/svn/gnuviechadmin/trunk@257 a67ec6bc-e5d5-0310-a910-815c51eb3124
This commit is contained in:
Jan Dittberner 2008-06-06 19:20:18 +00:00
parent 7c4d25da43
commit 09180938f1
45 changed files with 759 additions and 514 deletions

View File

@ -1,7 +1,8 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: UTF-8 -*- # -*- python -*-
# -*- coding: utf-8 -*-
# #
# Copyright (C) 2007 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

View File

@ -18,8 +18,7 @@ client = Table(
Column('mobile', String(32)), Column('mobile', String(32)),
Column('fax', String(32)), Column('fax', String(32)),
Column('email', String(64), unique=True, nullable=False), Column('email', String(64), unique=True, nullable=False),
schema = dbschema schema = dbschema)
)
sysuser = Table( sysuser = Table(
'sysuser', meta, 'sysuser', meta,
Column('sysuserid', Integer, primary_key=True), Column('sysuserid', Integer, primary_key=True),
@ -33,8 +32,7 @@ sysuser = Table(
nullable=False), nullable=False),
Column('sysuid', Integer, nullable=False, unique=True), Column('sysuid', Integer, nullable=False, unique=True),
Column('lastchange', DateTime, default=func.now()), Column('lastchange', DateTime, default=func.now()),
schema = dbschema schema = dbschema)
)
domain = Table( domain = Table(
'domain', meta, 'domain', meta,
Column('domainid', Integer, primary_key=True), Column('domainid', Integer, primary_key=True),
@ -45,8 +43,7 @@ domain = Table(
Column('notified_serial', Integer), Column('notified_serial', Integer),
Column('sysuserid', Integer, ForeignKey(sysuser.c.sysuserid), Column('sysuserid', Integer, ForeignKey(sysuser.c.sysuserid),
nullable=False), nullable=False),
schema = dbschema schema = dbschema)
)
record = Table( record = Table(
'record', meta, 'record', meta,
Column('recordid', Integer, primary_key=True), Column('recordid', Integer, primary_key=True),
@ -58,16 +55,15 @@ record = Table(
Column('ttl', Integer), Column('ttl', Integer),
Column('prio', Integer), Column('prio', Integer),
Column('change_date', Integer), Column('change_date', Integer),
schema = dbschema schema = dbschema)
)
supermaster = Table( supermaster = Table(
'supermaster', meta, 'supermaster', meta,
Column('ip', String(25), nullable=False), Column('ip', String(25), nullable=False),
Column('nameserver', String(255), nullable=False), Column('nameserver', String(255), nullable=False),
Column('account', Integer, ForeignKey(sysuser.c.sysuserid), Column('account', Integer, ForeignKey(sysuser.c.sysuserid),
nullable=False), nullable=False),
schema = dbschema schema = dbschema)
)
def upgrade(): def upgrade():
client.create() client.create()
@ -76,6 +72,7 @@ def upgrade():
record.create() record.create()
supermaster.create() supermaster.create()
def downgrade(): def downgrade():
supermaster.drop() supermaster.drop()
record.drop() record.drop()

View File

@ -17,8 +17,7 @@ mailaccount = Table(
Column('home', String(128), nullable = False), Column('home', String(128), nullable = False),
Column('spamcheck', Boolean, nullable = False, default = False), Column('spamcheck', Boolean, nullable = False, default = False),
Column('sajunkscore', Integer), Column('sajunkscore', Integer),
schema = dbschema schema = dbschema)
)
mailaddress = Table( mailaddress = Table(
'mailaddress', meta, 'mailaddress', meta,
Column('mailaddressid', Integer, primary_key = True), Column('mailaddressid', Integer, primary_key = True),
@ -26,8 +25,7 @@ mailaddress = Table(
nullable = False), nullable = False),
Column('email', String(255), nullable = False), Column('email', String(255), nullable = False),
UniqueConstraint('email', 'domainid'), UniqueConstraint('email', 'domainid'),
schema = dbschema schema = dbschema)
)
mailtarget = Table( mailtarget = Table(
'mailtarget', meta, 'mailtarget', meta,
Column('mailtargetid', Integer, primary_key = True), Column('mailtargetid', Integer, primary_key = True),
@ -35,14 +33,15 @@ mailtarget = Table(
nullable = False), nullable = False),
Column('target', String(128), nullable = False), Column('target', String(128), nullable = False),
UniqueConstraint('target', 'mailaddressid'), UniqueConstraint('target', 'mailaddressid'),
schema = dbschema schema = dbschema)
)
def upgrade(): def upgrade():
mailaccount.create() mailaccount.create()
mailaddress.create() mailaddress.create()
mailtarget.create() mailtarget.create()
def downgrade(): def downgrade():
mailtarget.drop() mailtarget.drop()
mailaddress.drop() mailaddress.drop()

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -20,7 +19,9 @@
# #
# Version: $Id$ # Version: $Id$
import os, logging, tempfile import os
import logging
import tempfile
from settings import config from settings import config
from gnuviechadmin.exceptions import * from gnuviechadmin.exceptions import *
@ -29,6 +30,7 @@ from subprocess import *
import sqlalchemy import sqlalchemy
from sqlalchemy.orm import object_mapper from sqlalchemy.orm import object_mapper
class BackendEntity(object): class BackendEntity(object):
"""This is the abstract base class for all backend entity classes.""" """This is the abstract base class for all backend entity classes."""
@ -75,10 +77,10 @@ class BackendEntity(object):
for cmdline in cmdlines: for cmdline in cmdlines:
toexec = "%s %s" % (suwrapper, cmdline) toexec = "%s %s" % (suwrapper, cmdline)
if predecessor is None: if predecessor is None:
p = Popen(toexec, shell = True, stdout = PIPE) p = Popen(toexec, shell = True, stdout = PIPE)
else: else:
p = Popen(toexec, shell = True, stdin = predecessor.stdout, p = Popen(toexec, shell = True, stdin = predecessor.stdout,
stdout = PIPE) stdout = PIPE)
predecessor = p predecessor = p
output = predecessor.communicate()[0] output = predecessor.communicate()[0]
return predecessor.wait() return predecessor.wait()
@ -110,4 +112,3 @@ class BackendEntity(object):
cmd = 'cp "%s" "%s"' % (tmp.name, filename) cmd = 'cp "%s" "%s"' % (tmp.name, filename)
self.sucommand(cmd) self.sucommand(cmd)
tmp.close() tmp.close()

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -20,12 +19,15 @@
# #
# Version: $Id$ # Version: $Id$
import sqlalchemy, logging import sqlalchemy
import logging
from sqlalchemy.orm import create_session from sqlalchemy.orm import create_session
from gnuviechadmin.exceptions import * from gnuviechadmin.exceptions import *
from BackendEntity import * from BackendEntity import *
class BackendEntityHandler(object): class BackendEntityHandler(object):
def __init__(self, entityclass, toclass, verbose = False): def __init__(self, entityclass, toclass, verbose = False):
self.logger = logging.getLogger("%s.%s" % ( self.logger = logging.getLogger("%s.%s" % (
self.__class__.__module__, self.__class__.__name__)) self.__class__.__module__, self.__class__.__name__))
@ -40,7 +42,7 @@ class BackendEntityHandler(object):
sess = create_session() sess = create_session()
transaction = sess.create_transaction() transaction = sess.create_transaction()
delegate = self.toclass(**kwargs) delegate = self.toclass(**kwargs)
entity = self.entityclass(delegate, self.verbose) entity = self.entityclass(delegate, self.verbose)
try: try:
sess.save(delegate) sess.save(delegate)
sess.flush() sess.flush()

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -21,11 +20,12 @@
# Version: $Id$ # Version: $Id$
from sqlalchemy.orm import object_mapper, mapper, relation from sqlalchemy.orm import object_mapper, mapper, relation
from tables import * from tables import *
class BackendTo(object): class BackendTo(object):
"""Backend transfer object class.""" """Backend transfer object class."""
def __init__(self, **kwargs): def __init__(self, **kwargs):
for (key, value) in kwargs.items(): for (key, value) in kwargs.items():
self.__setattr__(key, value) self.__setattr__(key, value)
@ -37,7 +37,7 @@ class BackendTo(object):
format = "%(class)s:" format = "%(class)s:"
format = format + ", ".join([col + "=%(" + col + ")s" for col in \ format = format + ", ".join([col + "=%(" + col + ")s" for col in \
cols]) cols])
data = {'class' : self.__class__.__name__} data = {'class': self.__class__.__name__}
else: else:
cols = self._shortkeys cols = self._shortkeys
format = ",".join("%(" + col + ")s" for col in cols) format = ",".join("%(" + col + ")s" for col in cols)
@ -45,30 +45,31 @@ class BackendTo(object):
data.update(dict([(col, self.__getattribute__(col)) for col in cols])) data.update(dict([(col, self.__getattribute__(col)) for col in cols]))
return format % data return format % data
class Client(BackendTo): class Client(BackendTo):
"""Transfer object class for clients.""" """Transfer object class for clients."""
_shortkeys = ('clientid', 'firstname', 'lastname', 'email') _shortkeys = ('clientid', 'firstname', 'lastname', 'email')
class Sysuser(BackendTo): class Sysuser(BackendTo):
"""Transfer object class for system users.""" """Transfer object class for system users."""
_shortkeys = ("sysuserid", "clientid", "username", "home", "shell") _shortkeys = ("sysuserid", "clientid", "username", "home", "shell")
class Domain(BackendTo): class Domain(BackendTo):
"""Transfer object class for DNS domains.""" """Transfer object class for DNS domains."""
_shortkeys = ("domainid", "sysuserid", "name", "type") _shortkeys = ("domainid", "sysuserid", "name", "type")
class Record(BackendTo): class Record(BackendTo):
"""Transfer object class for DNS domain records.""" """Transfer object class for DNS domain records."""
_shortkeys = ("recordid", "domainid", "name", "type", "content") _shortkeys = ("recordid", "domainid", "name", "type", "content")
client_mapper = mapper(Client, client_table)
sysuser_mapper = mapper(Sysuser, sysuser_table) client_mapper = mapper(Client, client_table, {
domain_mapper = mapper(Domain, domain_table) 'sysusers': relation(Sysuser, backref = 'client')})
sysuser_mapper = mapper(Sysuser, sysuser_table, {
'domains': relation(Domain, backref = 'sysuser')})
domain_mapper = mapper(Domain, domain_table, {
'records': relation(Record, cascade = 'all', backref = 'domain')})
record_mapper = mapper(Record, record_table) record_mapper = mapper(Record, record_table)
client_mapper.add_property("sysusers", relation(Sysuser, backref = 'client'))
sysuser_mapper.add_property("domains", relation(Domain, backref = 'sysuser'))
domain_mapper.add_property("records", relation(Record, cascade = 'all',
backref = 'domain'))

View File

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -25,6 +25,7 @@ from BackendTo import *
from BackendEntity import * from BackendEntity import *
from BackendEntityHandler import * from BackendEntityHandler import *
class ClientEntity(BackendEntity): class ClientEntity(BackendEntity):
"""Entity class for clients.""" """Entity class for clients."""
@ -39,18 +40,18 @@ class ClientEntity(BackendEntity):
def _client_mail(self): def _client_mail(self):
text = get_template(config.get('common', 'mailtemplates'), text = get_template(config.get('common', 'mailtemplates'),
config.get('client', 'create.mail')).substitute({ config.get('client', 'create.mail')).substitute({
'firstname' : self.delegateto.firstname, 'firstname': self.delegateto.firstname,
'lastname' : self.delegateto.lastname, 'lastname': self.delegateto.lastname,
'email' : self.delegateto.email, 'email': self.delegateto.email,
'address1' : self.delegateto.address1, 'address1': self.delegateto.address1,
'zipcode' : self.delegateto.zip, 'zipcode': self.delegateto.zip,
'city' : self.delegateto.city, 'city': self.delegateto.city,
'phone' : self.delegateto.phone}) 'phone': self.delegateto.phone})
subject = get_template_string( subject = get_template_string(
config.get('client', 'create_subject')).substitute({ config.get('client', 'create_subject')).substitute({
'firstname' : self.delegateto.firstname, 'firstname': self.delegateto.firstname,
'lastname' : self.delegateto.lastname}) 'lastname': self.delegateto.lastname})
self.send_mail(subject, text) self.send_mail(subject, text)
def create_hook(self, session): def create_hook(self, session):
"""Actions to perform when a client is created.""" """Actions to perform when a client is created."""
@ -69,6 +70,7 @@ class ClientEntity(BackendEntity):
"""Gets the default country.""" """Gets the default country."""
return config.get('common', 'defaultcountry') return config.get('common', 'defaultcountry')
class ClientHandler(BackendEntityHandler): class ClientHandler(BackendEntityHandler):
"""BackendEntityHandler for Client entities.""" """BackendEntityHandler for Client entities."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -18,9 +17,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA. # USA.
# #
# Version: $Id: client.py 1101 2007-02-28 21:15:20Z jan $ # Version: $Id$
import datetime, os import datetime
import os
from gnuviechadmin.exceptions import * from gnuviechadmin.exceptions import *
from settings import * from settings import *
@ -28,6 +28,7 @@ from BackendTo import Record, Domain
from BackendEntity import BackendEntity from BackendEntity import BackendEntity
from BackendEntityHandler import BackendEntityHandler from BackendEntityHandler import BackendEntityHandler
class DomainEntity(BackendEntity): class DomainEntity(BackendEntity):
"""Entity class for DNS domains.""" """Entity class for DNS domains."""
@ -130,12 +131,12 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('domain', 'htdocstemplate'), template = get_template(config.get('domain', 'htdocstemplate'),
tpl) tpl)
template = template.substitute({ template = template.substitute({
'domain' : self.delegateto.name}) 'domain': self.delegateto.name})
self.write_to_file(os.path.join(vhostdir, tpl), template) self.write_to_file(os.path.join(vhostdir, tpl), template)
cmd = 'chown -R %(username)s:%(group)s "%(dir)s"' % { cmd = 'chown -R %(username)s:%(group)s "%(dir)s"' % {
'username' : self.delegateto.sysuser.username, 'username': self.delegateto.sysuser.username,
'group' : config.get('sysuser', 'defaultgroup'), 'group': config.get('sysuser', 'defaultgroup'),
'dir' : vhostdir} 'dir': vhostdir}
self.sucommand(cmd) self.sucommand(cmd)
def _create_log_dir(self): def _create_log_dir(self):
@ -164,8 +165,8 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('domain', 'conftemplates'), template = get_template(config.get('domain', 'conftemplates'),
config.get('domain', 'statshtaccesstemplate')) config.get('domain', 'statshtaccesstemplate'))
template = template.substitute({ template = template.substitute({
'domain' : self.delegateto.name, 'domain': self.delegateto.name,
'userfile' : authfile}) 'userfile': authfile})
self.write_to_file(os.path.join(self._get_stats_dir(), self.write_to_file(os.path.join(self._get_stats_dir(),
'.htaccess'), template) '.htaccess'), template)
@ -178,10 +179,10 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('domain', 'conftemplates'), template = get_template(config.get('domain', 'conftemplates'),
config.get('domain', 'modlogantemplate')) config.get('domain', 'modlogantemplate'))
template = template.substitute({ template = template.substitute({
'statsdir' : self._get_stats_dir(), 'statsdir': self._get_stats_dir(),
'logdir' : self._get_log_dir(), 'logdir': self._get_log_dir(),
'domain' : self.delegateto.name, 'domain': self.delegateto.name,
'domainesc' : self.delegateto.name.replace('.', '\.')}) 'domainesc': self.delegateto.name.replace('.', '\.')})
self.write_to_file(os.path.join(modlogandir, self.write_to_file(os.path.join(modlogandir,
self.delegateto.name + '.conf'), self.delegateto.name + '.conf'),
template) template)
@ -190,11 +191,11 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('domain', 'conftemplates'), template = get_template(config.get('domain', 'conftemplates'),
config.get('domain', 'apachetemplate')) config.get('domain', 'apachetemplate'))
template = template.substitute({ template = template.substitute({
'ipaddr' : self.ipaddr, 'ipaddr': self.ipaddr,
'statsdir' : self._get_stats_dir(), 'statsdir': self._get_stats_dir(),
'logdir' : self._get_log_dir(), 'logdir': self._get_log_dir(),
'domain' : self.delegateto.name, 'domain': self.delegateto.name,
'docroot' : self._get_vhost_dir()}) 'docroot': self._get_vhost_dir()})
self.write_to_file(os.path.join(config.get('domain', 'sitesdir'), self.write_to_file(os.path.join(config.get('domain', 'sitesdir'),
self.delegateto.name), template) self.delegateto.name), template)
@ -202,14 +203,14 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('common', 'mailtemplates'), template = get_template(config.get('common', 'mailtemplates'),
config.get('domain', 'create.mail')) config.get('domain', 'create.mail'))
text = template.substitute({ text = template.substitute({
'sysuser' : self.delegateto.sysuser.username, 'sysuser': self.delegateto.sysuser.username,
'domain' : self.delegateto.name, 'domain': self.delegateto.name,
'docroot' : self._get_vhost_dir(), 'docroot': self._get_vhost_dir(),
'statspass' : self.delegateto.sysuser.clearpass}) 'statspass': self.delegateto.sysuser.clearpass})
template = get_template_string(config.get('domain', 'create_subject')) template = get_template_string(config.get('domain', 'create_subject'))
subject = template.substitute({ subject = template.substitute({
'domain' : self.delegateto.name}) 'domain': self.delegateto.name})
self.send_mail(subject, text) self.send_mail(subject, text)
def create_hook(self, session): def create_hook(self, session):
self.delegateto.records.append(Record( self.delegateto.records.append(Record(
@ -223,7 +224,7 @@ class DomainEntity(BackendEntity):
name = self.delegateto.name, type = 'NS', content = self.ns2, name = self.delegateto.name, type = 'NS', content = self.ns2,
ttl = config.getint('domain', 'defaultttl'))) ttl = config.getint('domain', 'defaultttl')))
self.delegateto.records.append(Record( self.delegateto.records.append(Record(
name = self.delegateto.name, type = 'MX', content = self.mx, name = self.delegateto.name, type = 'MX', content = self.mx,
ttl = config.getint('domain', 'defaultttl'), ttl = config.getint('domain', 'defaultttl'),
prio = config.getint('domain', 'defaultmxprio'))) prio = config.getint('domain', 'defaultmxprio')))
self.delegateto.records.append(Record( self.delegateto.records.append(Record(
@ -258,65 +259,69 @@ class DomainEntity(BackendEntity):
def _archive_stats_dir(self): def _archive_stats_dir(self):
archive = os.path.join(self.delegateto.sysuser.home, archive = os.path.join(self.delegateto.sysuser.home,
'%(domain)s-stats.tar.gz' % { '%(domain)s-stats.tar.gz' % {
'domain' : self.delegateto.name}) 'domain': self.delegateto.name})
cmd = 'tar czf "%(archive)s" --directory="%(statsbase)s" "%(statsdir)s"' % { cmd = 'tar czf "%(archive)s" --directory="%(statsbase)s" ' + \
'archive' : archive, '"%(statsdir)s"' % {
'statsbase' : config.get('domain', 'statspath'), 'archive': archive,
'statsdir' : self.delegateto.name} 'statsbase': config.get('domain', 'statspath'),
'statsdir': self.delegateto.name}
self.sucommand(cmd) self.sucommand(cmd)
cmd = 'rm -r "%(statsdir)s"' % { cmd = 'rm -r "%(statsdir)s"' % {
'statsdir' : self._get_stats_dir()} 'statsdir': self._get_stats_dir()}
self.sucommand(cmd) self.sucommand(cmd)
cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % { cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % {
'username' : self.delegateto.sysuser.username, 'username': self.delegateto.sysuser.username,
'group' : config.get('sysuser', 'defaultgroup'), 'group': config.get('sysuser', 'defaultgroup'),
'archive' : archive} 'archive': archive}
self.sucommand(cmd) self.sucommand(cmd)
def _archive_log_dir(self): def _archive_log_dir(self):
archive = os.path.join(self.delegateto.sysuser.home, archive = os.path.join(self.delegateto.sysuser.home,
'%(domain)s-logs.tar.gz' % { '%(domain)s-logs.tar.gz' % {
'domain' : self.delegateto.name}) 'domain': self.delegateto.name})
cmd = 'tar czf "%(archive)s" --directory="%(logbase)s" "%(logdir)s"' % { cmd = 'tar czf "%(archive)s" --directory="%(logbase)s" ' + \
'archive' : archive, '"%(logdir)s"' % {
'logbase' : config.get('domain', 'logpath'), 'archive': archive,
'logdir' : self.delegateto.name} 'logbase': config.get('domain', 'logpath'),
'logdir': self.delegateto.name}
self.sucommand(cmd) self.sucommand(cmd)
cmd = 'rm -r "%(logdir)s"' % { cmd = 'rm -r "%(logdir)s"' % {
'logdir' : self._get_log_dir()} 'logdir': self._get_log_dir()}
self.sucommand(cmd) self.sucommand(cmd)
cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % { cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % {
'username' : self.delegateto.sysuser.username, 'username': self.delegateto.sysuser.username,
'group' : config.get('sysuser', 'defaultgroup'), 'group': config.get('sysuser', 'defaultgroup'),
'archive' : archive} 'archive': archive}
self.sucommand(cmd) self.sucommand(cmd)
def _archive_vhost_dir(self): def _archive_vhost_dir(self):
archive = os.path.join(self.delegateto.sysuser.home, archive = os.path.join(self.delegateto.sysuser.home,
'%(domain)s-vhost.tar.gz' % { '%(domain)s-vhost.tar.gz' % {
'domain' : self.delegateto.name}) 'domain': self.delegateto.name})
cmd = 'tar czf "%(archive)s" --directory="%(vhostbase)s" "%(vhostdir)s"' % { cmd = 'tar czf "%(archive)s" --directory="%(vhostbase)s" ' + \
'archive' : archive, '"%(vhostdir)s"' % {
'vhostbase' : self.delegateto.sysuser.home, 'archive': archive,
'vhostdir' : self.delegateto.name} 'vhostbase': self.delegateto.sysuser.home,
'vhostdir': self.delegateto.name}
self.sucommand(cmd) self.sucommand(cmd)
cmd = 'rm -r "%(vhostdir)s"' % { cmd = 'rm -r "%(vhostdir)s"' % {
'vhostdir' : os.path.join(self.delegateto.sysuser.home, 'vhostdir': os.path.join(self.delegateto.sysuser.home,
self.delegateto.name)} self.delegateto.name)}
self.sucommand(cmd) self.sucommand(cmd)
cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % { cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % {
'username' : self.delegateto.sysuser.username, 'username': self.delegateto.sysuser.username,
'group' : config.get('sysuser', 'defaultgroup'), 'group': config.get('sysuser', 'defaultgroup'),
'archive' : archive} 'archive': archive}
self.sucommand(cmd) self.sucommand(cmd)
def delete_hook(self, session): def delete_hook(self, session):
self._delete_apache_conf() self._delete_apache_conf()
self._delete_stats_conf() self._delete_stats_conf()
self._archive_stats_dir() self._archive_stats_dir()
self._archive_log_dir() self._archive_log_dir()
self._archive_vhost_dir() self._archive_vhost_dir()
class DomainHandler(BackendEntityHandler): class DomainHandler(BackendEntityHandler):
"""BackendEntityHandler for Domain entities.""" """BackendEntityHandler for Domain entities."""

View File

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -25,16 +25,19 @@ from domain import DomainEntity
from BackendEntity import * from BackendEntity import *
from BackendEntityHandler import * from BackendEntityHandler import *
class RecordEntity(BackendEntity): class RecordEntity(BackendEntity):
"""Entity class for DNS domain records.""" """Entity class for DNS domain records."""
def create_hook(self, session): def create_hook(self, session):
domain = session.load(Domain, self.delegateto.domainid) domain = session.load(Domain, self.delegateto.domainid)
DomainEntity(domain).update_serial(session) DomainEntity(domain).update_serial(session)
def delete_hook(self, session): def delete_hook(self, session):
domain = session.load(Domain, self.delegateto.domainid) domain = session.load(Domain, self.delegateto.domainid)
DomainEntity(domain).update_serial(session) DomainEntity(domain).update_serial(session)
class RecordHandler(BackendEntityHandler): class RecordHandler(BackendEntityHandler):
"""BackendEntityHandler for Record entities.""" """BackendEntityHandler for Record entities."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -26,7 +25,10 @@ This module handles all central configuration of Gnuviech Admin. It
parses configuration files and provides functions for reading parses configuration files and provides functions for reading
templates.""" templates."""
import ConfigParser, os, string, logging.config import ConfigParser
import os
import string
import logging.config
# global settings which must not be user configurable # global settings which must not be user configurable
required_version = 3 required_version = 3
@ -40,11 +42,13 @@ dbschema = None
if config.get('database', 'uri').startswith('postgres://'): if config.get('database', 'uri').startswith('postgres://'):
dbschema = 'gva' dbschema = 'gva'
def get_template_dir(dirname): def get_template_dir(dirname):
"""Returns the template directory for the given directory.""" """Returns the template directory for the given directory."""
templatepath = config.get('common', 'templatedir') templatepath = config.get('common', 'templatedir')
return os.path.join(templatepath, dirname) return os.path.join(templatepath, dirname)
def get_template(dirname, filename): def get_template(dirname, filename):
"""Returns the template data from the given template file.""" """Returns the template data from the given template file."""
templatefile = file(os.path.join(get_template_dir(dirname), templatefile = file(os.path.join(get_template_dir(dirname),
@ -52,6 +56,7 @@ def get_template(dirname, filename):
templatedata = templatefile.read() templatedata = templatefile.read()
return string.Template(templatedata.decode('utf_8')) return string.Template(templatedata.decode('utf_8'))
def get_template_string(templatestring): def get_template_string(templatestring):
"""Returns a template object for the given template string.""" """Returns a template object for the given template string."""
return string.Template(templatestring) return string.Template(templatestring)

View File

@ -27,6 +27,7 @@ from BackendEntity import *
from BackendEntityHandler import * from BackendEntityHandler import *
import os import os
class SysuserEntity(BackendEntity): class SysuserEntity(BackendEntity):
"""Entity class for system users.""" """Entity class for system users."""
@ -54,7 +55,8 @@ class SysuserEntity(BackendEntity):
usernames = [user.username for user in \ usernames = [user.username for user in \
getenttools.find_user_by_prefix(prefix)] getenttools.find_user_by_prefix(prefix)]
if usernames: if usernames:
maxid = max([int(username[len(prefix):]) for username in usernames]) maxid = max([int(username[len(prefix):]) \
for username in usernames])
maxid += 2 maxid += 2
for number in range(1, maxid): for number in range(1, maxid):
username = "%s%02d" % (prefix, number) username = "%s%02d" % (prefix, number)
@ -81,17 +83,18 @@ class SysuserEntity(BackendEntity):
def _get_next_sysuid(self): def _get_next_sysuid(self):
return getenttools.get_next_uid(int(config.get('sysuser', 'minuid')), return getenttools.get_next_uid(int(config.get('sysuser', 'minuid')),
int(config.get('sysuser', 'maxuid'))) int(config.get('sysuser', 'maxuid')))
def _populate_home(self): def _populate_home(self):
templatedir = get_template_dir(config.get('sysuser', 'hometemplate')) templatedir = get_template_dir(config.get('sysuser', 'hometemplate'))
olddir = os.getcwd() olddir = os.getcwd()
os.chdir(templatedir) os.chdir(templatedir)
cmd1 = 'find . -depth \! -regex ".*\.svn.*" \! -name "*~" -print0' cmd1 = 'find . -depth \! -regex ".*\.svn.*" \! -name "*~" -print0'
cmd2 = 'cpio --pass-through --owner=%(username)s.%(group)s --null --make-directories %(home)s' % { cmd2 = 'cpio --pass-through --owner=%(username)s.%(group)s --null ' + \
'username' : self.delegateto.username, '--make-directories %(home)s' % {
'group' : config.get('sysuser', 'defaultgroup'), 'username': self.delegateto.username,
'home' : self.delegateto.home} 'group': config.get('sysuser', 'defaultgroup'),
'home': self.delegateto.home}
self.supipe((cmd1, cmd2)) self.supipe((cmd1, cmd2))
os.chdir(olddir) os.chdir(olddir)
@ -99,33 +102,35 @@ class SysuserEntity(BackendEntity):
template = get_template(config.get('common', 'mailtemplates'), template = get_template(config.get('common', 'mailtemplates'),
config.get('sysuser', 'create.mail')) config.get('sysuser', 'create.mail'))
text = template.substitute({ text = template.substitute({
'uid' : self.delegateto.sysuid, 'uid': self.delegateto.sysuid,
'firstname' : self.delegateto.client.firstname, 'firstname': self.delegateto.client.firstname,
'lastname' : self.delegateto.client.lastname, 'lastname': self.delegateto.client.lastname,
'email' : self.delegateto.client.email, 'email': self.delegateto.client.email,
'username' : self.delegateto.username, 'username': self.delegateto.username,
'password' : self.delegateto.clearpass, 'password': self.delegateto.clearpass,
'home' : self.delegateto.home, 'home': self.delegateto.home,
'shell' : self._get_shell_binary()}) 'shell': self._get_shell_binary()})
template = get_template_string(config.get('sysuser', 'create_subject')) template = get_template_string(config.get('sysuser', 'create_subject'))
subject = template.substitute({ subject = template.substitute({
'username' : self.delegateto.username}) 'username': self.delegateto.username})
self.send_mail(subject, text) self.send_mail(subject, text)
def create_hook(self, session): def create_hook(self, session):
gecos = config.get('sysuser', 'gecos') % (self.delegateto.username) gecos = config.get('sysuser', 'gecos') % (self.delegateto.username)
cmdline = 'adduser --home "%(home)s" --shell "%(shell)s" --no-create-home --uid %(sysuid)d --ingroup "%(group)s" --disabled-password --gecos "%(gecos)s" %(username)s' % { cmdline = 'adduser --home "%(home)s" --shell "%(shell)s" ' + \
'home' : self.delegateto.home, '--no-create-home --uid %(sysuid)d --ingroup "%(group)s" ' + \
'shell' : self._get_shell_binary(), '--disabled-password --gecos "%(gecos)s" %(username)s' % {
'sysuid' : self.delegateto.sysuid, 'home': self.delegateto.home,
'group' : config.get('sysuser', 'defaultgroup'), 'shell': self._get_shell_binary(),
'gecos' : gecos, 'sysuid': self.delegateto.sysuid,
'username' : self.delegateto.username} 'group': config.get('sysuser', 'defaultgroup'),
'gecos': gecos,
'username': self.delegateto.username}
self.sucommand(cmdline) self.sucommand(cmdline)
cmdline = 'chpasswd --encrypted' cmdline = 'chpasswd --encrypted'
inline = '%(username)s:%(md5pass)s' % { inline = '%(username)s:%(md5pass)s' % {
'username' : self.delegateto.username, 'username': self.delegateto.username,
'md5pass' : self.delegateto.md5pass} 'md5pass': self.delegateto.md5pass}
self.sucommand(cmdline, inline) self.sucommand(cmdline, inline)
self._populate_home() self._populate_home()
self._mail_sysuser() self._mail_sysuser()
@ -141,15 +146,17 @@ class SysuserEntity(BackendEntity):
config.get('sysuser', 'homebackupdir')) config.get('sysuser', 'homebackupdir'))
if not os.path.isdir(backupdir): if not os.path.isdir(backupdir):
cmdline = 'mkdir -p "%(backupdir)s"' % { cmdline = 'mkdir -p "%(backupdir)s"' % {
'backupdir' : backupdir} 'backupdir': backupdir}
status = self.sucommand(cmdline) status = self.sucommand(cmdline)
if status != 0: if status != 0:
raise Exception("could not create backup directory") raise Exception("could not create backup directory")
cmdline = 'deluser --remove-home --backup --backup-to "%(backupdir)s" %(username)s' % { cmdline = 'deluser --remove-home --backup --backup-to ' + \
'backupdir' : backupdir, ' "%(backupdir)s" %(username)s' % {
'username' : self.delegateto.username} 'backupdir': backupdir,
'username': self.delegateto.username}
self.sucommand(cmdline) self.sucommand(cmdline)
class SysuserHandler(BackendEntityHandler): class SysuserHandler(BackendEntityHandler):
"""BackendEntityHandler for Sysuser entities.""" """BackendEntityHandler for Sysuser entities."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -31,7 +30,8 @@ try:
config.get('database', 'uri'), config.get('database', 'uri'),
config.get('database', 'repository')) config.get('database', 'repository'))
if dbversion < required_version: if dbversion < required_version:
print("""Database version is %d but required version is %d. Trying automatic upgrade.""" % print("""Database version is %d but required version is %d. Trying
automatic upgrade.""" %
(dbversion, required_version)) (dbversion, required_version))
try: try:
migrate.versioning.api.upgrade( migrate.versioning.api.upgrade(
@ -42,10 +42,11 @@ try:
print "Automatic upgrade failed." print "Automatic upgrade failed."
raise raise
elif dbversion > required_version: elif dbversion > required_version:
print("""Database version is %d which is higher than the required version %d. I cannot handle this situation without possible data loss.""" % print("""Database version is %d which is higher than the required
version %d. I cannot handle this situation without possible data loss.""" %
(dbversion, required_version)) (dbversion, required_version))
sys.exit(1) sys.exit(1)
except NoSuchTableError, nste: except NoSuchTableError, nste:
print """The database is not versioned. Trying automatic versioning.""" print """The database is not versioned. Trying automatic versioning."""
try: try:
migrate.versioning.api.version_control( migrate.versioning.api.version_control(

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,10 +18,12 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
import getopt
import getopt, sys, logging import sys
import logging
from gnuviechadmin.exceptions import GnuviechadminError from gnuviechadmin.exceptions import GnuviechadminError
class CliCommand: class CliCommand:
"""Base class for command line interface. """Base class for command line interface.
@ -65,17 +66,17 @@ Common options:
%(option)s %(option)s
%(mandatory)s %(optiondesc)s %(mandatory)s %(optiondesc)s
""" % { 'called' : sys.argv[0], """ % {'called': sys.argv[0],
'command' : self.name, 'command': self.name,
'description' : self.description, 'description': self.description,
'option' : '-v, --verbose', 'option': '-v, --verbose',
'optiondesc' : 'verbose operation', 'optiondesc': 'verbose operation',
'mandatory' : " "} 'mandatory': " "}
for commandname in self._optionmap.keys(): for commandname in self._optionmap.keys():
cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % { cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % {
'called' : sys.argv[0], 'called': sys.argv[0],
'command' : self.name, 'command': self.name,
'subcommand' : commandname} 'subcommand': commandname}
desc = """ desc = """
%s %s
""" % (self._optionmap[commandname][0]) """ % (self._optionmap[commandname][0])
@ -97,9 +98,9 @@ Common options:
if not mandatory: if not mandatory:
cmd = cmd + "]" cmd = cmd + "]"
descmap = { descmap = {
'option' : ", ".join(pairs), 'option': ", ".join(pairs),
'optiondesc' : optiondesc, 'optiondesc': optiondesc,
'mandatory' : ' '} 'mandatory': ' '}
if mandatory: if mandatory:
descmap['mandatory'] = '*' descmap['mandatory'] = '*'
desc = desc + """ %(option)s desc = desc + """ %(option)s

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,7 +18,6 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
"""This is the gnuviechadmin.cli package. """This is the gnuviechadmin.cli package.
This package provides modules for the command line interface of the This package provides modules for the command line interface of the

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,8 +18,9 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class ClientCli(CliCommand.CliCommand): class ClientCli(CliCommand.CliCommand):
"""Command line interface command for client management.""" """Command line interface command for client management."""
@ -28,37 +28,36 @@ class ClientCli(CliCommand.CliCommand):
name = "client" name = "client"
description = "manage clients" description = "manage clients"
_optionmap = { _optionmap = {
'create' : ("creates a new client", 'create': ("creates a new client",
[(["-f", "--firstname"], "firstname", [(["-f", "--firstname"], "firstname",
"the client's first name", True), "the client's first name", True),
(["-l", "--lastname"], "lastname", (["-l", "--lastname"], "lastname",
"the client's last name", True), "the client's last name", True),
(["-t", "--title"], "title", (["-t", "--title"], "title",
"the client's title", False), "the client's title", False),
(["-a", "--address"], "address1", (["-a", "--address"], "address1",
"the address of the client", True), "the address of the client", True),
(["--address2"], "address2", (["--address2"], "address2",
"second line of the client's address", False), "second line of the client's address", False),
(["-z", "--zip"], "zip", (["-z", "--zip"], "zip",
"the zipcode of the client's address", True), "the zipcode of the client's address", True),
(["-c", "--city"], "city", (["-c", "--city"], "city",
"the city of the client's address", True), "the city of the client's address", True),
(["--country"], "country", (["--country"], "country",
"the client's country", False), "the client's country", False),
(["-e", "--email"], "email", (["-e", "--email"], "email",
"the client's email address", True), "the client's email address", True),
(["-p", "--phone"], "phone", (["-p", "--phone"], "phone",
"the client's phone number", True), "the client's phone number", True),
(["-m", "--mobile"], "mobile", (["-m", "--mobile"], "mobile",
"the client's mobile phone number", False), "the client's mobile phone number", False),
(["-x", "--fax"], "fax", (["-x", "--fax"], "fax",
"the client's fax number", False)]), "the client's fax number", False)]),
'list' : ("lists existing clients", 'list': ("lists existing clients", []),
[]), 'delete': ("deletes the specified client if it has no dependent data",
'delete' : ("deletes the specified client if it has no dependent data", [(["-c", "--clientid"], "clientid",
[(["-c", "--clientid"], "clientid", "the client id", True)])}
"the client id", True)])}
def _execute(self, subcommand): def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand, self.logger.debug("execute %s with data %s", subcommand,
str(self._data)) str(self._data))

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,8 +18,9 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class DomainCli(CliCommand.CliCommand): class DomainCli(CliCommand.CliCommand):
"""Command line interface command for domain management.""" """Command line interface command for domain management."""
@ -28,20 +28,19 @@ class DomainCli(CliCommand.CliCommand):
name = "domain" name = "domain"
description = "manage domains" description = "manage domains"
_optionmap = { _optionmap = {
'create' : ("creates a new domain", 'create': ("creates a new domain",
[(["-n", "--name"], "name", [(["-n", "--name"], "name",
"the domain name", True), "the domain name", True),
(["-t", "--type"], "type", (["-t", "--type"], "type",
"domain type m for master or s for slave", False), "domain type m for master or s for slave", False),
(["-m", "--master"], "master", (["-m", "--master"], "master",
"master server for slave domains", False), "master server for slave domains", False),
(["-s", "--sysuserid"], "sysuserid", (["-s", "--sysuserid"], "sysuserid",
"system user id", True)]), "system user id", True)]),
'list' : ("lists existing domains", 'list': ("lists existing domains", []),
[]), 'delete': ("delete a domain",
'delete' : ("delete a domain", [(["-d", "--domainid"], "domainid",
[(["-d", "--domainid"], "domainid", "the domain id", True)])}
"the domain id", True)])}
def _execute(self, subcommand): def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand, self.logger.debug("execute %s with data %s", subcommand,

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,8 +18,9 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class RecordCli(CliCommand.CliCommand): class RecordCli(CliCommand.CliCommand):
"""Command line interface command for DNS record management.""" """Command line interface command for DNS record management."""
@ -28,25 +28,25 @@ class RecordCli(CliCommand.CliCommand):
name = "record" name = "record"
description = "manage DNS records" description = "manage DNS records"
_optionmap = { _optionmap = {
'create' : ("creates a new record", 'create': ("creates a new record",
[(["-n", "--name"], "name", [(["-n", "--name"], "name",
"the record name", True), "the record name", True),
(["-t", "--type"], "type", (["-t", "--type"], "type",
"record type", True), "record type", True),
(["-c", "--content"], "content", (["-c", "--content"], "content",
"record content", True), "record content", True),
(["-p", "--prio"], "prio", (["-p", "--prio"], "prio",
"MX record priority", False), "MX record priority", False),
(["--ttl"], "ttl", (["--ttl"], "ttl",
"time to live", False), "time to live", False),
(["-d", "--domainid"], "domainid", (["-d", "--domainid"], "domainid",
"domain id", True)]), "domain id", True)]),
'list' : ("lists existing records", 'list': ("lists existing records",
[(["-d", "--domainid"], "domainid", [(["-d", "--domainid"], "domainid",
"domain id", False)]), "domain id", False)]),
'delete' : ("delete a record", 'delete': ("delete a record",
[(["-r", "--recordid"], "recordid", [(["-r", "--recordid"], "recordid",
"the record id", True)])} "the record id", True)])}
def _execute(self, subcommand): def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand, self.logger.debug("execute %s with data %s", subcommand,

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,33 +18,33 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class SysuserCli(CliCommand.CliCommand): class SysuserCli(CliCommand.CliCommand):
"""Command line interface command for system user managament.""" """Command line interface command for system user managament."""
name = "sysuser" name = "sysuser"
description = "manage system users" description = "manage system users"
_optionmap = { _optionmap = {
"create" : ("create a new system user with the given options.", "create": ("create a new system user with the given options.",
[(["-n", "--username"], "username", [(["-n", "--username"], "username",
"the system user name", False), "the system user name", False),
(["-t", "--usertype"], "usertype", (["-t", "--usertype"], "usertype",
"the numeric user type", False), "the numeric user type", False),
(["-h", "--home"], "home", (["-h", "--home"], "home",
"the home directory", False), "the home directory", False),
(["-s", "--shell"], "shell", (["-s", "--shell"], "shell",
"true if the user should get shell access", False), "true if the user should get shell access", False),
(["-p", "--password"], "clearpass", (["-p", "--password"], "clearpass",
"the password for the user", False), "the password for the user", False),
(["-c", "--clientid"], "clientid", (["-c", "--clientid"], "clientid",
"the client id", True)]), "the client id", True)]),
"list" : ("list existing system users.", "list": ("list existing system users.", []),
[]), "delete": ("delete a system user.",
"delete" : ("delete a system user.", [(["-s", "--sysuserid"], "sysuserid",
[(["-s", "--sysuserid"], "sysuserid", "the system user id", True)])}
"the system user id", True)])}
def _execute(self, subcommand): def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand, self.logger.debug("execute %s with data %s", subcommand,

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,26 +18,30 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
"""This file defines the gnuviechadmin specific exception types.""" """This file defines the gnuviechadmin specific exception types."""
class GnuviechadminError(Exception): class GnuviechadminError(Exception):
"""This is the base class for domain specific exceptions of """This is the base class for domain specific exceptions of
Gnuviechadmin.""" Gnuviechadmin."""
pass pass
class MissingFieldsError(GnuviechadminError): class MissingFieldsError(GnuviechadminError):
"""This exception should be raised when a required field of a data """This exception should be raised when a required field of a data
class is missing.""" class is missing."""
def __init__(self, missingfields): def __init__(self, missingfields):
self.missing = missingfields self.missing = missingfields
def __str__(self): def __str__(self):
return "the fields %s are missing." % (repr(self.missing)) return "the fields %s are missing." % (repr(self.missing))
class CreationFailedError(GnuviechadminError): class CreationFailedError(GnuviechadminError):
"""This exception should be raised if a business object could not """This exception should be raised if a business object could not
be created.""" be created."""
def __init__(self, classname, cause = None): def __init__(self, classname, cause = None):
self.classname = classname self.classname = classname
self.cause = cause self.cause = cause
@ -49,9 +52,11 @@ class CreationFailedError(GnuviechadminError):
msg += " The reason is %s." % (str(self.cause)) msg += " The reason is %s." % (str(self.cause))
return msg return msg
class DeleteFailedError(GnuviechadminError): class DeleteFailedError(GnuviechadminError):
"""This exception should be raise if a business object coild not """This exception should be raise if a business object coild not
be deleted.""" be deleted."""
def __init__(self, classname, cause = None): def __init__(self, classname, cause = None):
self.classname = classname self.classname = classname
self.cause = cause self.cause = cause
@ -62,9 +67,11 @@ class DeleteFailedError(GnuviechadminError):
msg += " The reason is %s." % (str(self.cause)) msg += " The reason is %s." % (str(self.cause))
return msg return msg
class ValidationFailedError(GnuviechadminError): class ValidationFailedError(GnuviechadminError):
"""This exception should be raised if the validation of a business """This exception should be raised if the validation of a business
object failed.""" object failed."""
def __init__(self, instance, cause = None): def __init__(self, instance, cause = None):
self.instance = instance self.instance = instance
self.cause = cause self.cause = cause
@ -75,9 +82,11 @@ class ValidationFailedError(GnuviechadminError):
msg += " The reason is %s." % (str(self.cause)) msg += " The reason is %s." % (str(self.cause))
return msg return msg
class CannotDeleteError(GnuviechadminError): class CannotDeleteError(GnuviechadminError):
"""This exception should be raised if an entity cannot be deleted """This exception should be raised if an entity cannot be deleted
because of some unmatched precondition.""" because of some unmatched precondition."""
def __init__(self, instance, cause = None): def __init__(self, instance, cause = None):
self.instance = instance self.instance = instance
self.cause = cause self.cause = cause

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -22,10 +21,13 @@
"""Tools for handling user and group information.""" """Tools for handling user and group information."""
import pwd, grp import pwd
import grp
class PasswdUser(object): class PasswdUser(object):
"""This class represents users in the user database.""" """This class represents users in the user database."""
def __init__(self, username, pw, uid, gid, gecos, home, shell): def __init__(self, username, pw, uid, gid, gecos, home, shell):
"""Create a new PasswdUser.""" """Create a new PasswdUser."""
self.username = username self.username = username
@ -45,8 +47,10 @@ class PasswdUser(object):
self.home, self.home,
self.shell) self.shell)
class PasswdGroup(object): class PasswdGroup(object):
"""This class represents lines in the groups database.""" """This class represents lines in the groups database."""
def __init__(self, groupname, pw, gid, members): def __init__(self, groupname, pw, gid, members):
"""Create a new PasswdGroup.""" """Create a new PasswdGroup."""
self.groupname = groupname self.groupname = groupname
@ -60,18 +64,22 @@ class PasswdGroup(object):
self.gid, self.gid,
",".join(self.members)) ",".join(self.members))
def parse_groups(): def parse_groups():
"""Parses all available groups to PasswdGroup instances.""" """Parses all available groups to PasswdGroup instances."""
return [PasswdGroup(*arr) for arr in grp.getgrall()] return [PasswdGroup(*arr) for arr in grp.getgrall()]
def parse_users(): def parse_users():
"""Parses all available users to PasswdUser instances.""" """Parses all available users to PasswdUser instances."""
return [PasswdUser(*arr) for arr in pwd.getpwall()] return [PasswdUser(*arr) for arr in pwd.getpwall()]
def find_user_by_prefix(prefix): def find_user_by_prefix(prefix):
"""Finds all user entries with the given prefix.""" """Finds all user entries with the given prefix."""
return [user for user in parse_users() if user.username.startswith(prefix)] return [user for user in parse_users() if user.username.startswith(prefix)]
def get_user_by_id(uid): def get_user_by_id(uid):
"""Gets the user with the given user id.""" """Gets the user with the given user id."""
users = [user for user in parse_users() if user.uid == uid] users = [user for user in parse_users() if user.uid == uid]
@ -79,6 +87,7 @@ def get_user_by_id(uid):
return users[0] return users[0]
return None return None
def get_group_by_id(gid): def get_group_by_id(gid):
"""Gets the group with the given group id.""" """Gets the group with the given group id."""
groups = [group for group in parse_groups() if group.gid == gid] groups = [group for group in parse_groups() if group.gid == gid]
@ -86,6 +95,7 @@ def get_group_by_id(gid):
return groups[0] return groups[0]
return None return None
def get_next_uid(lowerboundary = 10000, upperboundary = 65536): def get_next_uid(lowerboundary = 10000, upperboundary = 65536):
"""Gets the first available user id in the given range. """Gets the first available user id in the given range.
@ -98,16 +108,19 @@ def get_next_uid(lowerboundary = 10000, upperboundary = 65536):
""" """
for uid in range(lowerboundary, upperboundary): for uid in range(lowerboundary, upperboundary):
try: try:
user = pwd.getpwuid(uid) user = pwd.getpwuid(uid)
except KeyError: except KeyError:
return uid return uid
raise Exception("no free uid found in range %d to %d", lowerboundary, upperboundary) raise Exception("no free uid found in range %d to %d",
lowerboundary, upperboundary)
def get_max_uid(boundary = 65536): def get_max_uid(boundary = 65536):
"""Gets the highest uid value.""" """Gets the highest uid value."""
return max([user.uid for user in parse_users() if user.uid <= boundary]) return max([user.uid for user in parse_users() if user.uid <= boundary])
def get_max_gid(boundary = 65536): def get_max_gid(boundary = 65536):
"""Gets the highest gid value.""" """Gets the highest gid value."""
return max([group.gid for group in parse_groups() \ return max([group.gid for group in parse_groups() \
@ -119,4 +132,3 @@ if __name__ == "__main__":
print "User with max UID is %s" % (get_user_by_id(get_max_uid(40000))) print "User with max UID is %s" % (get_user_by_id(get_max_uid(40000)))
print "Group with max GID is %s" % (get_group_by_id(get_max_gid(40000))) print "Group with max GID is %s" % (get_group_by_id(get_max_gid(40000)))
print "First free UID is %s" % (get_next_uid(10000, 40000)) print "First free UID is %s" % (get_next_uid(10000, 40000))

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -33,6 +32,7 @@ from pyme.constants.sig import mode
from gnuviechadmin.backend.settings import config from gnuviechadmin.backend.settings import config
def send_mail(subject, text): def send_mail(subject, text):
"""Send a signed and possibly encrypted mail. """Send a signed and possibly encrypted mail.
@ -56,33 +56,33 @@ def send_mail(subject, text):
rcpt = config.get('common', 'mailto') rcpt = config.get('common', 'mailto')
c.signers_clear() c.signers_clear()
for sigkey in [x for x in c.op_keylist_all(signer, 1)]: for sigkey in [x for x in c.op_keylist_all(signer, 1)]:
if sigkey.can_sign: if sigkey.can_sign:
c.signers_add(sigkey) c.signers_add(sigkey)
if not c.signers_enum(0): if not c.signers_enum(0):
raise Exception("No secret keys for signing available for %s." % ( raise Exception("No secret keys for signing available for %s." % (
signer)) signer))
keylist = [] keylist = []
for key in c.op_keylist_all(rcpt, 0): for key in c.op_keylist_all(rcpt, 0):
valid = 0 valid = 0
subkey = key.subkeys subkey = key.subkeys
while subkey: while subkey:
keyid = subkey.keyid keyid = subkey.keyid
if keyid == None: if keyid == None:
break break
can_encrypt = subkey.can_encrypt can_encrypt = subkey.can_encrypt
valid += can_encrypt valid += can_encrypt
subkey = subkey.next subkey = subkey.next
if valid: if valid:
keylist.append(key) keylist.append(key)
if keylist: if keylist:
c.op_encrypt_sign(keylist, 1, plain, cipher) c.op_encrypt_sign(keylist, 1, plain, cipher)
else: else:
c.op_sign(plain, cipher, mode.CLEAR) c.op_sign(plain, cipher, mode.CLEAR)
cipher.seek(0,0) cipher.seek(0, 0)
msg = MIMEText(cipher.read()) msg = MIMEText(cipher.read())
if keylist: if keylist:
msg.set_param("x-action", "pgp-encrypted") msg.set_param("x-action", "pgp-encrypted")
msg['Subject'] = subject msg['Subject'] = subject
msg['From'] = signer msg['From'] = signer
msg['To'] = rcpt msg['To'] = rcpt

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -21,7 +20,9 @@
# Version: $Id$ # Version: $Id$
"""This module provides some functions for password handling.""" """This module provides some functions for password handling."""
import crypt, crack, random import crypt
import crack
import random
_pwchars = [] _pwchars = []
for _pair in (('0', '9'), ('A', 'Z'), ('a', 'z')): for _pair in (('0', '9'), ('A', 'Z'), ('a', 'z')):
@ -30,6 +31,7 @@ _saltchars = [_char for _char in _pwchars]
for _char in "-+/*_@": for _char in "-+/*_@":
_pwchars.append(ord(_char)) _pwchars.append(ord(_char))
def generatepassword(minlength = 8, maxlength = 12): def generatepassword(minlength = 8, maxlength = 12):
"""Generates a new random password with a given length. """Generates a new random password with a given length.
@ -44,6 +46,7 @@ def generatepassword(minlength = 8, maxlength = 12):
random.sample(_pwchars, random.sample(_pwchars,
random.randint(minlength, maxlength))]) random.randint(minlength, maxlength))])
def checkpassword(password): def checkpassword(password):
"""Checks the password with cracklib. """Checks the password with cracklib.
@ -58,7 +61,8 @@ def checkpassword(password):
except ValueError, ve: except ValueError, ve:
print "Weak password:", ve print "Weak password:", ve
return None return None
def md5_crypt_password(password): def md5_crypt_password(password):
"""Hashes the given password with MD5 and a random salt value. """Hashes the given password with MD5 and a random salt value.
@ -71,6 +75,7 @@ def md5_crypt_password(password):
random.sample(_saltchars, 8)]) random.sample(_saltchars, 8)])
return crypt.crypt(password, '$1$' + salt) return crypt.crypt(password, '$1$' + salt)
def get_pw_tuple(password = None): def get_pw_tuple(password = None):
"""Gets a valid (password, hashvalue) tuple. """Gets a valid (password, hashvalue) tuple.
@ -82,3 +87,6 @@ def get_pw_tuple(password = None):
while password == None or checkpassword(password) == None: while password == None or checkpassword(password) == None:
password = generatepassword() password = generatepassword()
return (password, md5_crypt_password(password)) return (password, md5_crypt_password(password))
# TODO: implement a is_password_valid(hash, password) function

31
gnuviechadmin/util/stmtcreator.py Normal file → Executable file
View File

@ -1,4 +1,4 @@
# -*- python -*- #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -24,16 +24,23 @@
creation.""" creation."""
if __name__ == '__main__': if __name__ == '__main__':
from passwordutils import get_pw_tuple from passwordutils import get_pw_tuple
import sys import sys
for line in sys.stdin.readlines(): for line in sys.stdin.readlines():
parts = line.split() parts = line.split()
if len(parts) < 4: if len(parts) < 4:
raise ValueError("""lines must consist of the elements: raise ValueError("""lines must consist of the elements:
email@domain username uid domainid""") email@domain username uid domainid""")
(email, domain) = parts[0].split("@") (email, domain) = parts[0].split("@")
username = parts[1][0:5] username = parts[1][0:5]
pwtuple = get_pw_tuple() pwtuple = get_pw_tuple()
print "INSERT INTO mailpassword (id, clearpass, cryptpass, uid, gid, home, spamcheck) VALUES ('%s', '%s', '%s', %d, %d, '/home/mail/%s/%s', 'false');" % (parts[1], pwtuple[0], pwtuple[1], int(parts[2]), 119, username, parts[1]) print "INSERT INTO mailpassword " + \
print "INSERT INTO mailaddress (domainid, email, target) VALUES (%d, '%s', '%s');" % (int(parts[3]), email, parts[1]) "(id, clearpass, cryptpass, uid, gid, home, spamcheck) " + \
"VALUES " + \
"('%s', '%s', '%s', %d, %d, '/home/mail/%s/%s', 'false');" % (
parts[1], pwtuple[0], pwtuple[1], int(parts[2]), 119,
username, parts[1])
print "INSERT INTO mailaddress (domainid, email, target) " + \
"VALUES (%d, '%s', '%s');" % (
int(parts[3]), email, parts[1])

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2008 by Jan Dittberner. # Copyright (C) 2008 by Jan Dittberner.
@ -19,12 +18,12 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
"""This file defines a facade for exporting gnuviechadmin """This file defines a facade for exporting gnuviechadmin
functionality via XMLRPC.""" functionality via XMLRPC."""
from gnuviechadmin.xmlrpc.users import GVAUsers from gnuviechadmin.xmlrpc.users import GVAUsers
class XMLRPCFacade(GVAUsers): class XMLRPCFacade(GVAUsers):
"""This class provides access to selected gnuviechadmin """This class provides access to selected gnuviechadmin
functionality for use via XMLRPC.""" functionality for use via XMLRPC."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2008 by Jan Dittberner. # Copyright (C) 2008 by Jan Dittberner.
@ -19,7 +18,6 @@
# USA. # USA.
# #
# Version: $Id$ # Version: $Id$
"""This is the gnuviechadmin.xmlrpc package. """This is the gnuviechadmin.xmlrpc package.
This package provides modules for the XMLRPC interface of the This package provides modules for the XMLRPC interface of the

View File

@ -1,20 +1,47 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
"""This file provides a authkit.users.Users implementation and several
UserProviders for authenticating different user types and enabling
password change functions."""
from authkit.users import Users, AuthKitNoSuchUserError from authkit.users import Users, AuthKitNoSuchUserError
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class UserProvider(Users): class UserProvider(Users):
"""A base class for user providers."""
def _get_user(self, username, password, role): def _get_user(self, username, password, role):
return { return {
'username' : username, 'username': username,
'group' : None, 'group': None,
'password' : password, 'password': password,
'roles' : [role] 'roles': [role]}
}
class ClientUserProvider(UserProvider): class ClientUserProvider(UserProvider):
"""A UserProvider implementation class for clients."""
def user(self, username): def user(self, username):
print 'checking %s' % username print 'checking %s' % username
if username == 'dummy': if username == 'dummy':
@ -24,23 +51,34 @@ class ClientUserProvider(UserProvider):
def list_roles(self): def list_roles(self):
return ['client'] return ['client']
class MailuserUserProvider(UserProvider): class MailuserUserProvider(UserProvider):
"""A UserProvider implementation class for mail users."""
def user(self, username): def user(self, username):
raise AuthKitNoSuchUserError() raise AuthKitNoSuchUserError()
def list_roles(self): def list_roles(self):
return ['mailuser'] return ['mailuser']
class SysuserUserProvider(UserProvider): class SysuserUserProvider(UserProvider):
"""A UserProvider implementation class for system users."""
def user(self, username): def user(self, username):
raise AuthKitNoSuchUserError() raise AuthKitNoSuchUserError()
def list_roles(self): def list_roles(self):
return ['sysuser'] return ['sysuser']
class GVAUsers(Users): class GVAUsers(Users):
"""This class provides an implementation of authkit.users.Users
which dispatches several methods to configured UserProvider
implementations."""
def __init__(self, data, userproviders = [], encrypt = None): def __init__(self, data, userproviders = [], encrypt = None):
"""Initialize the GVAXMLRPCUsers instance.""" """Initialize the GVAUsers instance."""
Users.__init__(self, data, encrypt) Users.__init__(self, data, encrypt)
self.userproviders = [prov(self.data) for prov in userproviders] self.userproviders = [prov(self.data) for prov in userproviders]
@ -65,16 +103,16 @@ class GVAUsers(Users):
def user(self, username): def user(self, username):
"""Returns a dictionary in the following format: """Returns a dictionary in the following format:
.. code-block :: Python .. code-block :: Python
{ {
'username': username, 'username': username,
'group': group, 'group': group,
'password': password, 'password': password,
'roles': [role1,role2,role3... etc] 'roles': [role1,role2,role3... etc]
} }
The role names are ordered alphabetically The role names are ordered alphabetically
Raises an exception if the user doesn't exist.""" Raises an exception if the user doesn't exist."""
for prov in self.userproviders: for prov in self.userproviders:

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (C) 2007, 2008 by Jan Dittberner. # Copyright (C) 2007, 2008 by Jan Dittberner.
@ -36,7 +35,7 @@ setup(
setup_requires = [], setup_requires = [],
include_package_data = True, include_package_data = True,
exclude_package_data = { '' : ['gva.cfg'] }, exclude_package_data = {'': ['gva.cfg']},
author = 'Jan Dittberner', author = 'Jan Dittberner',
author_email = 'jan@dittberner.info', author_email = 'jan@dittberner.info',
@ -44,7 +43,7 @@ setup(
long_description = """this is a suite of tools for administering a server long_description = """this is a suite of tools for administering a server
it contains tools for maintaining e.g. clients, domains, users, mail it contains tools for maintaining e.g. clients, domains, users, mail
accounts""", accounts""",
license = 'GPL', license = 'GPL',
keywords = 'administration backend frontend', keywords = 'administration backend frontend',
url = 'http://www.gnuviech-server.de/projects/gnuviechadmin', url = 'http://www.gnuviech-server.de/projects/gnuviechadmin',
) )

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
from migrate.versioning.shell import main from migrate.versioning.shell import main
main(url='postgres://jan:heyyou97@localhost:5432/jan',repository='ormaptest_repo') main(url='postgres://jan:heyyou97@localhost:5432/jan',
repository='ormaptest_repo')

View File

@ -1,26 +1,47 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
from sqlalchemy import * from sqlalchemy import *
meta = BoundMetaData('postgres://jan:heyyou97@localhost:5432/jan') meta = BoundMetaData('postgres://jan:heyyou97@localhost:5432/jan')
domains_table = Table('domains', meta, autoload=True) domains_table = Table('domains', meta, autoload=True)
records_table = Table('records', meta, autoload=True) records_table = Table('records', meta, autoload=True)
class Domain(object): class Domain(object):
def __repr__(self): def __repr__(self):
return "%s(%r,%r)" % ( return "%s(%r,%r)" % (
self.__class__.__name__, self.id, self.name) self.__class__.__name__, self.id, self.name)
class Record(object): class Record(object):
def __repr__(self): def __repr__(self):
return "%s(%r,%r,%r)" % ( return "%s(%r,%r,%r)" % (
self.__class__.__name__, self.id, self.domain_id, self.domain) self.__class__.__name__, self.id, self.domain_id, self.domain)
recordmapper = mapper(Record, records_table) recordmapper = mapper(Record, records_table)
domainmapper = mapper(Domain, domains_table, properties = { domainmapper = mapper(Domain, domains_table, properties = {
'records': relation(Record, backref='domain') 'records': relation(Record, backref='domain')})
})
session = create_session() session = create_session()
query = session.query(Domain) query = session.query(Domain)

View File

@ -7,8 +7,10 @@ account = Table('account', meta,
Column('login', String(40)), Column('login', String(40)),
Column('passwd', String(40))) Column('passwd', String(40)))
def upgrade(): def upgrade():
account.create() account.create()
def downgrade(): def downgrade():
account.drop() account.drop()

View File

@ -4,8 +4,10 @@ from migrate import *
meta = BoundMetaData(migrate_engine) meta = BoundMetaData(migrate_engine)
account = Table('account', meta) account = Table('account', meta)
def upgrade(): def upgrade():
account.drop() account.drop()
def downgrade(): def downgrade():
account.create() account.create()

View File

@ -15,8 +15,7 @@ domains = Table('domains', meta,
Column('type', String(6), nullable=False), Column('type', String(6), nullable=False),
Column('notified_serial', Integer), Column('notified_serial', Integer),
Column('account', String(40)), Column('account', String(40)),
UniqueConstraint('name', name='name_index') UniqueConstraint('name', name='name_index'))
)
records = Table('records', meta, records = Table('records', meta,
Column('id', Integer, primary_key=True), Column('id', Integer, primary_key=True),
@ -28,17 +27,18 @@ records = Table('records', meta,
Column('prio', Integer), Column('prio', Integer),
Column('change_date', Integer), Column('change_date', Integer),
ForeignKeyConstraint(['domain_id'], ['domains.id'], ForeignKeyConstraint(['domain_id'], ['domains.id'],
ondelete='CASCADE', name='domain_exists') ondelete='CASCADE', name='domain_exists'))
)
Index('domain_id', records.c.domain_id) Index('domain_id', records.c.domain_id)
Index('nametype_index', records.c.name, records.c.type) Index('nametype_index', records.c.name, records.c.type)
Index('rec_name_index', records.c.name) Index('rec_name_index', records.c.name)
def upgrade(): def upgrade():
supermasters.create() supermasters.create()
domains.create() domains.create()
records.create() records.create()
def downgrade(): def downgrade():
records.drop() records.drop()
domains.drop() domains.drop()

View File

@ -1,74 +1,93 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*-
# #
# Copyright (c) 2007 Jan Dittberner # Copyright (C) 2007, 2008 by Jan Dittberner.
# $Id$
# #
import getopt, sys # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
import getopt
import sys
from gnuviechadmin.dblayer import * from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --firstname=<firstname> --lastname=<lastname> \ def usage():
--address1=<address1> --town=<town> --zipcode=<zipcode> \ print """Usage information:
[--address2=<address2>] [--country=<country>] [--state=<state>] \ =====================
[--active=true|false] [--phone=<phone>] [--mobile=<mobile>] %(process)s -h|--help
- adds a new client - prints this help text
""" % {'process': sys.argv[0]}
%(process)s --firstname=<firstname> --lastname=<lastname> \
--address1=<address1> --town=<town> --zipcode=<zipcode> \
[--address2=<address2>] [--country=<country>] [--state=<state>] \
[--active=true|false] [--phone=<phone>] [--mobile=<mobile>]
- adds a new client
""" % {'process': sys.argv[0]}
if __name__ == "__main__": if __name__ == "__main__":
try: try:
(options, args) = getopt.getopt(sys.argv[1:], "h", (options, args) = getopt.getopt(sys.argv[1:], "h",
['help', ['help',
'firstname=', 'lastname=', 'address1=', 'firstname=', 'lastname=',
'town=', 'zipcode=', 'address2=', 'address1=',
'country=', 'state=', 'active=', 'town=', 'zipcode=', 'address2=',
'phone=', 'mobile=']) 'country=', 'state=', 'active=',
except getopt.GetoptError: 'phone=', 'mobile='])
usage() except getopt.GetoptError:
sys.exit(1) usage()
sys.exit(1)
if (not options or if (not options or
dict(options).has_key('-h') or '-h' in dict(options) or
dict(options).has_key('--help') or '--help' in dict(options) or
not dict(options).has_key('--firstname') or not '--firstname' in dict(options) or
not dict(options).has_key('--lastname') or not '--lastname' in dict(options) or
not dict(options).has_key('--address1') or not '--address1' in dict(options) or
not dict(options).has_key('--town') or not '--town' in dict(options) or
not dict(options).has_key('--zipcode') or not '--zipcode' in dict(options) or
not dict(options)['--firstname'].strip() or not dict(options)['--firstname'].strip() or
not dict(options)['--lastname'].strip() or not dict(options)['--lastname'].strip() or
not dict(options)['--address1'].strip() or not dict(options)['--address1'].strip() or
not dict(options)['--town'].strip() or not dict(options)['--town'].strip() or
not dict(options)['--zipcode'].strip()): not dict(options)['--zipcode'].strip()):
usage() usage()
sys.exit(1) sys.exit(1)
po = dict(options) po = dict(options)
for key in po.keys(): for key in po.keys():
po[key] = po[key].strip() po[key] = po[key].strip()
client = Client() client = Client()
client.firstname = po['--firstname'] client.firstname = po['--firstname']
client.lastname = po['--lastname'] client.lastname = po['--lastname']
client.address1 = po['--address1'] client.address1 = po['--address1']
client.town = po['--town'] client.town = po['--town']
client.zipcode = po['--zipcode'] client.zipcode = po['--zipcode']
if po.has_key('--active'): if '--active' in po:
client.active = (po['--active'] == 'true') client.active = (po['--active'] == 'true')
else: else:
client.active = True client.active = True
if po.has_key('--address2') and po['--address2']: if '--address2' in po and po['--address2']:
client.address2 = po['--address2'] client.address2 = po['--address2']
if po.has_key('--country') and po['--country']: if '--country' in po and po['--country']:
client.country = po['--country'] client.country = po['--country']
if po.has_key('--state') and po['--state']: if '--state' in po and po['--state']:
client.state = po['--state'] client.state = po['--state']
if po.has_key('--phone') and po['--phone']: if '--phone' in po and po['--phone']:
client.phone = po['--phone'] client.phone = po['--phone']
if po.has_key('--mobile') and po['--mobile']: if '--mobile' in po and po['--mobile']:
client.mobile = po['--mobile'] client.mobile = po['--mobile']
session.save(client) session.save(client)
session.flush() session.flush()

View File

@ -1,59 +1,77 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*-
# #
# Copyright (c) 2007 Jan Dittberner # Copyright (C) 2007, 2008 by Jan Dittberner.
# $Id$
# #
import getopt, sys # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
import getopt
import sys
from gnuviechadmin.dblayer import * from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> --sysuser=<sysuser> --type=MASTER|SLAVE \ def usage():
[[--ns=<nameserver>] [--mx=<mxserver[,prio]>] [--a=<ipaddress>] ...] print """Usage information:
- adds a new domain =====================
""" % {'process': sys.argv[0]} %(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> --sysuser=<sysuser> --type=MASTER|SLAVE \
[[--ns=<nameserver>] [--mx=<mxserver[,prio]>] [--a=<ipaddress>] ...]
- adds a new domain
""" % {'process': sys.argv[0]}
if __name__ == "__main__": if __name__ == "__main__":
try: try:
(options, args) = getopt.getopt(sys.argv[1:], "h", (options, args) = getopt.getopt(sys.argv[1:], "h",
['help', ['help',
'domain=', 'sysuser=', 'domain=', 'sysuser=',
'type=', 'ns=', 'mx=', 'a=']) 'type=', 'ns=', 'mx=', 'a='])
except getopt.GetoptError: except getopt.GetoptError:
usage() usage()
sys.exit(1) sys.exit(1)
if (not options or if (not options or
dict(options).has_key('-h') or '-h' in dict(options) or
dict(options).has_key('--help') or '--help' in dict(options) or
not dict(options).has_key('--domain') or not '--domain' in dict(options) or
not dict(options).has_key('--sysuser') or not '--sysuser' in dict(options) or
not dict(options)['--sysuser'].strip() or not dict(options)['--sysuser'].strip() or
not dict(options)['--domain'].strip()): not dict(options)['--domain'].strip()):
usage() usage()
sys.exit(1) sys.exit(1)
po = {} po = {}
for (key, value) in options: for (key, value) in options:
if po.has_key(key): if key in po:
po[key].append(value.strip()) po[key].append(value.strip())
else: else:
po[key] = [value.strip()] po[key] = [value.strip()]
# fetch the sysuser # fetch the sysuser
query = session.query(SysUser) query = session.query(SysUser)
sysuser = query.get_by(name = po['--sysuser'][0]) sysuser = query.get_by(name = po['--sysuser'][0])
if not sysuser: if not sysuser:
print "Invalid system user" print "Invalid system user"
allsysusers = query.get_by(name = '*') allsysusers = query.get_by(name = '*')
if allsysusers: if allsysusers:
print "Valid system users are:\n%s" % ("\n".join(allsysusers)) print "Valid system users are:\n%s" % ("\n".join(allsysusers))
else: else:
print "No system users defined yet." print "No system users defined yet."
sys.exit(1) sys.exit(1)
print sysuser.domains print sysuser.domains

View File

@ -1,45 +1,64 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*-
# #
# Copyright (c) 2007 Jan Dittberner # Copyright (C) 2007, 2008 by Jan Dittberner.
# $Id$
# #
import getopt, sys # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
import getopt
import sys
from gnuviechadmin.dblayer import * from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> [--password=<password>] def usage():
- adds a new pop user for the given domain print """Usage information:
- if the optional password is ommitted a generated one is used =====================
- the password is checked using cracklib %(process)s -h|--help
- if the password is too weak a generated one is used - prints this help text
""" % {'process': sys.argv[0]}
%(process)s --domain=<domain> [--password=<password>]
- adds a new pop user for the given domain
- if the optional password is ommitted a generated one is used
- the password is checked using cracklib
- if the password is too weak a generated one is used
""" % {'process': sys.argv[0]}
if __name__ == "__main__": if __name__ == "__main__":
try: try:
(options, args) = getopt.getopt(sys.argv[1:], "h", ['help', 'password=', 'domain=']) (options, args) = getopt.getopt(sys.argv[1:], "h",
except getopt.GetoptError: ['help', 'password=', 'domain='])
usage() except getopt.GetoptError:
sys.exit(1) usage()
sys.exit(1)
if (not options or
dict(options).has_key('-h') or
dict(options).has_key('--help') or
not dict(options).has_key('--domain') or
not dict(options)['--domain'].strip()):
usage()
sys.exit(1)
# specify the domain if (not options or
query = session.query(Domain) '-h' in dict(options) or
domain = query.get_by(name = dict(options)['--domain'].strip()) '--help' in dict(options) or
if not domain: not '--domain' in dict(options) or
print "Invalid Domain" not dict(options)['--domain'].strip()):
print "valid domains are:\n%s" % ("\n".join(query.get())) usage()
sys.exit(1) sys.exit(1)
print domain.popaccounts # specify the domain
query = session.query(Domain)
domain = query.get_by(name = dict(options)['--domain'].strip())
if not domain:
print "Invalid Domain"
print "valid domains are:\n%s" % ("\n".join(query.get()))
sys.exit(1)
print domain.popaccounts

View File

@ -1,53 +1,72 @@
#!/usr/bin/env python #!/usr/bin/env python
# #
# Copyright (c) 2007 Jan Dittberner # Copyright (C) 2007, 2008 by Jan Dittberner.
# $Id$
# #
import getopt, sys # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
import getopt
import sys
from gnuviechadmin.dblayer import * from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --type=admin|reseller|client --clientid=<clientid> \ def usage():
[--name=<name>] [--home=<home>] [--shell=<shell>] [--password] \ print """Usage information:
[--sysuid=<uid>] =====================
- adds a new system user %(process)s -h|--help
""" % {'process': sys.argv[0]} - prints this help text
%(process)s --type=admin|reseller|client --clientid=<clientid> \
[--name=<name>] [--home=<home>] [--shell=<shell>] [--password] \
[--sysuid=<uid>]
- adds a new system user
""" % {'process': sys.argv[0]}
if __name__ == "__main__": if __name__ == "__main__":
try: try:
(options, args) = getopt.getopt(sys.argv[1:], "h", (options, args) = getopt.getopt(sys.argv[1:], "h",
['help', ['help', 'type=', 'clientid=',
'type=', 'clientid=', 'name=', 'home=', 'name=', 'home=', 'shell=',
'shell=', 'password=', 'sysuid=']) 'password=', 'sysuid='])
except getopt.GetoptError: except getopt.GetoptError:
usage() usage()
sys.exit(1) sys.exit(1)
if (not options or if (not options or
dict(options).has_key('-h') or '-h' in dict(options) or
dict(options).has_key('--help') or '--help' in dict(options) or
not dict(options).has_key('--type') or not '--type' in dict(options) or
not dict(options).has_key('--clientid') or not '--clientid' in dict(options) or
not dict(options)['--type'].strip() or not dict(options)['--type'].strip() or
not dict(options)['--clientid'].strip() or not dict(options)['--clientid'].strip() or
not dict(options)['--type'].strip() in ('admin', 'reseller', 'client')): not dict(options)['--type'].strip() in ('admin', 'reseller',
usage() 'client')):
sys.exit(1) usage()
sys.exit(1)
query = session.query(Client) query = session.query(Client)
client = query.get_by(clientid = dict(options)['--clientid'].strip()) client = query.get_by(clientid = dict(options)['--clientid'].strip())
if not client: if not client:
print "Invalid client" print "Invalid client"
allclients = query.select() allclients = query.select()
if allclients: if allclients:
print "Valid clients are:\n- %s" % "\n- ".join([str(client) for client in allclients]) print "Valid clients are:\n- %s" % "\n- ".join(
[str(client) for client in allclients])
else: else:
print "No clients defined yet." print "No clients defined yet."
sys.exit(1) sys.exit(1)
print client.sysusers print client.sysusers

View File

@ -6,7 +6,7 @@ meta = BoundMetaData(migrate_engine)
domains = Table('domains', meta, autoload = True) domains = Table('domains', meta, autoload = True)
mailalias = Table( mailalias = Table(
'mailalias', meta, 'mailalias', meta,
Column('mailaliasid', Integer, primary_key = True), Column('mailaliasid', Integer, primary_key = True),
Column('domainid', Integer, ForeignKey('domains.id'), nullable = False), Column('domainid', Integer, ForeignKey('domains.id'), nullable = False),
Column('email', String(255), nullable = False), Column('email', String(255), nullable = False),
Column('target', TEXT, nullable = False), Column('target', TEXT, nullable = False),
@ -24,10 +24,12 @@ mailpassword = Table(
Column('spamcheck', Boolean, default = False), Column('spamcheck', Boolean, default = False),
Column('sajunkscore', Integer)) Column('sajunkscore', Integer))
def upgrade(): def upgrade():
mailalias.create() mailalias.create()
mailpassword.create() mailpassword.create()
def downgrade(): def downgrade():
mailpassword.drop() mailpassword.drop()
mailalias.drop() mailalias.drop()

View File

@ -31,10 +31,12 @@ sysuser_table = Table(
Column('md5pass', String(34)), Column('md5pass', String(34)),
Column('sysuid', Integer)) Column('sysuid', Integer))
def upgrade(): def upgrade():
client_table.create() client_table.create()
sysuser_table.create() sysuser_table.create()
def downgrade(): def downgrade():
sysuser_table.drop() sysuser_table.drop()
client_table.drop() client_table.drop()

View File

@ -9,9 +9,11 @@ sysuidrefcol = Column('sysuserid', Integer,
ForeignKey('sysuser.sysuserid'), ForeignKey('sysuser.sysuserid'),
nullable = False) nullable = False)
def upgrade(): def upgrade():
sysuidrefcol.create(domains) sysuidrefcol.create(domains)
def downgrade(): def downgrade():
col = domains.c.sysuserid col = domains.c.sysuserid
col.drop() col.drop()

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
from migrate.versioning.shell import main from migrate.versioning.shell import main
main(url='postgres://jan:heyyou97@localhost:5432/testdb',repository='gnuviechadmin') main(url='postgres://jan:heyyou97@localhost:5432/testdb',
repository='gnuviechadmin')

View File

@ -1,3 +1,23 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
from sqlalchemy import * from sqlalchemy import *
from entities import * from entities import *

View File

@ -1,4 +1,27 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$
class Client(object): class Client(object):
def __repr__(self): def __repr__(self):
return "%s(clientid=%s,firstname=%s,lastname=%s)" % \ return "%s(clientid=%s,firstname=%s,lastname=%s)" % \
(self.__class__.__name__, (self.__class__.__name__,
@ -6,7 +29,9 @@ class Client(object):
self.firstname, self.firstname,
self.lastname) self.lastname)
class PopAccount(object): class PopAccount(object):
def __repr__(self): def __repr__(self):
return "%s(%s,%d,%d,%d,%s,%s,%s)" % \ return "%s(%s,%d,%d,%d,%s,%s,%s)" % \
(self.__class__.__name__, (self.__class__.__name__,
@ -18,7 +43,9 @@ class PopAccount(object):
self.cryptpass, self.cryptpass,
self.clearpass) self.clearpass)
class SysUser(object): class SysUser(object):
def __repr__(self): def __repr__(self):
return "%s(%d,%s,%d,%s,%s,%s,%d,%d,%s,%d)" % \ return "%s(%d,%s,%d,%s,%s,%s,%d,%d,%s,%d)" % \
(self.__class__.__name__, (self.__class__.__name__,
@ -33,7 +60,9 @@ class SysUser(object):
self.md5pass, self.md5pass,
self.sysuid) self.sysuid)
class Domain(object): class Domain(object):
def __repr__(self): def __repr__(self):
return "%s(%d,%s,%s,%s,%s,%s,%s)" % \ return "%s(%d,%s,%s,%s,%s,%s,%s)" % \
(self.__class__.__name__, (self.__class__.__name__,