Skip to content

Commit

Permalink
Merge pull request #309 from afh/afh-kind-column
Browse files Browse the repository at this point in the history
Add kind column in contact table
  • Loading branch information
lucc authored Jun 27, 2022
2 parents 8dec8e9 + cd3e2d5 commit 2791c40
Show file tree
Hide file tree
Showing 12 changed files with 62 additions and 2 deletions.
2 changes: 2 additions & 0 deletions doc/source/examples/khard.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ reverse = no
show_nicknames = no
# show uid table column: yes / no
show_uids = yes
# show kind table column: yes / no
show_kinds = no
# sort by first or last name: first_name / last_name / formatted_name
sort = last_name
# localize dates: yes / no
Expand Down
1 change: 1 addition & 0 deletions doc/source/man/khard.conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ contact table
- *reverse*: whether to reverse the order of contact listings or not
- *show_nicknames*: whether to show nick names
- *show_uids*: whether to show uids
- *show_kinds*: whether to show kinds
- *sort*: field by which to sort contact listings

vcard
Expand Down
10 changes: 10 additions & 0 deletions khard/carddav_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class VCardWrapper:
by the vobject library are enforced here.
"""

_default_kind = "individual"
_default_version = "3.0"
_supported_versions = ("3.0", "4.0")

Expand Down Expand Up @@ -448,6 +449,11 @@ def _prepare_birthday_value(self, date: Date) -> Tuple[Optional[str],
fmt = "%F"
return date.strftime(fmt), False

@property
def kind(self) -> str:
kind = self._get_string_field("kind") or self._default_kind
return kind if kind != "org" else "organisation"

@property
def formatted_name(self) -> str:
return self._get_string_field("fn")
Expand Down Expand Up @@ -1421,6 +1427,10 @@ def pretty(self, verbose: bool = True) -> str:
if verbose:
strings.append("Address book: {}".format(self.address_book))

# kind
if self.kind is not None:
strings.append("Kind: {}".format(self.kind))

# person related information
if (self.birthday is not None or self.anniversary is not None
or self.nicknames or self.roles or self.titles):
Expand Down
1 change: 1 addition & 0 deletions khard/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ def _set_attributes(self) -> None:
self.preferred_email_address_type = table['preferred_email_address_type']
self.preferred_phone_number_type = table['preferred_phone_number_type']
self.show_uids = table['show_uids']
self.show_kinds = table['show_kinds']

def init_address_books(self) -> None:
"""Initialize the internal address book collection.
Expand Down
1 change: 1 addition & 0 deletions khard/data/config.spec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ preferred_phone_number_type = string_list(default=list('pref'))
reverse = boolean(default=False)
show_nicknames = boolean(default=False)
show_uids = boolean(default=True)
show_kinds = boolean(default=False)
sort = option('first_name', 'last_name', 'formatted_name', default='first_name')

[vcard]
Expand Down
2 changes: 2 additions & 0 deletions khard/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def get_special_field(self, vcard: CarddavObject, field: str) -> str:
if vcard.emails:
return self.format_labeled_field(vcard.emails,
self._preferred_email)
if field == 'kind':
return vcard.kind
return ""

@staticmethod
Expand Down
7 changes: 6 additions & 1 deletion khard/khard.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,18 @@ def list_address_books(address_books: Union[AddressBookCollection,
def list_contacts(vcard_list: List[CarddavObject], fields: Iterable[str] = (),
parsable: bool = False) -> None:
selected_address_books: List[VdirAddressBook] = []
selected_kinds = set()
for contact in vcard_list:
if contact.address_book not in selected_address_books:
selected_address_books.append(contact.address_book)
if contact.kind not in selected_kinds:
selected_kinds.add(contact.kind)
table = []
# default table header
table_header = ["index", "name", "phone", "email"]
plural = ""
if config.show_kinds or len(selected_kinds) > 1 or CarddavObject._default_kind not in selected_kinds:
table_header.append("kind")
if len(selected_address_books) > 1:
plural = "s"
table_header.append("address_book")
Expand Down Expand Up @@ -200,7 +205,7 @@ def list_contacts(vcard_list: List[CarddavObject], fields: Iterable[str] = (),
for field in table_header:
if field == 'index':
row.append(str(index + 1))
elif field in ['name', 'phone', 'email']:
elif field in ['name', 'phone', 'email', 'kind']:
row.append(formatter.get_special_field(vcard, field))
elif field == 'uid':
if parsable:
Expand Down
7 changes: 7 additions & 0 deletions test/fixture/vcards/individual.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BEGIN:VCARD
VERSION:4.0
UID:18F098B5-7383-4FD6-B482-48F2181D73AA
N:Coyote;Wile;E.;;
FN:Wile E. Coyote
ORG:ACME Inc.;
END:VCARD
7 changes: 7 additions & 0 deletions test/fixture/vcards/org.vcf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BEGIN:VCARD
VERSION:4.0
UID:429A43AB-52F2-4714-AA62-077528A12464
KIND:org
FN:ACME Inc.
ORG:ACME Inc.;
END:VCARD
21 changes: 21 additions & 0 deletions test/test_command_line_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,27 @@ def test_postaddr_lists_only_contacts_with_post_addresses(self):
' SomeState, HomeCountry']
self.assertListEqual(expect, text)

def test_mixed_kinds(self):
with TmpConfig(["org.vcf", "individual.vcf"]):
stdout = run_main("list", "organisations:acme")
text = [line.rstrip() for line in stdout.getvalue().splitlines()]
expected = [
"Address book: tmp",
"Index Name Phone Email Kind Uid",
"1 ACME Inc. organisation 4",
"2 Wile E. Coyote individual 1"]
self.assertListEqual(expected, text)

def test_non_individual_kind(self):
with TmpConfig(["org.vcf"]):
stdout = run_main("list")
text = [line.rstrip() for line in stdout.getvalue().splitlines()]
expected = [
"Address book: tmp",
"Index Name Phone Email Kind Uid",
"1 ACME Inc. organisation 4"]
self.assertListEqual(expected, text)


class ListingCommands2(unittest.TestCase):

Expand Down
4 changes: 4 additions & 0 deletions test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ def test_show_uids_defaults_to_true(self):
c = config.Config("test/fixture/minimal.conf")
self.assertTrue(c.show_uids)

def test_show_kinds_defaults_to_false(self):
c = config.Config("test/fixture/minimal.conf")
self.assertFalse(c.show_kinds)

def test_sort_defaults_to_first_name(self):
c = config.Config("test/fixture/minimal.conf")
self.assertEqual(c.sort, 'first_name')
Expand Down
1 change: 0 additions & 1 deletion todo.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
ToDo list for khard

1. Add support for vcard attributes kind and member
- kind column in contact table
- option to filter contact table (--kind)
- member action to list all members of an organisation

Expand Down

0 comments on commit 2791c40

Please sign in to comment.