mirror of
https://github.com/KnugiHK/WhatsApp-Chat-Exporter.git
synced 2026-04-25 07:21:36 +00:00
Fix the support on grouped vCard properties (#207 )
Parse and match vCard properties that use grouping prefixes (e.g. item1.TEL) by extracting the property name correctly. Regression caused by the removal of the vobject dependency.
This commit is contained in:
@@ -66,13 +66,18 @@ def _parse_vcard_line(line: str) -> tuple[str, dict[str, str], str] | None:
|
|||||||
value = line[colon_index + 1:].strip()
|
value = line[colon_index + 1:].strip()
|
||||||
|
|
||||||
# Split property name from parameters
|
# Split property name from parameters
|
||||||
parts = prop_and_params.split(';')
|
property_part, *params = prop_and_params.split(';')
|
||||||
property_name = parts[0].upper()
|
|
||||||
|
# We only care about property name for now, but the grouping mechanism may be
|
||||||
|
# useful in the future if we want to associate multiple properties together.
|
||||||
|
parts = property_part.split('.')
|
||||||
|
_, property_name = parts if len(parts) == 2 else (None, parts[0])
|
||||||
|
property_name = property_name.upper()
|
||||||
|
|
||||||
parameters = {}
|
parameters = {}
|
||||||
for part in parts[1:]:
|
for param in params:
|
||||||
if '=' in part:
|
if '=' in param:
|
||||||
key, val = part.split('=', 1)
|
key, val = param.split('=', 1)
|
||||||
parameters[key.upper()] = val.strip('"') # Remove potential quotes from value
|
parameters[key.upper()] = val.strip('"') # Remove potential quotes from value
|
||||||
|
|
||||||
return property_name, parameters, value
|
return property_name, parameters, value
|
||||||
@@ -98,8 +103,9 @@ def get_vcard_value(entry: str, field_name: str) -> list[str]:
|
|||||||
values.append(decode_quoted_printable(cached_line + line, charset))
|
values.append(decode_quoted_printable(cached_line + line, charset))
|
||||||
cached_line = ""
|
cached_line = ""
|
||||||
else:
|
else:
|
||||||
# Skip empty lines or lines that don't start with the target field (after stripping)
|
# Skip empty lines or lines that don't start with the target
|
||||||
if not line or not line.upper().startswith(target_name):
|
# field (after stripping), considering potential grouping prefixes
|
||||||
|
if not line or (not line.upper().startswith(target_name) and f".{target_name}" not in line.upper().split(':')[0]):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
parsed = _parse_vcard_line(line)
|
parsed = _parse_vcard_line(line)
|
||||||
|
|||||||
@@ -42,3 +42,12 @@ VERSION:2.1
|
|||||||
TEL;CELL:8889990001
|
TEL;CELL:8889990001
|
||||||
ORG:AAA Car Service
|
ORG:AAA Car Service
|
||||||
END:VCARD
|
END:VCARD
|
||||||
|
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:2.1
|
||||||
|
item1.TEL;CELL:7777777778
|
||||||
|
item2.TEL;CELL:7777777779
|
||||||
|
item1.FN:Racing Team
|
||||||
|
item2.FN:Racing Team
|
||||||
|
END:VCARD
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# from contacts_names_from_vcards import readVCardsFile
|
# from contacts_names_from_vcards import readVCardsFile
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from Whatsapp_Chat_Exporter.vcards_contacts import normalize_number, read_vcards_file
|
from Whatsapp_Chat_Exporter.vcards_contacts import normalize_number, read_vcards_file, get_vcard_value
|
||||||
|
|
||||||
|
|
||||||
def test_readVCardsFile():
|
def test_readVCardsFile():
|
||||||
@@ -17,7 +17,7 @@ def test_readVCardsFile():
|
|||||||
# Print the count and the name
|
# Print the count and the name
|
||||||
print(f"{count}. {name}")
|
print(f"{count}. {name}")
|
||||||
print(data)
|
print(data)
|
||||||
assert len(data) == 6
|
assert len(data) == 8
|
||||||
# Test simple contact name
|
# Test simple contact name
|
||||||
assert data[0][1] == "Sample Contact"
|
assert data[0][1] == "Sample Contact"
|
||||||
# Test complex name
|
# Test complex name
|
||||||
@@ -30,6 +30,31 @@ def test_readVCardsFile():
|
|||||||
assert data[4][1] == "James Peacock Elementary"
|
assert data[4][1] == "James Peacock Elementary"
|
||||||
# Test business entry using ORG but not F/FN
|
# Test business entry using ORG but not F/FN
|
||||||
assert data[5][1] == "AAA Car Service"
|
assert data[5][1] == "AAA Car Service"
|
||||||
|
# Test grouped entry
|
||||||
|
assert data[6][1] == "Racing Team (1)"
|
||||||
|
assert data[7][1] == "Racing Team (2)"
|
||||||
|
|
||||||
|
|
||||||
|
def test_grouping_mechanism():
|
||||||
|
no_group_vcf = """
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:2.1
|
||||||
|
TEL;CELL:7777777778
|
||||||
|
TEL;CELL:7777777779
|
||||||
|
TEL;CELL:7777777780
|
||||||
|
ORG:Racing Team
|
||||||
|
END:VCARD"""
|
||||||
|
group_vcf = """
|
||||||
|
BEGIN:VCARD
|
||||||
|
VERSION:2.1
|
||||||
|
item1.TEL;CELL:7777777778
|
||||||
|
item2.TEL;CELL:7777777779
|
||||||
|
item3.TEL;CELL:7777777780
|
||||||
|
ORG:Racing Team
|
||||||
|
END:VCARD"""
|
||||||
|
assert get_vcard_value(no_group_vcf, "TEL") == ["7777777778", "7777777779", "7777777780"]
|
||||||
|
assert get_vcard_value(group_vcf, "TEL") == ["7777777778", "7777777779", "7777777780"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_number_to_name_dicts():
|
def test_create_number_to_name_dicts():
|
||||||
|
|||||||
Reference in New Issue
Block a user