diff --git a/elab_users/authz.py b/elab_users/authz.py index 1be9963..7dfeb04 100644 --- a/elab_users/authz.py +++ b/elab_users/authz.py @@ -118,19 +118,16 @@ class AuthzConfigParser(configparser.ConfigParser): elabs = (item for item in self.sections() if item.endswith(SVN_SUFFIX)) for elab in elabs: for (user_or_group, acl) in self.items(elab): - print(elab, "-", user_or_group, "-", acl) if user_or_group in self.elab_users: # a nicer name for the lab journal belongs_to = elab[: -len(SVN_SUFFIX)] # a acl entry for a user if acl.lower() == WRITE_ACL: - self.elab_users[user_or_group].write_acl.append( + self.elab_users[user_or_group].write_acl.add( belongs_to ) elif acl.lower() == READ_ACL: - self.elab_users[user_or_group].read_acl.append( - belongs_to - ) + self.elab_users[user_or_group].read_acl.add(belongs_to) def group_users(self): """uses the list of users to group them by their group name""" @@ -150,7 +147,7 @@ class AuthzConfigParser(configparser.ConfigParser): self.add_section(journal_path) self.set(journal_path, username, WRITE_ACL) for group, acl in GROUP_DEFAULTS.items(): - self.set(journal_path, "@" + group, acl) + self.set(journal_path, f"@{group}", acl) self._update_user_group_config() return self.elab_users[username] @@ -162,6 +159,8 @@ class AuthzConfigParser(configparser.ConfigParser): self.remove_option(access_to + SVN_SUFFIX, user.name) for access_to in user.read_acl: self.remove_option(access_to + SVN_SUFFIX, user.name) + user.write_acl = set() + user.read_acl = set() self._update_user_group_config() return user diff --git a/elab_users/users.py b/elab_users/users.py index 561c1af..1a83c77 100644 --- a/elab_users/users.py +++ b/elab_users/users.py @@ -3,17 +3,18 @@ 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 dataclass +from dataclasses import field, dataclass @dataclass class ElabUser: name: str group: str - write_acl = [] - read_acl = [] + write_acl: Set = field(default_factory=set) + read_acl: Set = field(default_factory=set) def __str__(self): """return a string representation""" @@ -43,16 +44,17 @@ class ElabUser: 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", new_repo], stderr=handler.STDOUT + ["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}", tmpdir] + ["svn", "checkout", f"file://{new_repo}", str(tmpdir)] ) # create subfolders today = datetime.now() @@ -61,17 +63,17 @@ class ElabUser: for month in range(today.month, 13): month_path = year_path / f"{month:0>2}" month_path.mkdir() - handler.check_call(["touch", month_path / ".empty"]) + 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", in_file, out_file]) + handler.check_call(["cp", str(in_file), str(out_file)]) # add and commit the changes handler.check_call( - "svn", "add", tmpdir / "*", shell=True # noqa: S604 + ["svn", "add", str(tmpdir / "*")], shell=True # noqa: S604 ) handler.check_call( - ["svn", "commit", "-m", f"New User: {self.name}", tmpdir] + ["svn", "commit", "-m", f"New User: {self.name}", str(tmpdir)] ) diff --git a/test-data/authz b/test-data/authz index b25f3b9..b862eec 100644 --- a/test-data/authz +++ b/test-data/authz @@ -4,845 +4,29 @@ alumni = AlexeyKopyshev, AndreasBoenisch, AndreasEver, AnkeWoerz, AnneLoesche, A users = AlexanderDietz, AliciaMalekLuz, AndreasMader, AnnaSchuler, AnneBuderer, ChristophScheibelein, CrispinAmiriNaini, DanielaMoessner, DavidBoschert, DavidSchwaerzle, EstherRiga, FrankScherag, FranziskaDorner, GregorOsterwinter, HeidiPerez, HolgerFrey, JanNiklasSchoenberg, JonGreen, KarenLienkamp, KatyaSergeeva, LauraHerrera, MalwinaPajestka, MaraFlorea, MarcZinggeler, MarcelHoffmann, MarcelRothfelder, MartinKoerner, MartinSchoenstein, MatthiasMenzel, MelanieEichhorn, MichaelHenze, MonikaKurowska, MostafaMahmoud, NataliaSchatz, NicoleBirsner, NilsKorf, PengZou, PetraHettich, PhilipKotrade, RaduCristianMutihac, RomanErath, SamarKazan, SaschaEngel, SebastianBonaus, ShararehSahneh, SureshReddyBanda, ThananthornKanokwijitsilp, ThomasBrandstetter, TianyangZheng, VanessaWeiss, VitaliyKondrashov, WibkeHartleb, XiaoqiangHou, ZhuolingDeng restricted = BeniPrasser, JuliaSaar, SimonZunker, UrmilShah, YongZhou -[cpi:/] -@administrators= r -@users = r -@restricted = -@alumni = - [AlexanderDietz:/] -@administrators= rw +@administrators = rw @users = r -@restricted = -@alumni = -AlexanderDietz= rw +@restricted = +@alumni = +AlexanderDietz = rw [AlexeyKopyshev:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[AliciaMalekLuz:/] -@administrators= rw -@users = r -@restricted = -@alumni = -AliciaMalekLuz= r - -[AndreasBoenisch:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[AndreasEver:/] -@administrators= rw +@administrators = rw @users = r -@restricted = -@alumni = +@restricted = +@alumni = [AndreasEvers:/] -@administrators= rw -@users = r -@restricted = -@alumni = -UrmilShah = r - -[AndreasMader:/] -@administrators= rw -@users = r -@restricted = -@alumni = -AndreasMader= r - -[AnkeWoerz:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[AnnaSchuler:/] -@administrators= rw -@users = r -@restricted = -@alumni = -AnnaSchuler= r - -[AnneBuderer:/] -@administrators= rw -@users = r -@restricted = -@alumni = -AnneBuderer= r - -[AnneLoesche:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[AnselmHoppmann:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[ArthurMartens:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[ArulGeetha:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[BeniPrasser:/] -@administrators= rw -@users = r -@restricted = -@alumni = -BeniPrasser= r - -[CamillaOestevold:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[CanerKaganaslan:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[ChristianSchuh:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[ChristineBunte:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[ChristophScheibelein:/] -@administrators= rw -@users = r -@restricted = -@alumni = -ChristophScheibelein= r - -[CkPandiyarajan:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[CleoStannard:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[CrispinAmiriNaini:/] -@administrators= rw -@users = -@restricted = -@alumni = -CrispinAmiriNaini= r - -[DanielaMoessner:/] -@administrators= rw -@users = r -@restricted = -@alumni = -DanielaMoessner= r - -[DavidBoschert:/] -@administrators= rw -@users = r -@restricted = -@alumni = -DavidBoschert= r - -[DavidSchwaerzle:/] -@administrators= rw -@users = r -@restricted = -@alumni = -DavidSchwaerzle= r - -[DennisTrenkle:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[DingdingHe:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[EstherRiga:/] -@administrators= rw -@users = r -@restricted = -@alumni = -EstherRiga= r - -[FanWu:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[FrankScherag:/] -@administrators= rw -@users = r -@restricted = -@alumni = -FrankScherag= r - -[FranziskaDorner:/] -@administrators= rw -@users = r -@restricted = -@alumni = -FranziskaDorner= r - -[GerhardBaaken:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[GinoRodriguez:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[GregorOsterwinter:/] -@administrators= rw -@users = r -@restricted = -@alumni = -GregorOsterwinter= r - -[GuillermoBenites:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[HeidiPerez:/] -@administrators= rw -@users = r -@restricted = -@alumni = -HeidiPerez= r - -[HeikeHaller:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[HolgerFrey:/] -@administrators= rw +@administrators = rw @users = r -@restricted = -@alumni = +@restricted = +@alumni = UrmilShah = r -HolgerFrey= rw - -[IrenaEipert:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[JacobBelardi:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[JanNiklasSchoenberg:/] -@administrators= rw -@users = r -@restricted = -@alumni = -JanNiklasSchoenberg= r - -[JenniferPfau:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[JoachimLauterwasser:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[JohannesBaader:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[JonGreen:/] -@administrators= rw -@users = r -@restricted = -@alumni = -JonGreen= r - -[JonasGroten:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[JuergenRuehe:/] -@administrators= rw -@users = -@restricted = -@alumni = -JuergenRuehe= r - -[JuliaSaar:/] -@administrators= rw -@users = r -@restricted = -@alumni = -JuliaSaar= r - -[KarenLienkamp:/] -@administrators= rw -@users = r -@restricted = -@alumni = -KarenLienkamp= r - -[KatrinMoosmann:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[KatyaSergeeva:/] -@administrators= rw -@users = r -@restricted = -@alumni = -KatyaSergeeva= r - -[KeLi:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[KerstinSchuh:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[KimberlySimancas:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[LauraHerrera:/] -@administrators= rw -@users = r -@restricted = -@alumni = -LauraHerrera= r - -[MalwinaPajestka:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MalwinaPajestka= r - -[MaraFlorea:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MaraFlorea= r - -[MarcZinggeler:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MarcZinggeler= r - -[MarcelHoffmann:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MarcelHoffmann= r - -[MarcelRothfelder:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MarcelRothfelder= r - -[MarcoArmbruster:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MariaVoehringer:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MartinKoerner:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MartinKoerner= r - -[MartinMarazita:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MartinRendl:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MartinSchoenstein:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MartinSchoenstein= r - -[MartinVellinger:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MartinaAuerswald:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MatthiasLischka:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MatthiasMenzel:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MatthiasMenzel= r - -[MaxMustermann:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MelanieEichhorn:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MelanieEichhorn= r - -[MessRechner:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MichaelHenze:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MichaelHenze= r - -[MichaelaFrase:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MiriamScheckenbach:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MonicaPerez:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[MonikaKurowska:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MonikaKurowska= r - -[MostafaMahmoud:/] -@administrators= rw -@users = r -@restricted = -@alumni = -MostafaMahmoud= r - -[NataliaSchatz:/] -@administrators= rw -@users = r -@restricted = -@alumni = -NataliaSchatz= r - -[NicolasSchorr:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[NicoleBirsner:/] -@administrators= rw -@users = r -@restricted = -@alumni = -NicoleBirsner= r - -[NilsKorf:/] -@administrators= rw -@users = r -@restricted = -@alumni = -NilsKorf= r - -[NinoLomadze:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[Nongluck:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[OliverDornfeld:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[OswaldPrucker:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[PengZou:/] -@administrators= rw -@users = r -@restricted = -@alumni = -PengZou= r - -[PeterZahn:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[PetraHettich:/] -@administrators= rw -@users = r -@restricted = -@alumni = -PetraHettich= r - -[PhilipKotrade:/] -@administrators= rw -@users = r -@restricted = -@alumni = -PhilipKotrade= r - -[PhilippDiefenthaler:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[RaduCristianMutihac:/] -@administrators= rw -@users = r -@restricted = -@alumni = -RaduCristianMutihac= r - -[RebeccaBlell:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[RodrigoNavarro:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[RomanErath:/] -@administrators= rw -@users = r -@restricted = -@alumni = -RomanErath= r - -[SamarKazan:/] -@administrators= rw -@users = r -@restricted = -@alumni = -SamarKazan= r - -[SaraFuchs:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[SaschaEngel:/] -@administrators= rw -@users = r -@restricted = -@alumni = -SaschaEngel= r - -[SebastianBoehmer:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[SebastianBonaus:/] -@administrators= rw -@users = r -@restricted = -@alumni = -SebastianBonaus= r - -[ShararehSahneh:/] -@administrators= rw -@users = r -@restricted = -@alumni = -ShararehSahneh= r - -[SimonBodendorfer:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[SimonEbner:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[SimonSchuster:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[SimonZunker:/] -@administrators= rw -@users = r -@restricted = -@alumni = -SimonZunker= r - -[SirasaYodmongkol:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[SureshReddyBanda:/] -@administrators= rw -@users = r -@restricted = -@alumni = -SureshReddyBanda= r - -[ThananthornKanokwijitsilp:/] -@administrators= rw -@users = r -@restricted = -@alumni = -ThananthornKanokwijitsilp= r - -[ThidaratWangkam:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[ThomasBrandstetter:/] -@administrators= rw -@users = r -@restricted = -@alumni = -ThomasBrandstetter= r - -[TianyangZheng:/] -@administrators= rw -@users = r -@restricted = -@alumni = -TianyangZheng= r - -[TobiasHeitzler:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[TobiasKoenig:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[TristanBourrel:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[UlrikeRiehle:/] -@administrators= rw -@users = r -@restricted = -@alumni = [UrmilShah:/] -@administrators= rw -@users = r -@restricted = -@alumni = -UrmilShah= r - -[VanessaWeiss:/] -@administrators= rw -@users = r -@restricted = -@alumni = -VanessaWeiss= r - -[ViVek:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[VinicioCarias:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[VitaliyKondrashov:/] -@administrators= rw -@users = r -@restricted = -@alumni = -VitaliyKondrashov= r -SimonZunker = r - -[WibkeHartleb:/] -@administrators= rw -@users = r -@restricted = -@alumni = -WibkeHartleb= r - -[WolfgangEhm:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[XiaoqiangHou:/] -@administrators= rw -@users = r -@restricted = -@alumni = -XiaoqiangHou= r - -[YnSekhar:/] -@administrators= rw -@users = r -@restricted = -@alumni = - -[YongZhou:/] -@administrators= rw -@users = r -@restricted = -@alumni = -YongZhou= r - -[ZhuolingDeng:/] -@administrators= rw -@users = r -@restricted = -@alumni = -ZhuolingDeng= r - -[ZouStaarter:/] -@administrators= rw +@administrators = rw @users = r -@restricted = -@alumni = +@restricted = +@alumni = +UrmilShah = rw \ No newline at end of file diff --git a/test-data/htpasswd b/test-data/htpasswd index af66e5c..5ea70aa 100644 --- a/test-data/htpasswd +++ b/test-data/htpasswd @@ -1,6 +1,2 @@ -foo:$apr1$SzJRyvJU$U3luHwCA6xHfKowizE.Gl. -FOO:$apr1$LSPDdLqg$tiGbDGgNEXcRA/oyadYSw1 -AndreasEvers:$apr1$n0Oaok6e$wyHcUg6Upm9sE2AoYlVMO/ -FOOBar:$apr1$pZCbClF5$smEDwhMJIVmPsNmMEkRPd1 -FooBar:$apr1$24r9zF2e$9q30fNOqSlvn6itdhZMpc1 +AlexanderDietz:$apr1$n0Oaok6e$wyHcUg6Upm9sE2AoYlVMO/ UrmilShh:$apr1$WxMGE8Wb$H0xWao6KZGqBJoXj7fJ420 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..db5780f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,66 @@ +import shutil +import tempfile +from typing import Dict, List +from pathlib import Path +from dataclasses import dataclass + +import pytest + + +@dataclass +class StubCall: + func: str + args: List + kargs: Dict + + +class StubShell: + + STDOUT = "STDOUT" + + def __init__(self): + self.stack = [] + + def _add(self, func, args, kargs): + sc = StubCall(func, args, kargs) + self.stack.append(sc) + + def check_call(self, args, **kargs): + self._add("check_call", args, kargs) + + +@pytest.fixture +def stub_handler(): + return StubShell() + + +def temporary_data_file(src_data_dir, file_name): + source = src_data_dir / file_name + with tempfile.TemporaryDirectory() as tmpdirname: + destination = Path(tmpdirname) / file_name + shutil.copy(source, destination) + yield destination + + +@pytest.fixture +def example_data_dir(): + this_file = Path(__file__).absolute() + src_dir = this_file.parent.parent + return src_dir / "test-data" + + +@pytest.fixture +def example_authz(example_data_dir): + yield from temporary_data_file(example_data_dir, "authz") + + +@pytest.fixture +def example_htpasswd(example_data_dir): + yield from temporary_data_file(example_data_dir, "htpasswd") + + +@pytest.fixture +def example_empty_file(): + with tempfile.TemporaryDirectory() as tmpdirname: + destination = Path(tmpdirname) / "empty" + yield destination diff --git a/tests/test_elab_users_authz.py b/tests/test_elab_users_authz.py new file mode 100644 index 0000000..cf25f88 --- /dev/null +++ b/tests/test_elab_users_authz.py @@ -0,0 +1,258 @@ +import pytest + + +def read_lines(path): + with path.open("r") as fh: + content = fh.read().strip() + lines = content.splitlines() + return [line.strip() for line in lines] + + +@pytest.mark.parametrize( + "value, expected", + [ + ("no line break", "KEY = no line break"), + ("with\nline\nbreak", "KEY = with\n\tline\n\tbreak"), + ], +) +def test_authz_format_ini_option(value, expected): + from elab_users.authz import format_ini_option + + result = format_ini_option("KEY", value) + + assert result == expected + + +def test_authz_parser_init(): + import configparser + + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + + assert isinstance(parser, configparser.ConfigParser) + assert parser.elab_users == {} + assert parser.original_path is None + + +def test_authz_parser_optionxfrom(): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + + assert parser.optionxform(123) == "123" + + +def test_authz_parser_read(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + parser.read(example_authz) + + assert parser.original_path == example_authz + assert parser.elab_users != {} + + +def test_authz_parser_from_file(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + + assert isinstance(parser, AuthzConfigParser) + assert parser.original_path == example_authz + assert parser.elab_users != {} + + +def test_authz_parser_write_to_file_raises_error(): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + + with pytest.raises(IOError): + parser.write_to_file(path=None) + + +def test_authz_parser_write_to_file_uses_original_path( + example_authz, example_empty_file +): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + parser.original_path = example_empty_file + parser.write_to_file(path=None) + + assert example_empty_file.is_file() + + +def test_authz_parser_write_to_file_custom_path( + example_authz, example_empty_file +): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + parser.write_to_file(path=example_empty_file) + + assert example_empty_file.is_file() + + +def test_authz_parser_write(example_authz, example_empty_file): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + with open(example_empty_file, "w") as fh: + parser.write(fh) + + original = read_lines(example_authz) + created = read_lines(example_empty_file) + assert original == created + + +def test_authz_parser_extract_user_info_from_config(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + + super(type(parser), parser).read(example_authz) + assert parser.elab_users == {} + + parser._extract_user_info_from_config() + assert parser.elab_users != {} + + +@pytest.mark.parametrize( + "name, group", + [ + ("OswaldPrucker", "administrators"), + ("AlexanderDietz", "users"), + ("UrmilShah", "restricted"), + ("CamillaOestevold", "alumni"), + ], +) +def test_authz_parser_extract_group_definitions(name, group, example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + + super(type(parser), parser).read(example_authz) + parser._extract_group_definitions() + + user = parser.elab_users[name] + assert user.group == group + + +@pytest.mark.parametrize( + "name, read, write", + [ + ("OswaldPrucker", [], []), + ("AlexanderDietz", [], ["AlexanderDietz"]), + ("UrmilShah", ["AndreasEvers"], ["UrmilShah"]), + ], +) +def test_authz_parser_extract_individual_acls( + name, read, write, example_authz +): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser() + + super(type(parser), parser).read(example_authz) + parser._extract_group_definitions() + parser._extract_individual_acls() + + user = parser.elab_users[name] + assert user.read_acl == set(read) + assert user.write_acl == set(write) + + +def test_authz_parser_group_users(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + + groups = parser.group_users() + + assert len(groups) == 4 + assert len(groups["administrators"]) == 2 + assert len(groups["users"]) == 54 + assert len(groups["restricted"]) == 5 + assert len(groups["alumni"]) == 62 + + +def test_authz_parser_add_journal_acl_for(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + + user = parser.add_journal_acl_for("JaneDoe", "users") + + assert user.name == "JaneDoe" + assert user.group == "users" + assert parser.elab_users["JaneDoe"] == user + assert "JaneDoe:/" in parser.sections() + items = parser.items("JaneDoe:/") + assert sorted(items) == [ + ("@administrators", "rw"), + ("@alumni", ""), + ("@restricted", ""), + ("@users", "r"), + ("JaneDoe", "rw"), + ] + + +def test_authz_parser_move_user_to_alumni(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + + user = parser.move_user_to_alumni("UrmilShah") + + assert user.name == "UrmilShah" + assert user.group == "alumni" + assert user.write_acl == set() + assert user.read_acl == set() + + for group, userlist in parser.items("groups"): + if group == "alumni": + assert "UrmilShah" in userlist + else: + assert "UrmilShah" not in userlist + + +def test_authz_parser_update_user_group_config(example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + parser.elab_users["UrmilShah"].group = "alumni" + + parser._update_user_group_config() + + for group, userlist in parser.items("groups"): + if group == "alumni": + assert "UrmilShah" in userlist + else: + assert "UrmilShah" not in userlist + + +@pytest.mark.parametrize( + "elab, read, write", + [ + ("AlexeyKopyshev:/", ["@users"], ["@administrators"]), + ( + "AndreasEvers:/", + ["@users", "UrmilShah"], + ["@administrators"], + ), + ( + "UrmilShah:/", + ["@users"], + ["@administrators", "UrmilShah"], + ), + ], +) +def test_authz_parser_get_journal_info(elab, read, write, example_authz): + from elab_users.authz import AuthzConfigParser + + parser = AuthzConfigParser.from_file(example_authz) + + info = parser.get_journal_info(elab) + assert info == {"r": read, "rw": write} diff --git a/tests/test_elab_users_users.py b/tests/test_elab_users_users.py new file mode 100644 index 0000000..aac2324 --- /dev/null +++ b/tests/test_elab_users_users.py @@ -0,0 +1,104 @@ +# import pytest +from datetime import datetime + + +def test_elabuser_string_representation(): + from elab_users.users import ElabUser + + eu = ElabUser("John Doe", "Some Group") + + assert str(eu) == "John Doe" + + +def test_elabuser_set_new_password(stub_handler): + from elab_users.users import ElabUser + + eu = ElabUser("John Doe", "Some Group") + + password = eu.set_new_password("some path", 12, handler=stub_handler) + + assert len(password) == 12 + assert len(stub_handler.stack) == 1 + called = stub_handler.stack[0] + assert called.func == "check_call" + assert called.args == [ + "htpasswd", + "-b", + "some path", + "John Doe", + password, + ] + assert called.kargs == {} + + +def test_elabuser_delete_password(stub_handler): + from elab_users.users import ElabUser + + eu = ElabUser("John Doe", "Some Group") + + eu.delete_password("some path", handler=stub_handler) + + assert len(stub_handler.stack) == 1 + called = stub_handler.stack[0] + assert called.func == "check_call" + assert called.args == [ + "htpasswd", + "-D", + "some path", + "John Doe", + ] + assert list(called.kargs.keys()) == ["stderr"] + + +def test_elabuser_create_new_repo(stub_handler): + from elab_users.users import ElabUser + + eu = ElabUser("John Doe", "Some Group") + + eu.create_new_repository("some path", handler=stub_handler) + + today = datetime.now() + current_month = today.month + current_year = today.year + + assert len(stub_handler.stack) == 8 + (12 - current_month) + + called = stub_handler.stack[0] + assert called.func == "check_call" + assert called.args == ["svnadmin", "create", "some path/John Doe"] + assert called.kargs == {"stderr": stub_handler.STDOUT} + + called = stub_handler.stack[1] + assert called.func == "check_call" + assert called.args[:3] == ["svn", "checkout", "file://some path/John Doe"] + assert called.args[3].startswith("/tmp/") # noqa: S108 + assert called.kargs == {} + + called = stub_handler.stack[2] + assert called.func == "check_call" + assert called.args[0] == "touch" + assert called.args[1].startswith("/tmp/") # noqa: S108 + assert called.args[1].endswith( + f"/{current_year:0>4}/{current_month:0>2}/.empty" + ) + assert called.kargs == {} + + called = stub_handler.stack[-3] + assert called.func == "check_call" + assert called.args[0] == "cp" + assert called.args[1] == "some path/template-toc.doc" + assert called.args[2].startswith("/tmp/") # noqa: S108 + assert called.args[2].endswith("/template-toc.doc") + assert called.kargs == {} + + called = stub_handler.stack[-2] + assert called.func == "check_call" + assert called.args[:2] == ["svn", "add"] + assert called.args[2].startswith("/tmp/") # noqa: S108 + assert called.args[2].endswith("/*") + assert called.kargs == {"shell": True} + + called = stub_handler.stack[-1] + assert called.func == "check_call" + assert called.args[:4] == ["svn", "commit", "-m", "New User: John Doe"] + assert called.args[4].startswith("/tmp/") # noqa: S108