From a418b8af81ec1653f35b864df41b54e1995c551a Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Fri, 14 Apr 2017 15:19:34 +0300 Subject: create_user improvements --- machammer/functions.py | 2 ++ machammer/users.py | 74 +++++++++++++++++++++++++++++++++++++------------- tests.py | 17 ++++++++++++ 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/machammer/functions.py b/machammer/functions.py index 6600118..b45a520 100644 --- a/machammer/functions.py +++ b/machammer/functions.py @@ -29,6 +29,7 @@ def call(*args): > call('ls', '/Users') """ + args = [str(x) for x in args] subprocess.call(args) @@ -48,6 +49,7 @@ def popen(cmd, input=None): def check_output(*args): """Shortcut for subprocess.check_output.""" + args = [str(x) for x in args] result = subprocess.check_output(args).strip() if len(result) < 1: diff --git a/machammer/users.py b/machammer/users.py index a64691a..0066454 100644 --- a/machammer/users.py +++ b/machammer/users.py @@ -1,11 +1,31 @@ # -*- coding: utf-8 -*- """machammer.users.""" +import re import os +import logging import plistlib import subprocess -from .functions import tell_app +from .functions import tell_app, check_output, call + + +def dscl(*args): + """Shortcut for accessing the local DS.""" + return check_output('/usr/bin/dscl', '.', *args) + + +def get_info(username): + path = '/Users/' + username + s = check_output('/usr/bin/dscl', '-plist', '.', 'read', path) + return plistlib.readPlistFromString(s) + + +def nextid(node='/Users', attr='UniqueID'): + """Return next available ID for DS node/attribute.""" + s = dscl('-list', node, attr) + ids = re.split(r'\s+', s)[1::2] + return max([int(x) for x in ids]) + 1 def add_login_item(path, name=None, hidden=True): @@ -14,8 +34,8 @@ def add_login_item(path, name=None, hidden=True): name = os.path.basename(path) hidden = 'true' if hidden else 'false' - tell_app('System Events', - 'make login item at end with properties {path:"%s", hidden:%s, name:"%s"}' % (path, hidden, name)) + cmd = 'make login item at end with properties {path:"%s", hidden:%s, name:"%s"}' + tell_app('System Events', cmd % (path, hidden, name)) def remove_login_item(**kwargs): @@ -30,23 +50,39 @@ def remove_login_item(**kwargs): tell_app('System Events', 'delete every login item whose %s is "%s"' % (k, v)) -def create_user(username, realname, password): +def create_user(realname, password, username=None, uid=None, gid=20): """Create a user account.""" - os.system("""dscl . create /Users/{0} - dscl . create /Users/{0} RealName "{1}" - dscl . passwd /Users/{0} {2} - dscl . create /Users/{0} UniqueID 501 - dscl . create /Users/{0} PrimaryGroupID 80 - dscl . create /Users/{0} UserShell /bin/bash - dscl . create /Users/{0} NFSHomeDirectory /Users/{0} - cp -R /System/Library/User\ Template/English.lproj /Users/{0} - chown -R {0}:staff /Users/{0}""".format(username, realname, password)) + if uid is None: + uid = nextid() + + if gid is None: + gid = nextid('/Groups', 'PrimaryGroupID') + + if username is None: + username = realname.lower().replace(' ', '.') + + path = '/Users/' + username + dscl('create', path) + dscl('create', path, 'RealName', realname) + dscl('create', path, 'UniqueID', uid) + dscl('create', path, 'PrimaryGroupID', gid) + dscl('create', path, 'UserShell', '/bin/bash') + dscl('create', path, 'NFSHomeDirectory', path) + + dscl('passwd', path, password) + + template = '/System/Library/User Template/' + call('/usr/bin/ditto', template + 'English.lproj/', path) + call('/usr/bin/ditto', template + 'Non_localized/', path) + call('/usr/sbin/chown', '-R', username + ':staff', path) + + return get_info(username) def hide_user(username, hide_home=True): """Hide a user account.""" path = '/Users/%s' % username - subprocess.call(['dscl', '.', 'create', path, 'IsHidden', '1']) + dscl('create', path, 'IsHidden', '1') if hide_home: subprocess.call(['/usr/bin/chflags', 'hidden', path]) @@ -55,16 +91,16 @@ def hide_user(username, hide_home=True): def delete_user(username, delete_home=True): """Delete a user account.""" path = '/Users/' + username - dscl = subprocess.check_output(['dscl', '-plist', '.', 'read', path]) - userinfo = plistlib.readPlistFromString(dscl) + userinfo = get_info(username) - subprocess.call(['dscl', '.', 'delete', path]) + dscl('delete', path) if delete_home: homedir = userinfo['dsAttrTypeStandard:NFSHomeDirectory'][0] - os.rmdir(homedir) + logging.debug('Deleting home directory: %s' % homedir) + call('/bin/rm', '-r', homedir) def make_admin(username): """Give admin rights to username.""" - subprocess.call(['dscl', '.', '-append', '/Groups/admin', 'users', username]) + dscl('-append', '/Groups/admin', 'users', username) diff --git a/tests.py b/tests.py index ef606ae..f990f81 100755 --- a/tests.py +++ b/tests.py @@ -13,6 +13,23 @@ from machammer import (functions, system_profiler, printers, process,) +class UsersTestCase(TestCase): + def test_nextid(self): + self.assertGreater(users.nextid(), 1) + + def test_create(self): + info = users.create_user('Test User', 'testpassword') + rn = info['dsAttrTypeStandard:RecordName'][0] + self.assertEquals(rn, 'test.user') + + def test_make_admin(self): + users.make_admin('test.user') + + def test_delete(self): + users.create_user('Test User', 'testpassword') + users.delete_user('test.user') + + class PrintersTestCase(TestCase): def test_delete_printers(self): printers.delete_printers() -- cgit v1.2.3