From 145da4e438e8895c19969398bdc75e1a027426b8 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 21 May 2024 10:59:38 +0200 Subject: [PATCH 1/3] Add obs_api.Person.cmd_register() for registering new users --- osc/obs_api/person.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/osc/obs_api/person.py b/osc/obs_api/person.py index 54925d20..4aba536a 100644 --- a/osc/obs_api/person.py +++ b/osc/obs_api/person.py @@ -2,6 +2,7 @@ from ..util.models import * # pylint: disable=wildcard-import,unused-wildcard-i from .enums import BoolString from .person_owner import PersonOwner from .person_watchlist import PersonWatchlist +from .status import Status class Person(XmlModel): @@ -69,3 +70,45 @@ class Person(XmlModel): for node in root: result.append(cls.from_xml(node, apiurl=apiurl)) return result + + @classmethod + def cmd_register( + cls, + apiurl: str, + *, + login: str, + realname: str, + email: str, + password: str, + note: Optional[str] = None, + state: Optional[str] = "confirmed", + ): + person = UnregisteredPerson(login=login, realname=realname, email=email, password=password, note=note, state=state) + url_path = ["person"] + url_query = { + "cmd": "register", + } + response = cls.xml_request("POST", apiurl, url_path, url_query, data=person.to_string()) + return Status.from_file(response, apiurl=apiurl) + + +class UnregisteredPerson(XmlModel): + XML_TAG = "unregisteredperson" + + login: str = Field( + ) + + realname: str = Field( + ) + + email: str = Field( + ) + + password: str = Field( + ) + + note: Optional[str] = Field( + ) + + state: Optional[str] = Field( + ) From ab749fcaf522253204f790c392c69c3fb09c9341 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 21 May 2024 13:11:16 +0200 Subject: [PATCH 2/3] Add 'person register' command --- osc/commands/person.py | 12 +++++++ osc/commands/person_register.py | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 osc/commands/person.py create mode 100644 osc/commands/person_register.py diff --git a/osc/commands/person.py b/osc/commands/person.py new file mode 100644 index 00000000..b4e560c4 --- /dev/null +++ b/osc/commands/person.py @@ -0,0 +1,12 @@ +import osc.commandline + + +class PersonCommand(osc.commandline.OscCommand): + """ + Manage persons + """ + + name = "person" + + def run(self, args): + pass diff --git a/osc/commands/person_register.py b/osc/commands/person_register.py new file mode 100644 index 00000000..21ff0a1d --- /dev/null +++ b/osc/commands/person_register.py @@ -0,0 +1,58 @@ +import osc.commandline + + +class PersonRegisterCommand(osc.commandline.OscCommand): + """ + Register a new person (user) + """ + + name = "register" + parent = "PersonCommand" + + def init_arguments(self): + self.add_argument( + "--login", + required=True, + help="Login.", + ) + self.add_argument( + "--realname", + required=True, + help="Real name of the person.", + ) + self.add_argument( + "--email", + required=True, + help="Email address.", + ) + self.add_argument( + "--password", + help="Password. An interactive prompt is shown if password is not specified.", + ) + self.add_argument( + "--note", + help="Any notes about the person.", + ) + self.add_argument( + "--state", + help="State of the account. Defaults to 'unconfirmed'.", + ) + + def run(self, args): + from osc import obs_api + from osc.util.helper import raw_input + + if args.password: + password = args.password + else: + password = raw_input(f"Enter password for {args.login}@{args.apiurl}: ") + + obs_api.Person.cmd_register( + args.apiurl, + login=args.login, + realname=args.realname, + email=args.email, + password=password, + note=args.note, + state=args.state, + ) From a36c4a9f6fac3ab8a06c312e0a7ad6072f79cbea Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Tue, 21 May 2024 13:16:49 +0200 Subject: [PATCH 3/3] Add 'person search' command --- osc/commands/person_search.py | 51 +++++++++++++++++++++++++++++++++++ osc/obs_api/person.py | 13 +++++++++ 2 files changed, 64 insertions(+) create mode 100644 osc/commands/person_search.py diff --git a/osc/commands/person_search.py b/osc/commands/person_search.py new file mode 100644 index 00000000..0651978a --- /dev/null +++ b/osc/commands/person_search.py @@ -0,0 +1,51 @@ +import osc.commandline + + +class PersonSearchCommand(osc.commandline.OscCommand): + """ + Search a person (user) + """ + + name = "search" + parent = "PersonCommand" + + def init_arguments(self): + self.add_argument( + "--login", + help="Search by a login.", + ) + self.add_argument( + "--login-contains", + metavar="SUBSTR", + help="Search by a substring in a login.", + ) + self.add_argument( + "--realname-contains", + metavar="SUBSTR", + help="Search by a substring in a realname.", + ) + self.add_argument( + "--email", + help="Search by an email address.", + ) + self.add_argument( + "--email-contains", + metavar="SUBSTR", + help="Search by a substring in an email address.", + ) + + def run(self, args): + from .. import obs_api + + persons = obs_api.Person.search( + args.apiurl, + login=args.login, + login__contains=args.login_contains, + realname__contains=args.realname_contains, + email=args.email, + email__contains=args.email_contains, + ) + + for person in persons: + print(person.to_human_readable_string()) + print() diff --git a/osc/obs_api/person.py b/osc/obs_api/person.py index 4aba536a..ae4b6c51 100644 --- a/osc/obs_api/person.py +++ b/osc/obs_api/person.py @@ -33,6 +33,19 @@ class Person(XmlModel): ignore_auth_services: Optional[BoolString] = Field( ) + def to_human_readable_string(self) -> str: + """ + Render the object as a human readable string. + """ + from ..output import KeyValueTable + + table = KeyValueTable() + table.add("Login", self.login, color="bold") + table.add("Real name", self.realname) + table.add("Email", self.email) + table.add("State", self.state) + return f"{table}" + @classmethod def from_api(cls, apiurl: str, username: str): url_path = ["person", username]