Commit | Line | Data |
---|---|---|
a2916c06 MW |
1 | ### -*-python-*- |
2 | ### | |
3 | ### Administrative commands | |
4 | ### | |
5 | ### (c) 2013 Mark Wooding | |
6 | ### | |
7 | ||
8 | ###----- Licensing notice --------------------------------------------------- | |
9 | ### | |
10 | ### This file is part of Chopwood: a password-changing service. | |
11 | ### | |
12 | ### Chopwood is free software; you can redistribute it and/or modify | |
13 | ### it under the terms of the GNU Affero General Public License as | |
14 | ### published by the Free Software Foundation; either version 3 of the | |
15 | ### License, or (at your option) any later version. | |
16 | ### | |
17 | ### Chopwood is distributed in the hope that it will be useful, | |
18 | ### but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ### GNU Affero General Public License for more details. | |
21 | ### | |
22 | ### You should have received a copy of the GNU Affero General Public | |
23 | ### License along with Chopwood; if not, see | |
24 | ### <http://www.gnu.org/licenses/>. | |
25 | ||
26 | from __future__ import with_statement | |
27 | ||
28 | import agpl as AGPL | |
29 | import cmdutil as CU | |
30 | import dbmaint as D | |
31 | from output import OUT, PRINT | |
32 | import subcommand as SC | |
33 | import util as U | |
34 | ||
35 | @SC.subcommand( | |
36 | 'listusers', ['admin'], 'List the existing users.', | |
37 | opts = [SC.Opt('service', '-s', '--service', | |
38 | 'list users with SERVICE accounts', | |
39 | argname = 'SERVICE')], | |
40 | oparams = [SC.Arg('pat')]) | |
41 | def cmd_listuser(service = None, pat = None): | |
42 | CU.format_list(CU.list_users(service, pat), | |
43 | [CU.column('USER', "~={0.user}A", 3), | |
44 | CU.column('EMAIL', "~={0.email}:[---~;~={0.email}A~]")]) | |
45 | ||
46 | @SC.subcommand( | |
47 | 'adduser', ['admin'], 'Add a user to the master database.', | |
48 | opts = [SC.Opt('email', '-e', '--email', | |
49 | "email address for the new user", | |
50 | argname = 'EMAIL')], | |
51 | params = [SC.Arg('user')]) | |
52 | def cmd_adduser(user, email = None): | |
53 | with D.DB: | |
54 | CU.check_user(user, False) | |
55 | D.DB.execute("INSERT INTO users (user, email) VALUES ($user, $email)", | |
56 | user = user, email = email) | |
57 | D.DB.execute("""INSERT INTO services (user, service) | |
58 | VALUES ($user, $service)""", | |
59 | user = user, service = 'master') | |
60 | ||
61 | @SC.subcommand( | |
62 | 'deluser', ['admin'], 'Remove USER from the master database.', | |
63 | params = [SC.Arg('user')]) | |
64 | def cmd_deluser(user, email = None): | |
65 | with D.DB: | |
66 | CU.check_user(user) | |
67 | D.DB.execute("DELETE FROM users WHERE user = $user", user = user) | |
68 | ||
69 | @SC.subcommand( | |
70 | 'edituser', ['admin'], 'Modify a user record.', | |
71 | opts = [SC.Opt('email', '-e', '--email', | |
72 | "change USER's email address", | |
73 | argname = 'EMAIL'), | |
74 | SC.Opt('noemail', '-E', '--no-email', | |
75 | "forget USER's email address"), | |
76 | SC.Opt('rename', '-r', '--rename', | |
77 | "rename USER", | |
78 | argname = 'NEW-NAME')], | |
79 | params = [SC.Arg('user')]) | |
80 | def cmd_edituser(user, email = None, noemail = False, rename = None): | |
81 | with D.DB: | |
82 | CU.check_user(user) | |
83 | if rename is not None: check_user(rename, False) | |
84 | CU.edit_records('users', 'user = $user', | |
85 | [('email', email, noemail), | |
86 | ('user', rename, False)], | |
87 | user = user) | |
88 | ||
89 | @SC.subcommand( | |
90 | 'delsvc', ['admin'], "Remove all records for SERVICE.", | |
91 | params = [SC.Arg('service')]) | |
92 | def cmd_delsvc(service): | |
93 | with D.DB: | |
94 | CU.check_service(service, must_config_p = False, must_records_p = True) | |
95 | D.DB.execute("DELETE FROM services WHERE service = $service", | |
96 | service = service) | |
97 | ||
98 | @SC.subcommand( | |
99 | 'editsvc', ['admin'], "Edit a given SERVICE.", | |
100 | opts = [SC.Opt('rename', '-r', '--rename', "rename the SERVICE", | |
101 | argname = 'NEW-NAME')], | |
102 | params = [SC.Arg('service')]) | |
103 | def cmd_editsvc(service, rename = None): | |
104 | with D.DB: | |
105 | if service == 'master': | |
106 | raise U.ExpectedError, (400, "Can't edit the master service") | |
107 | if rename is None: | |
108 | CU.check_service(service, must_config_p = True, must_records_p = True) | |
109 | else: | |
110 | CU.check_service(service, must_config_p = False, must_records_p = True) | |
111 | CU.check_service(rename, must_config_p = True, must_records_p = False) | |
112 | CU.edit_records('services', 'service = $service', | |
113 | [('service', rename, False)], | |
114 | service = service) | |
115 | ||
116 | @SC.subcommand( | |
117 | 'addacct', ['admin'], 'Add an account for a user.', | |
118 | opts = [SC.Opt('alias', '-a', '--alias', | |
119 | "alias by which USER is known to SERVICE", | |
120 | argname = 'ALIAS')], | |
121 | params = [SC.Arg('user'), SC.Arg('service')]) | |
122 | def cmd_addacct(user, service, alias = None): | |
123 | with D.DB: | |
124 | CU.check_user(user) | |
125 | CU.check_service(service) | |
126 | D.DB.execute("""SELECT 1 FROM services | |
127 | WHERE user = $user AND service = $service""", | |
128 | user = user, service = service) | |
129 | if D.DB.fetchone() is not None: | |
130 | raise U.ExpectedError, ( | |
131 | 400, "User `%s' already has `%s' account" % (user, service)) | |
132 | D.DB.execute("""INSERT INTO services (service, user, alias) | |
133 | VALUES ($service, $user, $alias)""", | |
134 | service = service, user = user, alias = alias) | |
135 | ||
136 | @SC.subcommand( | |
137 | 'delacct', ['admin'], "Remove USER's SERVICE account.", | |
138 | params = [SC.Arg('user'), SC.Arg('service')]) | |
139 | def cmd_delacct(user, service): | |
140 | with D.DB: | |
141 | CU.resolve_account(service, user) | |
142 | if service == 'master': | |
143 | raise U.ExpectedError, \ | |
144 | (400, "Can't delete master accounts: use `deluser'") | |
145 | D.DB.execute("""DELETE FROM services | |
146 | WHERE service = $service AND user = $user""", | |
147 | service = service, user = user) | |
148 | ||
149 | @SC.subcommand( | |
150 | 'editacct', ['admin'], "Modify USER's SERVICE account record.", | |
151 | opts = [SC.Opt('alias', '-a', '--alias', | |
152 | "change USER's login name for SERVICE", | |
153 | argname = 'ALIAS'), | |
154 | SC.Opt('noalias', '-A', '--no-alias', | |
155 | "use USER's master login name")], | |
156 | params = [SC.Arg('user'), SC.Arg('service')]) | |
157 | def cmd_editacct(user, service, alias = None, noalias = False): | |
158 | with D.DB: | |
159 | CU.resolve_account(service, user) | |
160 | if service == 'master': | |
161 | raise U.ExpectedError, (400, "Can't edit master accounts") | |
162 | CU.edit_records('services', 'user = $user AND service = $service', | |
163 | [('alias', alias, noalias)], | |
164 | user = user, service = service) | |
165 | ||
166 | @SC.subcommand( | |
167 | 'source', ['admin', 'userv'], """\ | |
168 | Write source code (in `.tar.gz' format) to standard output.""") | |
169 | def cmd_source_admin(): | |
170 | AGPL.source(OUT) | |
171 | ||
172 | ###----- That's all, folks -------------------------------------------------- |