|
|
|
import os
|
|
|
|
import random
|
|
|
|
import string
|
|
|
|
import tempfile
|
|
|
|
import subprocess # noqa: S404
|
|
|
|
from typing import Set
|
|
|
|
from pathlib import Path
|
|
|
|
from datetime import datetime
|
|
|
|
from dataclasses import field, dataclass
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class ElabUser:
|
|
|
|
name: str
|
|
|
|
group: str
|
|
|
|
write_acl: Set = field(default_factory=set)
|
|
|
|
read_acl: Set = field(default_factory=set)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
"""return a string representation"""
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
def set_new_password(self, htpasswd_path, length=10, handler=subprocess):
|
|
|
|
"""sets a new random password for a user"""
|
|
|
|
characters = string.ascii_letters + string.digits
|
|
|
|
password = "".join(
|
|
|
|
random.choice(characters) for i in range(length) # noqa: S311
|
|
|
|
)
|
|
|
|
handler.check_call(
|
|
|
|
["htpasswd", "-b", htpasswd_path, self.name, password]
|
|
|
|
)
|
|
|
|
return password
|
|
|
|
|
|
|
|
def delete_password(self, htpasswd_path, handler=subprocess):
|
|
|
|
"""deletes a password for a user"""
|
|
|
|
# if the user was not added to the password db, the removal will show
|
|
|
|
# an error message that is confusing to the user - at least it
|
|
|
|
# confused me - so redirect this to /dev/null
|
|
|
|
with open(os.devnull, "wb") as devnull:
|
|
|
|
handler.check_call(
|
|
|
|
["htpasswd", "-D", htpasswd_path, self.name], stderr=devnull
|
|
|
|
)
|
|
|
|
|
|
|
|
def create_new_repository(self, data_dir, handler=subprocess):
|
|
|
|
"""creates a repository for a user and checks in some stuff"""
|
|
|
|
# create the new repository
|
|
|
|
data_dir = Path(data_dir)
|
|
|
|
new_repo = data_dir / self.name
|
|
|
|
handler.check_call(
|
|
|
|
["svnadmin", "create", str(new_repo)], stderr=handler.STDOUT
|
|
|
|
)
|
|
|
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
|
tmpdir = Path(tmpdir)
|
|
|
|
# check out a temporary working copy
|
|
|
|
handler.check_call(
|
|
|
|
["svn", "checkout", f"file://{new_repo}", str(tmpdir)]
|
|
|
|
)
|
|
|
|
# create subfolders
|
|
|
|
today = datetime.now()
|
|
|
|
year_path = tmpdir / f"{today.year:0>4}"
|
|
|
|
year_path.mkdir()
|
|
|
|
for month in range(today.month, 13):
|
|
|
|
month_path = year_path / f"{month:0>2}"
|
|
|
|
month_path.mkdir()
|
|
|
|
handler.check_call(["touch", str(month_path / ".empty")])
|
|
|
|
# copy some examples
|
|
|
|
for temp in ("experiment", "synthesis", "toc"):
|
|
|
|
filename = f"template-{temp}.doc"
|
|
|
|
in_file = data_dir / filename
|
|
|
|
out_file = tmpdir / filename
|
|
|
|
handler.check_call(["cp", str(in_file), str(out_file)])
|
|
|
|
# add and commit the changes
|
|
|
|
handler.check_call(
|
|
|
|
["svn", "add", "--force", str(tmpdir) + "/"] # noqa: S604
|
|
|
|
)
|
|
|
|
handler.check_call(
|
|
|
|
["svn", "commit", "-m", f"New User: {self.name}", str(tmpdir)]
|
|
|
|
)
|