Skip to content

Instantly share code, notes, and snippets.

@Epicpkmn11
Last active October 26, 2023 08:06
Show Gist options
  • Save Epicpkmn11/df4623f79c0d4aefb6b0b2506d71f614 to your computer and use it in GitHub Desktop.
Save Epicpkmn11/df4623f79c0d4aefb6b0b2506d71f614 to your computer and use it in GitHub Desktop.
concom.py - Creates a vCard from a CSV
#!/usr/bin/env python3
# SPDX-License-Identifier: CC0-1.0
# SPDX-FileContributer: Pk11, 2023
# Source: https://gist.github.com/Epicpkmn11/df4623f79c0d4aefb6b0b2506d71f614
from argparse import ArgumentParser, FileType
from datetime import datetime
import csv
import re
class vcard:
first_name = ""
last_name = ""
address = None
email = None
cell_phone = None
home_phone = None
discord = None
role = None
note = None
def set_name(self, first, last):
self.first_name = first
self.last_name = last
def set_email(self, email):
if email:
self.email = email
def set_address(self, address):
# Parse address in format:
# [STREET], [CITY] [STATE (2 letter)] [ZIP(+4)]
addresses = re.findall(r"(.*) *, +(.*?),? +([A-Z]{2}) +(\d{5}(?:-\d{4})?)", address)
if len(addresses):
addr = addresses[0]
self.address = f";;{addr[0]};{addr[1]};{addr[2]};{addr[3]};United States"
def set_phone(self, phone):
# Parse phone number in format:
# XXX-XXX-XXXX (type)
# If type left out, assume cell
phones = re.findall(r"(\d{3}-\d{3}-\d{4})(?: \((\w+)\))?", phone)
for phone in phones:
if phone[1] == "home":
self.home_phone = phone[0]
else:
self.cell_phone = phone[0]
def set_discord(self, discord):
# This column is set up as a yes/no with the
# username sometimes in parenthesis.
# Discord usernames are no more than 32 chars long
# and either a-z 0-9 . and _ or anything followed by #XXXX.
usernames = re.findall(r"Yes \(([a-z0-9._]{1,32}|.{1,32}#\d{4})\)", discord)
if len(usernames):
self.discord = usernames[0].replace("#", "%23")
def set_role(self, role):
if role:
self.role = role
def set_notes(self, notes):
# Remove any empty string notes, join together with double newlines,
# then escape all newlines
self.note = "\n\n".join([note for note in notes if note]).replace("\n", "\\n")
def to_string(self):
out = [
"BEGIN:VCARD",
"VERSION:2.1",
"ORG:MNStF;Concom",
"REV:" + datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"),
f"N:{self.last_name};{self.first_name};;;",
"FN:" + f"{self.first_name} {self.last_name}".strip()
]
if self.address:
out.append("ADR;HOME:" + self.address)
if self.email:
out.append("EMAIL:" + self.email)
if self.cell_phone:
out.append("TEL;CELL:" + self.cell_phone)
if self.home_phone:
out.append("TEL;HOME:" + self.home_phone)
if self.discord:
out.append("IMPP:discord:" + self.discord)
if self.role:
out.append("ROLE:" + self.role)
if self.note:
out.append("NOTE:" + self.note)
out.append("END:VCARD")
return "\n".join(out)
def main():
parser = ArgumentParser(description="Creates a vCard from a CSV")
parser.add_argument("input", metavar="input.csv", type=FileType("r"), help="CSV file")
parser.add_argument("output", metavar="output.vcf", type=str, help="vCard file")
args = parser.parse_args()
people = []
reader = csv.DictReader(args.input, delimiter=",", quotechar="\"")
for row in reader:
person = vcard()
person.set_name(row["First name"], row["Last name"])
person.set_email(row["E-mail"])
person.set_address(row["Postal"])
person.set_phone(row["Phone"])
person.set_discord(row["Discord?"])
person.set_role(row["Role(s)"])
person.set_notes([row["Phone comments"], row["Additional"]])
people.append(person)
with open(args.output, "w") as outfile:
outfile.write("\n\n".join([person.to_string() for person in people]))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment