commit 79dac3aa1a7b50ff2fcc410d15cc7760aae4f328 Author: vuko Date: Sun May 10 12:05:18 2020 +0200 adding initial version diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..0e05552 --- /dev/null +++ b/README.rst @@ -0,0 +1,19 @@ +hsldap2vcard +============ + +hsldap2vcard is a script for creating vCard_ contact files from +`Warsaw Hackerspace`_ LDAP membership database. + +.. _vCard: https://tools.ietf.org/html/rfc6350 +.. _Warsaw Hackerspace: https://hackerspace.pl + +Usage +----- + +.. code:: bash + + # create output directory + mkdir -p ~/.contacts/hs/ + + # create vCard files: + hsldap2vcard ~/.contacts/hs/ diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..113f718 --- /dev/null +++ b/default.nix @@ -0,0 +1,11 @@ +{ pkgs ? import {} }: + +pkgs.python3Packages.buildPythonPackage { + pname = "hsldap2vcard"; + version = "1.0"; + + src = ./.; + + propagatedBuildInputs = with pkgs; [ python3Packages.ldap ]; +} + diff --git a/hsldap2vcard/__init__.py b/hsldap2vcard/__init__.py new file mode 100644 index 0000000..6701a4f --- /dev/null +++ b/hsldap2vcard/__init__.py @@ -0,0 +1,121 @@ +import argparse +import re +import datetime +import getpass +import subprocess +import ldap +import sys +from pathlib import Path + + +def normalize_mobile(mobile): + mobile = mobile.replace(" ", "").replace("-", "") + if re.fullmatch("^[0-9]{9}$", mobile): + mobile = f"+48{mobile}" + elif re.fullmatch("^[0-9]{11}$", mobile): + mobile = f"+{mobile}" + elif re.fullmatch("^\+[0-9]*$", mobile): + pass + elif uid == "daz": + pass + else: + raise ValueError("invalid moble: {mobile}") + + +class HsLdap: + def __init__(self, uid, password): + if password is None: + pw = getpass.getpass(prompt="LDAP password:") + else: + pw = str(password) + + me = "uid={:s},ou=People,dc=hackerspace,dc=pl".format(str(uid)) + + self.l = ldap.initialize("ldap://hackerspace.pl") + self.l.simple_bind_s(me, pw) + + def get_vcards(self): + members = [] + filterstr = "(objectClass=hsMember)" + space = self.l.search_s( + "ou=People,dc=hackerspace,dc=pl", + ldap.SCOPE_ONELEVEL, + filterstr=filterstr, + attrlist=["givenName", "sn", "uid", "mobile"], + ) + + for ui, s in space: + + def get(name, default=None): + if name in s: + return s[name][0].decode() + else: + return default + + uid = get("uid") + name = get("givenName", "") + sn = get("sn", "") + mobile = get("mobile") + rev = datetime.datetime.now().strftime("%Y%d%mT%H%M%SZ") + + vcard = [] + vcard.extend( + [ + "BEGIN:VCARD", + "VERSION:4.0", + f"UID:mailto:{uid}@hackerspace.pl", + "CATEGORIES:hswaw", + f"FN:{uid}", + f"NICK:{uid}", + f"N:{uid};{name};{sn}", + f"REV:{rev}", + ] + ) + + if "mobile" in s and uid != "daz": + assert len(s["mobile"]) == 1 + mobile = get("mobile") + mobile = normalize_mobile(get("mobile")) + vcard.append(f"TEL;TYPE=cell:{mobile}") + + vcard.extend(["END:VCARD"]) + yield uid, "\n".join(vcard) + + +def run(): + parser = argparse.ArgumentParser() + parser.add_argument("output", type=Path, help="vcards output directory") + parser.add_argument( + "--ldap-user", default=getpass.getuser(), help="hs ldap username" + ) + parser.add_argument("--ldap-pass", default=None, help="hs ldap password") + + args = parser.parse_args() + + if not args.output.exists(): + print("ERROR: output directory does not exist", file=sys.stderr) + exit(1) + + if not args.output.is_dir(): + print("ERROR: output argument must be a directory", file=sys.stderr) + exit(1) + + try: + l = HsLdap( + args.ldap_user, + args.ldap_pass or getpass.getpass(f"LDAP password for {args.ldap_user}: "), + ) + except ldap.INVALID_CREDENTIALS: + print("ERROR: authorization error", file=sys.stderr) + exit(1) + + written = 0 + for uid, vcard in l.get_vcards(): + args.output.joinpath(f"{uid}.vcf").write_text(vcard) + written += 1 + + print(f'Written {written} vcards files into "{args.output}"', file=sys.stderr) + + +if __name__ == "__main__": + run() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0e957eb --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +from setuptools import setup + +setup( + name="hsldap2vcard", + version="1.0", + description="create vCard's from Warsaw Hackerspace LDAP", + author="Jan Wiśniewski", + author_email="vuko@hackerspace.pl", + classifiers=[ + "License :: OSI Approved :: zlib/libpng License", + "Programming Language :: Python :: 3.7", + ], + packages=["hsldap2vcard"], + python_requires=">=3.6,", + install_requires=["python-ldap"], + entry_points={ + "console_scripts": [ + "hsldap2vcard=hsldap2vcard:run", + ] + }, +) diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..ec6651f --- /dev/null +++ b/shell.nix @@ -0,0 +1,16 @@ +{ pkgs ? import {} }: + +let + device = import ./ext/pydevice { pkgs = pkgs; }; + python3 = pkgs.python3Full.withPackages (pp: with pp; [ + ldap + pyyaml + ipython + bpython + ]); +in pkgs.mkShell { + buildInputs = [ + python3 + ]; +} +