Skip to content

Commit 0c779c5

Browse files
authored
Merge pull request #25 from AfricasVoices/fetch-contacts
Fetch contacts
2 parents ea079d1 + 42352e3 commit 0c779c5

File tree

5 files changed

+275
-0
lines changed

5 files changed

+275
-0
lines changed

fetch_contacts/Dockerfile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FROM python:3.6-slim
2+
3+
# Install the tools we need.
4+
RUN apt-get update && apt-get install -y git
5+
RUN pip install pipenv
6+
7+
# Set working directory
8+
WORKDIR /app
9+
10+
# Install project dependencies.
11+
ADD Pipfile.lock /app
12+
ADD Pipfile /app
13+
RUN pipenv sync
14+
15+
# Copy the rest of the project
16+
ADD fetch_contacts.py /app
17+
18+
# Make a directory for intermediate data
19+
RUN mkdir /data
20+
21+
# Environment variables need to be set when constructing this container e.g. via
22+
# docker run or docker container create. Use docker-run.sh to set these automatically.
23+
CMD pipenv run python fetch_contacts.py --server "$SERVER" "$TOKEN" "$USER" /data/phone-uuid-table.json /data/output.json

fetch_contacts/Pipfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[[source]]
2+
url = "https://pypi.org/simple"
3+
verify_ssl = true
4+
name = "pypi"
5+
6+
[packages]
7+
rapidpro-python = ">=2.4"
8+
CoreDataModules = {git = "https://www.github.com/AfricasVoices/CoreDataModules", editable = true, ref = "v0.5.3"}
9+
10+
[dev-packages]
11+
12+
[requires]
13+
python_version = "3.6"

fetch_contacts/Pipfile.lock

Lines changed: 132 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fetch_contacts/docker-run.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
IMAGE_NAME=rapid-pro-fetch-contacts
6+
7+
# Check that the correct number of arguments were provided.
8+
if [ $# -ne 5 ]; then
9+
echo "Usage: sh docker-run.sh <server> <token> <user> <phone-uuid-table> <output-json>"
10+
exit
11+
fi
12+
13+
# Assign the program arguments to bash variables.
14+
SERVER=$1
15+
TOKEN=$2
16+
USER=$3
17+
PHONE_UUID_TABLE=$4
18+
OUTPUT_JSON=$5
19+
20+
# Build an image for this pipeline stage.
21+
docker build -t "$IMAGE_NAME" .
22+
23+
# Create a container from the image that was just built.
24+
container="$(docker container create --env SERVER="$SERVER" --env TOKEN="$TOKEN" --env USER="$USER" "$IMAGE_NAME")"
25+
26+
function finish {
27+
# Tear down the container when done.
28+
docker container rm "$container" >/dev/null
29+
}
30+
trap finish EXIT
31+
32+
# Copy input data into the container
33+
docker cp "$PHONE_UUID_TABLE" "$container:/data/phone-uuid-table.json"
34+
35+
# Run the image as a container.
36+
docker start -a -i "$container"
37+
38+
# Copy the output data back out of the container
39+
mkdir -p "$(dirname "$PHONE_UUID_TABLE")"
40+
docker cp "$container:/data/phone-uuid-table.json" "$PHONE_UUID_TABLE"
41+
42+
mkdir -p "$(dirname "$OUTPUT_JSON")"
43+
docker cp "$container:/data/output.json" "$OUTPUT_JSON"

fetch_contacts/fetch_contacts.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import argparse
2+
import os
3+
import time
4+
5+
from core_data_modules.traced_data import TracedData, Metadata
6+
from core_data_modules.traced_data.io import TracedDataJsonIO
7+
from core_data_modules.util import PhoneNumberUuidTable, IOUtils
8+
from temba_client.v2 import TembaClient
9+
10+
if __name__ == "__main__":
11+
parser = argparse.ArgumentParser(description="Downloads contacts from RapidPro")
12+
parser.add_argument("--server", help="Address of RapidPro server. Defaults to http://localhost:8000.",
13+
nargs="?", default="http://localhost:8000")
14+
parser.add_argument("token", help="RapidPro API Token")
15+
parser.add_argument("user", help="Identifier of user launching this program, for use in TracedData Metadata")
16+
parser.add_argument("phone_uuid_table_path", metavar="phone-uuid-table-path",
17+
help="JSON file containing an existing phone number <-> UUID lookup table. "
18+
"This file will be updated with the new phone numbers which are found by this process")
19+
parser.add_argument("json_output_path", metavar="json-output-path",
20+
help="Path to serialized TracedData JSON file")
21+
22+
args = parser.parse_args()
23+
server = args.server
24+
token = args.token
25+
user = args.user
26+
phone_uuid_path = args.phone_uuid_table_path
27+
json_output_path = args.json_output_path
28+
29+
rapid_pro = TembaClient(server, token)
30+
31+
# Load the existing phone number <-> UUID table.
32+
if not os.path.exists(phone_uuid_path):
33+
raise FileNotFoundError("No such phone uuid table file '{}'. "
34+
"To create a new, empty UUID table, "
35+
"run $ echo \"{{}}\" > <target-json-file>".format(phone_uuid_path))
36+
with open(phone_uuid_path, "r") as f:
37+
phone_uuids = PhoneNumberUuidTable.load(f)
38+
39+
# Download all contacts
40+
print("Fetching contacts...")
41+
start = time.time()
42+
contacts = rapid_pro.get_contacts().all(retry_on_rate_exceed=True)
43+
print("Fetched {} contacts ({}s)".format(len(contacts), time.time() - start))
44+
45+
# Convert contacts to TracedData
46+
traced_contacts = []
47+
for contact in contacts:
48+
contact_dict = dict()
49+
contact_dict["avf_phone_id"] = phone_uuids.add_phone(contact.urns[0])
50+
contact_dict.update(contact.fields)
51+
52+
traced_contacts.append(TracedData(
53+
contact_dict,
54+
Metadata(user, Metadata.get_call_location(), time.time())
55+
))
56+
57+
# Write the UUIDs out to a file
58+
with open(phone_uuid_path, "w") as f:
59+
phone_uuids.dump(f)
60+
61+
# Output TracedData to JSON
62+
IOUtils.ensure_dirs_exist_for_file(json_output_path)
63+
with open(json_output_path, "w") as f:
64+
TracedDataJsonIO.export_traced_data_iterable_to_json(traced_contacts, f, pretty_print=True)

0 commit comments

Comments
 (0)