2
from epsilon.hotfix import require
3
require('twisted', 'filepath_copyTo')
7
from twisted.python import usage
8
from twisted.python import filepath
10
from axiom import attributes, userbase
11
from axiom.scripts import axiomatic
14
def installOn(self, other):
15
# XXX check installation on other, not store
16
for ls in self.store.query(userbase.LoginSystem):
17
raise usage.UsageError("UserBase already installed")
19
ls = userbase.LoginSystem(store=self.store)
23
class Install(axiomatic.AxiomaticSubCommand, UserbaseMixin):
24
def postOptions(self):
25
self.installOn(self.store)
27
class Create(axiomatic.AxiomaticSubCommand, UserbaseMixin):
28
synopsis = "<username> <domain> [password]"
30
def parseArgs(self, username, domain, password=None):
31
self['username'] = self.decodeCommandLine(username)
32
self['domain'] = self.decodeCommandLine(domain)
33
self['password'] = password
35
def postOptions(self):
36
for ls in self.store.query(userbase.LoginSystem):
39
ls = self.installOn(self.store)
41
msg = 'Enter new AXIOM password: '
42
while not self['password']:
43
password = getpass.getpass(msg)
44
second = getpass.getpass('Repeat to verify: ')
45
if password == second:
46
self['password'] = password
48
msg = 'Passwords do not match. Enter new AXIOM password: '
51
acc = ls.addAccount(self['username'],
54
except userbase.DuplicateUser:
55
raise usage.UsageError("An account by that name already exists.")
58
class Disable(axiomatic.AxiomaticSubCommand):
59
synopsis = "<username> <domain>"
61
def parseArgs(self, username, domain):
62
self['username'] = self.decodeCommandLine(username)
63
self['domain'] = self.decodeCommandLine(domain)
65
def postOptions(self):
66
for acc in self.store.query(userbase.LoginAccount,
67
attributes.AND(userbase.LoginAccount.username == self['username'],
68
userbase.LoginAccount.domain == self['domain'])):
70
raise usage.UsageError("That account is already disabled.")
75
raise usage.UsageError("No account by that name exists.")
78
class List(axiomatic.AxiomaticSubCommand):
79
def postOptions(self):
81
for acc in self.store.query(userbase.LoginMethod):
82
print acc.localpart + '@' + acc.domain,
83
if acc.account.disabled:
91
class UserBaseCommand(axiomatic.AxiomaticCommand):
93
description = 'LoginSystem introspection and manipulation.'
96
('install', None, Install, "Install UserBase on an Axiom database"),
97
('create', None, Create, "Create a new user"),
98
('disable', None, Disable, "Disable an existing user"),
99
('list', None, List, "List users in an Axiom database"),
103
return self.parent.getStore()
106
class Extract(axiomatic.AxiomaticCommand):
107
name = 'extract-user'
108
description = 'Remove an account from the login system, moving its associated database to the filesystem.'
110
('address', 'a', None, 'localpart@domain-format identifier of the user store to extract.'),
111
('destination', 'd', None, 'Directory into which to extract the user store.')]
113
def extractSubStore(self, localpart, domain, destinationPath):
114
siteStore = self.parent.getStore()
115
la = siteStore.findFirst(
116
userbase.LoginMethod,
117
attributes.AND(userbase.LoginMethod.localpart == localpart,
118
userbase.LoginMethod.domain == domain)).account
119
userbase.extractUserStore(la, destinationPath)
121
def postOptions(self):
122
localpart, domain = self.decodeCommandLine(self['address']).split('@', 1)
123
destinationPath = filepath.FilePath(
124
self.decodeCommandLine(self['destination'])).child(localpart + '@' + domain + '.axiom')
125
self.extractSubStore(localpart, domain, destinationPath)
127
class Insert(axiomatic.AxiomaticCommand):
129
description = 'Insert a user store, such as one extracted with "extract-user", into a site store and login system.'
131
('userstore', 'u', None, 'Path to user store to be inserted.')
134
def postOptions(self):
135
userbase.insertUserStore(self.parent.getStore(),
136
filepath.FilePath(self.decodeCommandLine(self['userstore'])))