254 lines
12 KiB
Plaintext
254 lines
12 KiB
Plaintext
|
{
|
|||
|
"cells": [
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"id": "yLL1WjbsNJdP"
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"# Phone number migration\n",
|
|||
|
"\n",
|
|||
|
"**Перед запуском необходимо добавить файл с Oauth2 Сredentials (по умолчанию credentials.json)**\n",
|
|||
|
"\n"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"id": "WmCKpRemMRba"
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Импортируем необходимые библиотеки."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 13,
|
|||
|
"metadata": {
|
|||
|
"id": "pzHzXS_eFteU"
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"import os.path\n",
|
|||
|
"\n",
|
|||
|
"from google.auth.transport.requests import Request\n",
|
|||
|
"from google.oauth2.credentials import Credentials\n",
|
|||
|
"from google_auth_oauthlib.flow import InstalledAppFlow\n",
|
|||
|
"from googleapiclient.discovery import build\n",
|
|||
|
"from googleapiclient.errors import HttpError"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"id": "qA-EnsZIMOeZ"
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Основные параметры приложения."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 14,
|
|||
|
"metadata": {
|
|||
|
"id": "rRgABs8rF1d8"
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Параметры приложения\n",
|
|||
|
"OLD_NUMBER_PREFIXES = ['+38071', '071']\n",
|
|||
|
"NEW_NUMBER_PREFIXES = ['+7949']\n",
|
|||
|
"\n",
|
|||
|
"# Функция для получения нового номера из основы старого\n",
|
|||
|
"# Вернет номер в формате +7 949 123-45-67\n",
|
|||
|
"def new_phone_number(base: str):\n",
|
|||
|
" num = '7949' + base\n",
|
|||
|
" return '+{} {} {}-{}-{}'.format(\n",
|
|||
|
" num[0],\n",
|
|||
|
" num[1:4],\n",
|
|||
|
" num[4:7],\n",
|
|||
|
" num[7:9],\n",
|
|||
|
" num[9:11]\n",
|
|||
|
" )\n",
|
|||
|
"# Тип телефона.\n",
|
|||
|
"# Доступные значения: https://developers.google.com/people/api/rest/v1/people#phonenumber\n",
|
|||
|
"PHONE_TYPE = 'mobile'"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 15,
|
|||
|
"metadata": {
|
|||
|
"id": "YMHU4Hs_F5-Y"
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Параметры Google API\n",
|
|||
|
"CREDENTIALS_FILE = 'credentials.json'\n",
|
|||
|
"TOKEN_FILE = 'token.json'\n",
|
|||
|
"SCOPES = ['https://www.googleapis.com/auth/contacts']"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"id": "-Kdstr4TOs1H"
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Основной код приложения"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 16,
|
|||
|
"metadata": {
|
|||
|
"id": "TimQdg09F2GV"
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"def main():\n",
|
|||
|
" creds = None\n",
|
|||
|
" if os.path.exists(TOKEN_FILE):\n",
|
|||
|
" creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)\n",
|
|||
|
" if not creds or not creds.valid:\n",
|
|||
|
" if creds and creds.expired and creds.refresh_token:\n",
|
|||
|
" creds.refresh(Request())\n",
|
|||
|
" else:\n",
|
|||
|
" flow = InstalledAppFlow.from_client_secrets_file(\n",
|
|||
|
" CREDENTIALS_FILE, SCOPES)\n",
|
|||
|
" creds = flow.run_console()\n",
|
|||
|
" with open(TOKEN_FILE, 'w') as token:\n",
|
|||
|
" token.write(creds.to_json())\n",
|
|||
|
" try:\n",
|
|||
|
" service = build('people', 'v1', credentials=creds)\n",
|
|||
|
" print('Получаем список контактов...')\n",
|
|||
|
" results = service.people().connections().list(resourceName='people/me',\n",
|
|||
|
" personFields='names,phoneNumbers').execute()\n",
|
|||
|
" connections = results.get('connections', [])\n",
|
|||
|
" print('Количество контактов: {}'.format(len(connections)))\n",
|
|||
|
" batch_request = {\n",
|
|||
|
" \"contacts\": {},\n",
|
|||
|
" \"updateMask\": \"phoneNumbers\"\n",
|
|||
|
" }\n",
|
|||
|
" for person in connections:\n",
|
|||
|
" phoneNumbers = person.get('phoneNumbers', [])\n",
|
|||
|
" has_old = False\n",
|
|||
|
" old_numbers = set()\n",
|
|||
|
" new_numbers = set()\n",
|
|||
|
" # Получаем номера нового и старого формата\n",
|
|||
|
" for phoneNumber in phoneNumbers:\n",
|
|||
|
" num = phoneNumber.get('canonicalForm')\n",
|
|||
|
" if not num:\n",
|
|||
|
" continue\n",
|
|||
|
" base = get_number_without_prefix(num, OLD_NUMBER_PREFIXES)\n",
|
|||
|
" if (base):\n",
|
|||
|
" has_old = True\n",
|
|||
|
" old_numbers.add(base)\n",
|
|||
|
" base = get_number_without_prefix(num, NEW_NUMBER_PREFIXES)\n",
|
|||
|
" if (base):\n",
|
|||
|
" new_numbers.add(base)\n",
|
|||
|
" # Если нет старого - пропускаем\n",
|
|||
|
" if not has_old:\n",
|
|||
|
" continue\n",
|
|||
|
" # Получаем старые номера, у которых нету парного нового\n",
|
|||
|
" numbers_not_updated = list(\n",
|
|||
|
" old_numbers.difference(new_numbers)\n",
|
|||
|
" )\n",
|
|||
|
" \n",
|
|||
|
" # Если нет старых номеров, которые нужно обновить - пропускаем\n",
|
|||
|
" if len(numbers_not_updated) == 0:\n",
|
|||
|
" continue\n",
|
|||
|
" # Получаем новые номера\n",
|
|||
|
" new_phone_numbers = [\n",
|
|||
|
" new_phone_number(x) for x in numbers_not_updated\n",
|
|||
|
" ]\n",
|
|||
|
" # batchUpdateContacts: https://developers.google.com/people/api/rest/v1/people/batchUpdateContacts\n",
|
|||
|
" # PhoneNumber: https://developers.google.com/people/api/rest/v1/people#phonenumber\n",
|
|||
|
" batch_request['contacts'][person['resourceName']] = {\n",
|
|||
|
" \"phoneNumbers\": [\n",
|
|||
|
" *person['phoneNumbers'],\n",
|
|||
|
" [\n",
|
|||
|
" { \n",
|
|||
|
" \"value\": number, \n",
|
|||
|
" \"type\": PHONE_TYPE\n",
|
|||
|
" } for number in new_phone_numbers\n",
|
|||
|
" ]\n",
|
|||
|
" ],\n",
|
|||
|
" \"etag\": person['etag']\n",
|
|||
|
" }\n",
|
|||
|
" contacts_len = len(batch_request['contacts'])\n",
|
|||
|
" if (contacts_len > 0):\n",
|
|||
|
" print('Количество контактов для обновления: {}'.format(contacts_len))\n",
|
|||
|
" print('Обновляем контакты...')\n",
|
|||
|
" service.people().batchUpdateContacts(body = batch_request).execute()\n",
|
|||
|
" print('Обновление завершено!')\n",
|
|||
|
" else:\n",
|
|||
|
" print('Нечего обновлять!')\n",
|
|||
|
" except HttpError as err:\n",
|
|||
|
" print(err)\n",
|
|||
|
"\n",
|
|||
|
"def get_number_without_prefix(number: str, prefixes: list):\n",
|
|||
|
" for prefix in prefixes:\n",
|
|||
|
" if number.startswith(prefix):\n",
|
|||
|
" return number[len(prefix):]\n",
|
|||
|
" return False"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"id": "WnbwQVZPNDpP"
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Запуск приложения"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 17,
|
|||
|
"metadata": {
|
|||
|
"colab": {
|
|||
|
"base_uri": "https://localhost:8080/",
|
|||
|
"height": 332
|
|||
|
},
|
|||
|
"id": "0v8m0ZYmGHnC",
|
|||
|
"outputId": "092f3a86-80d3-45c7-d4d6-f72878d96017"
|
|||
|
},
|
|||
|
"outputs": [
|
|||
|
{
|
|||
|
"ename": "FileNotFoundError",
|
|||
|
"evalue": "ignored",
|
|||
|
"output_type": "error",
|
|||
|
"traceback": [
|
|||
|
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|||
|
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
|
|||
|
"\u001b[0;32m<ipython-input-17-c7bc734e5e35>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'__main__'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
|
|||
|
"\u001b[0;32m<ipython-input-16-077678182ae9>\u001b[0m in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m flow = InstalledAppFlow.from_client_secrets_file(\n\u001b[0;32m---> 10\u001b[0;31m CREDENTIALS_FILE, SCOPES)\n\u001b[0m\u001b[1;32m 11\u001b[0m \u001b[0mcreds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mflow\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_console\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mTOKEN_FILE\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'w'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mtoken\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
|||
|
"\u001b[0;32m/usr/local/lib/python3.7/dist-packages/google_auth_oauthlib/flow.py\u001b[0m in \u001b[0;36mfrom_client_secrets_file\u001b[0;34m(cls, client_secrets_file, scopes, **kwargs)\u001b[0m\n\u001b[1;32m 199\u001b[0m \u001b[0mFlow\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mThe\u001b[0m \u001b[0mconstructed\u001b[0m \u001b[0mFlow\u001b[0m \u001b[0minstance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 200\u001b[0m \"\"\"\n\u001b[0;32m--> 201\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mclient_secrets_file\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"r\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mjson_file\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 202\u001b[0m \u001b[0mclient_config\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mjson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mjson_file\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 203\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
|
|||
|
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'credentials.json'"
|
|||
|
]
|
|||
|
}
|
|||
|
],
|
|||
|
"source": [
|
|||
|
"if __name__ == '__main__':\n",
|
|||
|
" main()\n"
|
|||
|
]
|
|||
|
}
|
|||
|
],
|
|||
|
"metadata": {
|
|||
|
"colab": {
|
|||
|
"name": "Phone number migration.ipynb",
|
|||
|
"provenance": []
|
|||
|
},
|
|||
|
"kernelspec": {
|
|||
|
"display_name": "Python 3",
|
|||
|
"name": "python3"
|
|||
|
},
|
|||
|
"language_info": {
|
|||
|
"name": "python"
|
|||
|
}
|
|||
|
},
|
|||
|
"nbformat": 4,
|
|||
|
"nbformat_minor": 0
|
|||
|
}
|