Merge pull request #28 from tildetown/rename-users
Support renaming usersfeature/enhanced-ticket-view
commit
747f1e6f17
|
@ -17,6 +17,7 @@ _Being an adminstrative tool written in Django for <https://tilde.town>_.
|
||||||
|
|
||||||
* Python 3.5+
|
* Python 3.5+
|
||||||
* PostgreSQL 9+
|
* PostgreSQL 9+
|
||||||
|
* Ubuntu or Debian
|
||||||
|
|
||||||
## Installation / setup
|
## Installation / setup
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""This script wraps the usermod command to allow user account renames via
|
||||||
|
sudoers."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def rename_user(old_username, new_username):
|
||||||
|
"""Given an old and a new username, renames user on disk with usermod.
|
||||||
|
Raises if the usermod call fails."""
|
||||||
|
args = [
|
||||||
|
'usermod',
|
||||||
|
'-l',
|
||||||
|
new_username,
|
||||||
|
'-m',
|
||||||
|
'-d',
|
||||||
|
os.path.join('/home', new_username),
|
||||||
|
old_username
|
||||||
|
]
|
||||||
|
subprocess.run(args, check=True)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
if len(argv) < 3:
|
||||||
|
print('[rename_user] Too few arguments passed.', file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
rename_user(argv[1], argv[2])
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print('[rename_user] {}'.format(e), file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
exit(main(sys.argv))
|
|
@ -14,11 +14,14 @@
|
||||||
|
|
||||||
* create ttadmin user
|
* create ttadmin user
|
||||||
* ttadmin db user (or just rely on ident..?) / database created
|
* ttadmin db user (or just rely on ident..?) / database created
|
||||||
* copy `create_keyfile.py` from `scripts/` and put it in `/opt/bin/`.
|
* copy `create_keyfile.py` from `scripts/` and put it in `/opt/bin/`.
|
||||||
* `chmod o+x /opt/bin/create_keyfile.py``
|
* copy `rename_user.py` from `scripts/` and put it in `/tilde/bin/`.
|
||||||
|
* `chmod u+x /opt/bin/create_keyfile.py``
|
||||||
* add to sudoers:
|
* add to sudoers:
|
||||||
|
|
||||||
ttadmin ALL=(ALL)NOPASSWD:/usr/sbin/adduser,/bin/mkdir,/opt/bin/create_keyfile.py
|
```
|
||||||
|
ttadmin ALL=(ALL)NOPASSWD:/usr/sbin/adduser,/bin/mkdir,/opt/bin/create_keyfile.py,/tilde/bin/rename_user.py
|
||||||
|
```
|
||||||
|
|
||||||
* have virtualenv with python 3.5+ ready, install tildetown-admin package into it
|
* have virtualenv with python 3.5+ ready, install tildetown-admin package into it
|
||||||
* run django app as wsgi container through gunicorn as the ttadmin user with venv active
|
* run django app as wsgi container through gunicorn as the ttadmin user with venv active
|
||||||
|
|
|
@ -34,6 +34,7 @@ def validate_displayname(display_name):
|
||||||
if not DISPLAY_NAME_RE.match(display_name):
|
if not DISPLAY_NAME_RE.match(display_name):
|
||||||
raise ValidationError("Valid characters: a-z, A-Z, 0-9, -, _, and '.")
|
raise ValidationError("Valid characters: a-z, A-Z, 0-9, -, _, and '.")
|
||||||
|
|
||||||
|
|
||||||
def validate_pubkey(pubkey):
|
def validate_pubkey(pubkey):
|
||||||
# TODO see if I can get the type out
|
# TODO see if I can get the type out
|
||||||
key = ssh.SSHKey(pubkey, strict_mode=False, skip_option_parsing=True)
|
key = ssh.SSHKey(pubkey, strict_mode=False, skip_option_parsing=True)
|
||||||
|
|
|
@ -152,13 +152,25 @@ class Townie(User):
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
def rename_on_disk(self, old_username):
|
||||||
|
"""Assuming that this instance has a new name set, renames this user on
|
||||||
|
disk with self.username."""
|
||||||
|
error = _guarded_run([
|
||||||
|
'sudo',
|
||||||
|
'/tilde/bin/rename_user.py',
|
||||||
|
old_username,
|
||||||
|
self.username])
|
||||||
|
if error:
|
||||||
|
logging.error(error)
|
||||||
|
return
|
||||||
|
logging.info('Renamed {} to {}'.format(old_username, self.username))
|
||||||
|
|
||||||
|
|
||||||
class Pubkey(Model):
|
class Pubkey(Model):
|
||||||
key_type = CharField(max_length=50,
|
key_type = CharField(max_length=50,
|
||||||
blank=False,
|
blank=False,
|
||||||
null=False,
|
null=False,
|
||||||
choices=SSH_TYPE_CHOICES,
|
choices=SSH_TYPE_CHOICES)
|
||||||
)
|
|
||||||
key = TextField(blank=False, null=False)
|
key = TextField(blank=False, null=False)
|
||||||
townie = ForeignKey(Townie)
|
townie = ForeignKey(Townie)
|
||||||
|
|
||||||
|
@ -188,11 +200,16 @@ def on_townie_pre_save(sender, instance, **kwargs):
|
||||||
|
|
||||||
existing = existing[0]
|
existing = existing[0]
|
||||||
|
|
||||||
if not existing.reviewed and instance.reviewed == True:
|
# See if we need to create this user on disk.
|
||||||
|
if not existing.reviewed and instance.reviewed is True:
|
||||||
instance.create_on_disk()
|
instance.create_on_disk()
|
||||||
instance.send_welcome_email()
|
instance.send_welcome_email()
|
||||||
instance.write_authorized_keys()
|
instance.write_authorized_keys()
|
||||||
|
|
||||||
|
# See if this user needs a rename on disk
|
||||||
|
if existing.username != instance.username:
|
||||||
|
instance.rename_on_disk(existing.username)
|
||||||
|
|
||||||
|
|
||||||
def _guarded_run(cmd_args, **run_args):
|
def _guarded_run(cmd_args, **run_args):
|
||||||
"""Given a list of args representing a command invocation as well as var
|
"""Given a list of args representing a command invocation as well as var
|
||||||
|
@ -213,9 +230,6 @@ def _guarded_run(cmd_args, **run_args):
|
||||||
|
|
||||||
|
|
||||||
# things to consider:
|
# things to consider:
|
||||||
# * what happens when a user wants their name changed?
|
|
||||||
# * it looks like usermod -l and a mv of the home dir can change a user's username.
|
|
||||||
# * would hook this into the pre_save signal to note a username change
|
|
||||||
# * what happens when a user is marked as not reviewed?
|
# * what happens when a user is marked as not reviewed?
|
||||||
# * does this signal user deletion? Or does literal Townie deletion signal
|
# * does this signal user deletion? Or does literal Townie deletion signal
|
||||||
# "needs to be removed from disk"? I think it makes the most sense for the
|
# "needs to be removed from disk"? I think it makes the most sense for the
|
||||||
|
@ -225,7 +239,3 @@ def _guarded_run(cmd_args, **run_args):
|
||||||
# think I can ignore it.
|
# think I can ignore it.
|
||||||
# * what happens when a user needs to be banned?
|
# * what happens when a user needs to be banned?
|
||||||
# * the Townie should be deleted via post_delete signal
|
# * the Townie should be deleted via post_delete signal
|
||||||
# * what are things about a user that might change in django and require changes on disk?
|
|
||||||
# * username
|
|
||||||
# * displayname (only if i start using this?)
|
|
||||||
# * ssh key
|
|
||||||
|
|
Loading…
Reference in New Issue