1584 lines
49 KiB
Plaintext
1584 lines
49 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "4e3a145b",
|
||
"metadata": {},
|
||
"source": [
|
||
"# VK"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "44794e2f",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#ignore\n",
|
||
"import os\n",
|
||
"\n",
|
||
"def load_env(file_path):\n",
|
||
" \"\"\"Загружает переменные окружения из файла env с поддержкой булевых значений.\"\"\"\n",
|
||
" with open(file_path) as f:\n",
|
||
" for line in f:\n",
|
||
" line = line.strip()\n",
|
||
" if not line or line.startswith('#'):\n",
|
||
" continue\n",
|
||
" \n",
|
||
" try:\n",
|
||
" key, value = line.split('=', 1)\n",
|
||
" key = key.strip()\n",
|
||
" value = value.strip('\"\\' ')\n",
|
||
" \n",
|
||
" # Преобразование строковых значений в булевые\n",
|
||
" if value.lower() in ['true', '1', 'yes']:\n",
|
||
" value = True\n",
|
||
" elif value.lower() in ['false', '0', 'no']:\n",
|
||
" value = False\n",
|
||
" \n",
|
||
" # Проверка, что ключ не пустой\n",
|
||
" if key:\n",
|
||
" os.environ[key] = str(value) # Храним как строку\n",
|
||
"\n",
|
||
" except ValueError:\n",
|
||
" print(f\"Ошибка: неверный формат в строке '{line}'\")\n",
|
||
"\n",
|
||
"try:\n",
|
||
" load_env('env')\n",
|
||
"except:\n",
|
||
" load_env('env_example')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "dd08738b",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Class"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "49f00c66",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import httpx\n",
|
||
"import asyncio\n",
|
||
"from db import *\n",
|
||
"from config import *\n",
|
||
"from auth import *\n",
|
||
"from token_manager import TokenManager\n",
|
||
"import logging\n",
|
||
"from PIL import Image\n",
|
||
"from io import BytesIO\n",
|
||
"from celery import Celery\n",
|
||
"from bson import ObjectId\n",
|
||
"from fastapi import status\n",
|
||
"from fastapi import APIRouter,Depends\n",
|
||
"from fastapi.responses import RedirectResponse\n",
|
||
"from images import insert_logo\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "28509a4b",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Конфигурация"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "cd75fe35",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"celery_app_vk = Celery('vk', broker=f'{redis_uri}1', backend=f'{redis_uri}1', task_track_started=True )\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "f33750b5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"token_manager = TokenManager()\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "d94f31bd",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"router = APIRouter(prefix=\"/vk\", tags=[\"VK OAuth\"])\n",
|
||
"@router.get(\"/auth\")\n",
|
||
"async def auth_redirect(\n",
|
||
" user=Depends(get_current_user)\n",
|
||
"):\n",
|
||
" url = await token_manager.get_auth_url(user_id=user['id'])\n",
|
||
" return RedirectResponse(url=url, status_code=status.HTTP_303_SEE_OTHER)\n",
|
||
"\n",
|
||
"\n",
|
||
"@router.get(\"/token\")\n",
|
||
"async def oauth_callback(code: str, state: str, device_id: str = None):\n",
|
||
" token_data = await token_manager.get_token(code=code, state=state, device_id=device_id)\n",
|
||
" return RedirectResponse(url='/profile/social', status_code=status.HTTP_303_SEE_OTHER)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "b05a93b5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"async def get_images(db_name: str, file_ids: list, sign_avatar: bool = True):\n",
|
||
" images = {}\n",
|
||
" photo_bytes_list= []\n",
|
||
"\n",
|
||
" if sign_avatar:\n",
|
||
" user = await users_collection.find_one({'_id': ObjectId(file_ids[0])},{'img':1})\n",
|
||
" stream = await gridfs_map['users'].open_download_stream(ObjectId(user['img']))\n",
|
||
" avatar_bytes = await stream.read()\n",
|
||
" logo = Image.open(BytesIO(avatar_bytes)).convert(\"RGBA\")\n",
|
||
" file_ids = file_ids[1:]\n",
|
||
" \n",
|
||
" for _id in file_ids:\n",
|
||
" stream = await gridfs_map[db_name].open_download_stream(ObjectId(_id))\n",
|
||
" photo_bytes_list.append((stream.name, BytesIO(await stream.read()), _id))\n",
|
||
" \n",
|
||
" for name, background, _id in photo_bytes_list:\n",
|
||
" if sign_avatar:\n",
|
||
" background = insert_logo(Image.open(background).convert(\"RGBA\"), logo)\n",
|
||
" images[_id] = (\"photo\", (name, background, \"image/jpeg\"))\n",
|
||
" \n",
|
||
" return images\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "6d815249",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# async def send_vk(item: dict, text: str, file_ids: list, doc: dict, sign_avatar: bool = True): TODO\n",
|
||
"@router.post(\"/send\")\n",
|
||
"async def send_vk(data:dict, request: Request):\n",
|
||
" auth = request.headers.get(\"Authorization\")\n",
|
||
" if auth and auth.lower().startswith(\"bearer \"):\n",
|
||
" parts = auth.split(\" \", 1)\n",
|
||
" if len(parts) == 2:\n",
|
||
" if parts[1].strip() != ATOKEN:\n",
|
||
" return None\n",
|
||
" item = data['item']\n",
|
||
" text = data['text']\n",
|
||
" file_ids = data['file_ids']\n",
|
||
" doc = data['doc']\n",
|
||
" \n",
|
||
" sign_avatar = data['sign_avatar']\n",
|
||
" db_name = item.get('db')\n",
|
||
" # if db_name == 'competitions':\n",
|
||
" # social = await social_collection.find_one({'service': True, 'type':'vk'})\n",
|
||
" # else:\n",
|
||
" social = doc\n",
|
||
" logging.info(doc)\n",
|
||
" logging.info(social)\n",
|
||
" images = await get_images(db_name, file_ids, sign_avatar)\n",
|
||
" async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
||
" attachments = []\n",
|
||
" for _id, img in images.items():\n",
|
||
" # doc_photo = await mongo_client['vk']['photos'].find_one({'id':f\"{_id}:{social.get('_id')}\"})\n",
|
||
" # if doc_photo:\n",
|
||
" # attachments.append(doc_photo['attachment'])\n",
|
||
" # continue\n",
|
||
" payload = {\"v\": \"5.199\"}\n",
|
||
" if 'group' in social:\n",
|
||
" payload['group_id'] = social['id']\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.getWallUploadServer\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(social['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" upload_url = resp.json()['response']['upload_url']\n",
|
||
" resp = await client.post(upload_url, files=[img], timeout=60.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" payload.update(resp.json())\n",
|
||
" payload.update({'caption':text})\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.saveWallPhoto\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(social['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
||
" if not attachment:\n",
|
||
" return {'ok': False}\n",
|
||
" # await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f\"{_id}:{social.get('_id')}\"})\n",
|
||
" attachments.append(attachment)\n",
|
||
" logging.info(attachments)\n",
|
||
" \n",
|
||
" resp = await client.post(f\"{VK_API_URI}wall.post\", data={\n",
|
||
" \"access_token\": await token_manager.get_access_token(doc['user_id']),\n",
|
||
" \"owner_id\": f'-{doc['id']}' if 'group' in doc else doc['id'],\n",
|
||
" 'message': text,\n",
|
||
" 'attachments': ','.join(attachments),\n",
|
||
" 'primary_attachments_mode': 'grid',\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
" res = resp.json()\n",
|
||
" res.update({'doc': doc})\n",
|
||
" if 'error' in res:\n",
|
||
" return {'ok': False}\n",
|
||
" update_spec = {\"$push\": {\"vk\": res}}\n",
|
||
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
||
" return {\"ok\": True}\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "242e59e6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# async def edit_vk(item: dict, text: str, file_ids: list, doc: dict, sign_avatar: bool = True): TODO\n",
|
||
"@router.post(\"/edit\")\n",
|
||
"async def edit_vk(data:dict, request: Request):\n",
|
||
" auth = request.headers.get(\"Authorization\")\n",
|
||
" if auth and auth.lower().startswith(\"bearer \"):\n",
|
||
" parts = auth.split(\" \", 1)\n",
|
||
" if len(parts) == 2:\n",
|
||
" if parts[1].strip() != ATOKEN:\n",
|
||
" return None\n",
|
||
" item = data['item']\n",
|
||
" text = data['text']\n",
|
||
" file_ids = data['file_ids']\n",
|
||
" doc = data['doc']\n",
|
||
" post_id = data['post_id']\n",
|
||
" sign_avatar = data['sign_avatar']\n",
|
||
" db_name = item.get('db')\n",
|
||
" if db_name == 'competitions':\n",
|
||
" social = await social_collection.find_one({'service': True, 'type':'vk'})\n",
|
||
" else:\n",
|
||
" social = doc\n",
|
||
" logging.info(doc)\n",
|
||
" logging.info(social)\n",
|
||
" images = await get_images(db_name, file_ids, sign_avatar)\n",
|
||
" async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
||
" attachments = []\n",
|
||
" for _id, img in images.items():\n",
|
||
" vk_photos_key = f\"{item.get('_id')}:{_id}:{social.get('_id')}\"\n",
|
||
" doc_photo = await mongo_client['vk']['photos'].find_one({'id':vk_photos_key})\n",
|
||
" if doc_photo:\n",
|
||
" attachments.append(doc_photo['attachment'])\n",
|
||
" continue\n",
|
||
" payload = {\"v\": \"5.199\"}\n",
|
||
" if 'group' in social:\n",
|
||
" payload['group_id'] = social['id']\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.getWallUploadServer\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(social['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" upload_url = resp.json()['response']['upload_url']\n",
|
||
" resp = await client.post(upload_url, files=[img], timeout=60.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" payload.update(resp.json())\n",
|
||
" payload.update({'caption':text})\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.saveWallPhoto\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(social['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
||
" if not attachment:\n",
|
||
" return {'ok': False}\n",
|
||
" await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':vk_photos_key})\n",
|
||
" attachments.append(attachment)\n",
|
||
" logging.info(attachments)\n",
|
||
" \n",
|
||
" resp = await client.post(f\"{VK_API_URI}wall.edit\", data={\n",
|
||
" \"access_token\": await token_manager.get_access_token(doc['user_id']),\n",
|
||
" \"owner_id\": f'-{doc['id']}' if 'group' in doc else doc['id'],\n",
|
||
" \"post_id\": post_id,\n",
|
||
" 'message': text,\n",
|
||
" 'attachments': attachments,\n",
|
||
" 'primary_attachments_mode': 'grid',\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
" res = resp.json()\n",
|
||
" res.update({'doc': doc})\n",
|
||
" if 'error' in res:\n",
|
||
" return {'ok': False}\n",
|
||
" update_spec = {\"$push\": {\"vk\": res}}\n",
|
||
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
||
" return {\"ok\": True}\n",
|
||
"\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "a7bb0794",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# TODO сделать вызов функции из @celery_app_vk.task( а не по url в router\n",
|
||
"@router.post(\"/delete\")\n",
|
||
"async def wall_delete(data: dict, request: Request):\n",
|
||
" # ---- auth ----\n",
|
||
" auth = request.headers.get(\"Authorization\")\n",
|
||
" if auth and auth.lower().startswith(\"bearer \"):\n",
|
||
" token = auth.split(\" \", 1)[1].strip()\n",
|
||
" if token != ATOKEN:\n",
|
||
" return {\"ok\": False, \"error\": \"unauthorized\"}\n",
|
||
"\n",
|
||
" item = data[\"item\"]\n",
|
||
" post_id = data[\"post_id\"]\n",
|
||
" doc = data[\"doc\"]\n",
|
||
"\n",
|
||
" logging.info(doc)\n",
|
||
"\n",
|
||
" owner_id = f\"-{doc.get('id')}\" if \"group\" in doc else doc.get(\"id\")\n",
|
||
"\n",
|
||
" # ---- VK request ----\n",
|
||
" async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
||
" resp = await client.post(f\"{VK_API_URI}wall.delete\", data={\n",
|
||
" \"access_token\": await token_manager.get_access_token(doc[\"user_id\"]),\n",
|
||
" \"owner_id\": owner_id,\n",
|
||
" \"post_id\": post_id,\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
"\n",
|
||
" res = resp.json()\n",
|
||
" logging.info(f\"DELETE VK response: {res}\")\n",
|
||
" res[\"doc\"] = doc\n",
|
||
"\n",
|
||
" if \"error\" in res:\n",
|
||
" return {\"ok\": False, \"error\": res[\"error\"]}\n",
|
||
"\n",
|
||
" # ---- Mongo remove vk post record ----\n",
|
||
" if item:\n",
|
||
" col = item.get(\"col\")\n",
|
||
" mongo_col = mongo_client[item.get(\"db\")][col]\n",
|
||
"\n",
|
||
" mongo_col.update_one(\n",
|
||
" {\"_id\": ObjectId(item.get(\"_id\"))},\n",
|
||
" {\"$pull\": {\"vk\": {\"response\": {\"post_id\": post_id}}}}\n",
|
||
" )\n",
|
||
"\n",
|
||
" return {\"ok\": True}\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "2b5f808c",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"@celery_app_vk.task(\n",
|
||
" bind=True,\n",
|
||
" rate_limit='60/m',\n",
|
||
" name='vk.edit_vk',\n",
|
||
" retry_backoff=True,\n",
|
||
" retry_backoff_max=600,\n",
|
||
" retry_jitter=True,\n",
|
||
" max_retries=20,\n",
|
||
" soft_time_limit=60,\n",
|
||
" time_limit=100,\n",
|
||
")\n",
|
||
"def edit(self, post_id: int, item: dict, text: str, file_ids: list, social: dict, sign_avatar: bool = True):\n",
|
||
" try:\n",
|
||
" logging.info(f\"VK начало edit {item} {file_ids}\")\n",
|
||
" res = httpx.post(\n",
|
||
" 'http://127.0.0.1:30080/api/v1/social/vk/edit', \n",
|
||
" headers={\"Authorization\": f\"bearer {ATOKEN}\"}, \n",
|
||
" json={'post_id': post_id, 'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},\n",
|
||
" timeout=100\n",
|
||
" ).json()\n",
|
||
" if res['ok']:\n",
|
||
" return res\n",
|
||
" raise RuntimeError(f\"VK send failed: {res}\")\n",
|
||
" \n",
|
||
" except Exception as exc:\n",
|
||
" raise self.retry(exc=exc)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "3da1d0f1",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"@celery_app_vk.task(\n",
|
||
" bind=True,\n",
|
||
" rate_limit='60/m',\n",
|
||
" name='vk.wall_delete',\n",
|
||
" retry_backoff=True,\n",
|
||
" retry_backoff_max=600,\n",
|
||
" retry_jitter=True,\n",
|
||
" max_retries=20,\n",
|
||
" soft_time_limit=60,\n",
|
||
" time_limit=100,\n",
|
||
")\n",
|
||
"def delete_wall(self, post_id: int, doc: dict, item: dict|None = None):\n",
|
||
" try:\n",
|
||
" logging.info(f\"VK удаления публикации {doc} {post_id}\")\n",
|
||
" res = httpx.post(\n",
|
||
" 'http://127.0.0.1:30080/api/v1/social/vk/delete',\n",
|
||
" headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
||
" json={'item': item, 'post_id': post_id, \"doc\": doc},\n",
|
||
" timeout=100\n",
|
||
" ).json()\n",
|
||
" if res.get('ok'):\n",
|
||
" return res\n",
|
||
" raise RuntimeError(f\"VK send failed: {res}\")\n",
|
||
" \n",
|
||
" except Exception as exc:\n",
|
||
" raise self.retry(exc=exc)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "20ac6800",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"@celery_app_vk.task(\n",
|
||
" bind=True,\n",
|
||
" rate_limit='60/m',\n",
|
||
" name='vk.send_vk',\n",
|
||
" retry_backoff=True,\n",
|
||
" retry_backoff_max=600,\n",
|
||
" retry_jitter=True,\n",
|
||
" max_retries=20,\n",
|
||
" soft_time_limit=60,\n",
|
||
" time_limit=100,\n",
|
||
")\n",
|
||
"def notify(self, item: dict, text: str, file_ids: list, social: dict, sign_avatar: bool = True):\n",
|
||
" try:\n",
|
||
" logging.info(f\"VK начало публикации {item} {file_ids}\")\n",
|
||
" res = httpx.post(\n",
|
||
" 'http://127.0.0.1:30080/api/v1/social/vk/send',\n",
|
||
" headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
||
" json={'item': item, 'text': text, 'file_ids': file_ids, 'doc': social, 'sign_avatar': sign_avatar},\n",
|
||
" timeout=100\n",
|
||
" ).json()\n",
|
||
" if res.get('ok'):\n",
|
||
" return res\n",
|
||
" raise RuntimeError(f\"VK send failed: {res}\")\n",
|
||
" \n",
|
||
" except Exception as exc:\n",
|
||
" raise self.retry(exc=exc)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "8810213f",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Run"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "dacd2f6e",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# ignore \n",
|
||
"# async for post in posts_collection.find({}).sort('_id', -1).limit(50):\n",
|
||
"# vk_posts = post.get('vk')\n",
|
||
"# if len(vk_posts) > 1:\n",
|
||
"# print('ok')\n",
|
||
"# post_ref = {'_id': post['_id'], 'db': 'posts', 'col': 'posts'}\n",
|
||
" \n",
|
||
"# res = httpx.post(\n",
|
||
"# 'https://kultmost.spiritofweb.ru/api/v1/social/vk/delete',\n",
|
||
"# headers={\"Authorization\": f\"bearer {ATOKEN}\"},\n",
|
||
"# json={'item': bson_clear(post_ref), 'post_id': int(vk_posts[-1]['response']['post_id']), \"doc\": bson_clear(vk_posts[-1]['doc'])},\n",
|
||
"# timeout=100\n",
|
||
"# ).json()\n",
|
||
"# await asyncio.sleep(1)\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0e75e5f2",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import json\n",
|
||
"import os\n",
|
||
"\n",
|
||
"IGNORE = ['build.ipynb', 'data.ipynb']\n",
|
||
"\n",
|
||
"for _filename in [i for i in os.listdir() if 'ipynb' in i and i not in IGNORE]:\n",
|
||
" filename_without_extension = os.path.splitext(os.path.basename(_filename))[0]\n",
|
||
"\n",
|
||
" with open(f'{filename_without_extension}.ipynb', 'r') as f:\n",
|
||
" data = f.read()\n",
|
||
"\n",
|
||
" main = json.loads(data)\n",
|
||
" app = []\n",
|
||
" for cell in main['cells']:\n",
|
||
" if '## Run' in cell['source']:\n",
|
||
" break\n",
|
||
" if '# ignore\\n' in cell['source']:\n",
|
||
" continue\n",
|
||
" app.append(''.join(cell['source']))\n",
|
||
"\n",
|
||
" with open(f'{filename_without_extension}.py', 'w') as f:\n",
|
||
" f.write('\\n\\n'.join(app))\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "6f76c7c1",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "shellscript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"!celery -A vk.celery_app_vk worker --loglevel=info"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "b0d41fb5",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "shellscript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"!docker build -t registry.spiritofweb.ru/avtopost-api:latest ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "674d49e8",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "shellscript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"!sudo docker image push registry.spiritofweb.ru/avtopost-api:latest"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "65b3c103",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "shellscript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"!kubectl rollout restart deployments/vk-celery -n kultmost"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "79ce5429",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "shellscript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"!echo $REGISTRY_HOST"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "62a866f8",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Test"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0b930db4",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"stop"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "7fbab37f",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"user_id = '681684390000000000000000'"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "ab179fe7",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"await redis_client.delete(f\"access_token:{user_id}\")\n",
|
||
"await redis_client.delete(f\"tokens:{user_id}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "dce288c3",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"uid = ObjectId(user_id)\n",
|
||
"\n",
|
||
"doc = {}\n",
|
||
"doc.update({\n",
|
||
" \"expires_at\": 55435\n",
|
||
"})\n",
|
||
"\n",
|
||
"await mongo_client['test']['123'].update_one(\n",
|
||
" {\"user_ids\": uid},\n",
|
||
" {\n",
|
||
" \"$set\": doc,\n",
|
||
" \"$setOnInsert\": {\"user_ids\": [uid]},\n",
|
||
" },\n",
|
||
" upsert=True,\n",
|
||
")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "d1c2c193",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import token_manager as tm"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "c8b3a406",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from token_manager import TokenManager\n",
|
||
"token_manager = TokenManager()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "fbe436c7",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"token_manager = TokenManager()\n",
|
||
"access_token = await token_manager.get_access_token('644fa8bb0000000000000000')\n",
|
||
"access_token"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "fe977ad0",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"item ={'_id': '6a21559cca3ad8a73b652bcb', 'db': 'competitions', 'col': 'competitions'} \n",
|
||
"file_ids = ['681684390000000000000000', '6a21559cca3ad8a73b652bc6']"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "b8abc66f",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"docs =[ doc async for doc in mongo_client['social']['social'].find({'user_id':'681684390000000000000000'})]\n",
|
||
"doc = docs[1]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "42b797b5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"competition = await competitions_col.find_one({'_id':ObjectId('6a21559cca3ad8a73b652bcb')})"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "110260d2",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"images = await get_images(db_name, file_ids, sign_avatar)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e2537fa4",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
||
" attachments = []\n",
|
||
" for _id, img in images.items():\n",
|
||
" doc_photo = await mongo_client['vk']['photos'].find_one({'id':f\"{_id}:{doc.get('_id')}\"})\n",
|
||
" if doc_photo:\n",
|
||
" attachments.append(doc_photo['attachment'])\n",
|
||
" continue\n",
|
||
" payload = {\"v\": \"5.199\"}\n",
|
||
" if 'group' in doc:\n",
|
||
" payload['group_id'] = doc['id']\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.getWallUploadServer\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(doc['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" upload_url = resp.json()['response']['upload_url']\n",
|
||
" resp = await client.post(upload_url, files=[img], timeout=60.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" payload.update(resp.json())\n",
|
||
" payload.update({'caption':text})\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.saveWallPhoto\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(doc['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
||
" await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f\"{_id}:{doc.get('_id')}\"})\n",
|
||
" attachments.append(attachment)\n",
|
||
" print(attachments)\n",
|
||
" resp = await client.post(f\"{VK_API_URI}wall.post\", data={\n",
|
||
" \"access_token\": await token_manager.get_access_token(doc['user_id']),\n",
|
||
" \"owner_id\": f'-{doc['id']}' if 'group' in doc else doc['id'],\n",
|
||
" 'message': text,\n",
|
||
" 'attachments': attachments,\n",
|
||
" 'primary_attachments_mode': 'grid',\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
" res = resp.json()\n",
|
||
" res.update({'doc': doc})"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "7b531356",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"res"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e994cda8",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"@router.post(\"/send\")\n",
|
||
"async def send_vk(data:dict):\n",
|
||
" item = data['item']\n",
|
||
" text = data['text']\n",
|
||
" file_ids = data['file_ids']\n",
|
||
" doc = data['doc']\n",
|
||
" \n",
|
||
" sign_avatar = data['sign_avatar']\n",
|
||
"# async def send_vk(item: dict, text: str, file_ids: list, doc: dict, sign_avatar: bool = True):\n",
|
||
" \n",
|
||
" if db_name == 'competitions':\n",
|
||
" social = await social_collection.find_one({'service': True, 'type':'vk'})\n",
|
||
" else:\n",
|
||
" social = doc\n",
|
||
" logging.info(doc)\n",
|
||
" logging.info(social)\n",
|
||
" \n",
|
||
" async with httpx.AsyncClient(http2=True, verify=ctx) as client:\n",
|
||
" attachments = []\n",
|
||
" for _id, img in images.items():\n",
|
||
" doc_photo = await mongo_client['vk']['photos'].find_one({'id':f\"{_id}:{social.get('_id')}\"})\n",
|
||
" if doc_photo:\n",
|
||
" attachments.append(doc_photo['attachment'])\n",
|
||
" continue\n",
|
||
" payload = {\"v\": \"5.199\"}\n",
|
||
" if 'group' in social:\n",
|
||
" payload['group_id'] = social['id']\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.getWallUploadServer\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(social['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" upload_url = resp.json()['response']['upload_url']\n",
|
||
" resp = await client.post(upload_url, files=[img], timeout=60.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" payload.update(resp.json())\n",
|
||
" payload.update({'caption':text})\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.saveWallPhoto\", headers={\"Authorization\": f\"Bearer {await token_manager.get_access_token(social['user_id'])}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" attachment = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
||
" if not attachment:\n",
|
||
" return {'ok': False}\n",
|
||
" await mongo_client['vk']['photos'].insert_one({'attachment':attachment,'id':f\"{_id}:{social.get('_id')}\"})\n",
|
||
" attachments.append(attachment)\n",
|
||
" logging.info(attachments)\n",
|
||
" \n",
|
||
" resp = await client.post(f\"{VK_API_URI}wall.post\", data={\n",
|
||
" \"access_token\": await token_manager.get_access_token(doc['user_id']),\n",
|
||
" \"owner_id\": f'-{doc['id']}' if 'group' in doc else doc['id'],\n",
|
||
" 'message': text,\n",
|
||
" 'attachments': attachments,\n",
|
||
" 'primary_attachments_mode': 'grid',\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
" res = resp.json()\n",
|
||
" res.update({'doc': doc})\n",
|
||
" if 'error' in res:\n",
|
||
" return {'ok': False}\n",
|
||
" update_spec = {\"$push\": {\"vk\": res}}\n",
|
||
" await mongo_client[db_name][item.get('col')].update_one({'_id': ObjectId(item.get('_id'))}, update_spec)\n",
|
||
" return {\"ok\": True}\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "3d532511",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"stream = await gridfs_map['competition'].open_download_stream(ObjectId(competition['poster_file_id']))\n",
|
||
"data = await stream.read()\n",
|
||
"\n",
|
||
"files = {\"photo\": (stream.name, BytesIO(data), \"image/jpeg\")}\n",
|
||
"async with httpx.AsyncClient(verify=ctx, http2=True) as client:\n",
|
||
" payload = {\"v\": \"5.199\"}\n",
|
||
" if 'group' in doc:\n",
|
||
" payload['group_id'] = doc['id']\n",
|
||
" resp_get_upload_server = await client.post(f\"{VK_API_URI}photos.getWallUploadServer\", headers={\"Authorization\": f\"Bearer {access_token}\"}, data=payload, timeout=30.0)\n",
|
||
" resp_get_upload_server.raise_for_status()\n",
|
||
" upload_url = resp_get_upload_server.json()['response']['upload_url']\n",
|
||
" resp_upload = await client.post(upload_url, files=files, timeout=60.0)\n",
|
||
" resp_upload.raise_for_status()\n",
|
||
" payload.update(resp_upload.json())\n",
|
||
" payload.update({'caption':text})\n",
|
||
" resp = await client.post(f\"{VK_API_URI}photos.saveWallPhoto\", headers={\"Authorization\": f\"Bearer {access_token}\"}, data=payload, timeout=30.0)\n",
|
||
" resp.raise_for_status()\n",
|
||
" print(resp.json())\n",
|
||
" attachments = ','.join([f'photo{i['owner_id']}_{i['id']}' for i in resp.json()['response']])\n",
|
||
" print(attachments)\n",
|
||
" resp_wall = await client.post(f\"{VK_API_URI}wall.post\", data={\n",
|
||
" \"access_token\": access_token,\n",
|
||
" \"owner_id\": f'-{doc['id']}' if 'group' in doc else doc['id'],\n",
|
||
" 'message': text,\n",
|
||
" 'attachments': attachments,\n",
|
||
" 'primary_attachments_mode': 'grid',\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
" print(resp_wall.json())\n",
|
||
" \n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "8360f581",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"await competitions_col.find_one({'_id': competition['_id']})"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "04953ea6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"await competitions_col.update_one(\n",
|
||
" {'_id': competition['_id']},\n",
|
||
" {\n",
|
||
" \"$push\": {\"vk\": resp_wall.json()}\n",
|
||
" },\n",
|
||
" )"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "415c9000",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"resp = httpx.post(f\"{VK_API_URI}users.get\", data={\n",
|
||
" \"access_token\": access_token,\n",
|
||
" \"fields\": \"photo_max_orig,screen_name\",\n",
|
||
" \"v\": \"5.199\",\n",
|
||
" })\n",
|
||
"resp.json()['response'][0]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "8feb5878",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"[doc async for doc in mongo_client['social']['social'].find({'user_id':competition['user']['id']})]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "1316ebc0",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"z=httpx.post(f\"{VK_API_URI}wall.edit\", data={\n",
|
||
" 'access_token':access_token,\n",
|
||
" 'post_id':2970,\n",
|
||
" 'attachments': 'photo25126640_457244944',\n",
|
||
" 'message':text,\n",
|
||
" 'v':'5.199',\n",
|
||
"})\n",
|
||
"\n",
|
||
"z.json()['response']"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "a6f67f24",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#!pip freeze > requirements.txt"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "eea60230",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "javascript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"await fetch(\"https://api.vk.com/method/groups.editManager?v=5.269&client_id=6287487\", {\n",
|
||
" \"headers\": {\n",
|
||
" \"Accept\": \"*/*\",\n",
|
||
" },\n",
|
||
" \"body\": \"group_id=191599084&user_id=392892935&role=moderator&is_contact=0&contact_position=&contact_phone=&contact_email=&permissions=&access_token=vk1.a.-kG07OUZgX5FrxtsQrU5QJh8HaP_suYXkqcg\",\n",
|
||
" \"method\": \"POST\",\n",
|
||
"});"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "c878e08d",
|
||
"metadata": {
|
||
"vscode": {
|
||
"languageId": "javascript"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"OAUTH_URL = 'https://id.vk.com/oauth2/auth'\n",
|
||
"AUTHORIZE_URL = 'https://id.vk.ru/authorize'\n",
|
||
"VK_CLIENT_ID = 51852444\n",
|
||
"SCOPES = 'offline,wall,photos,groups'\n",
|
||
"redirect_uri = 'https://oauth.vk.ru/blank.html'"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "b990c1c5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"\n",
|
||
"AUTHORIZE_URL = 'https://id.vk.ru/authorize'\n",
|
||
"VK_CLIENT_ID = 51852444\n",
|
||
"SCOPES = 'offline,wall,photos,groups'\n",
|
||
"redirect_uri = 'https://oauth.vk.ru/blank.html'\n",
|
||
"\n",
|
||
"import os\n",
|
||
"import hashlib\n",
|
||
"import base64\n",
|
||
"from urllib.parse import urlencode\n",
|
||
"\n",
|
||
"\n",
|
||
"state = os.urandom(32).hex()\n",
|
||
"code_verifier = os.urandom(50).hex()\n",
|
||
"\n",
|
||
"code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest()).decode()\n",
|
||
"code_challenge = code_challenge.rstrip('=')\n",
|
||
"\n",
|
||
"\n",
|
||
"url = f'{AUTHORIZE_URL}?responsetype_item=code&client_id={VK_CLIENT_ID}&scope={SCOPES}&redirect_uri={redirect_uri}&state={state}&code_challenge={code_challenge}&code_challenge_method=S256'\n",
|
||
"\n",
|
||
"print(f\"\\n\\n{url}\\n\\n\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "23ee767f",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"\n",
|
||
"code='vk2.a.---'\n",
|
||
"device_id=''"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "6a5f9469",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"refresh_token = \"vk2.a.-----\"\n",
|
||
"device_id = \"-\"\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "3c04637d",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import httpx\n",
|
||
"import os\n",
|
||
"z=httpx.post('https://id.vk.com/oauth2/auth', data={\n",
|
||
" 'grant_type':'refresh_token',\n",
|
||
" 'refresh_token':refresh_token,\n",
|
||
" 'client_id':51852444,\n",
|
||
" 'device_id':device_id,\n",
|
||
" 'state': os.urandom(32).hex(),\n",
|
||
"})\n",
|
||
"z.json()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "19d44789",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"CLIENT_ID = 51852444\n",
|
||
"OAUTH_URL = 'https://id.vk.com/oauth2/auth'"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "2b21a826",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"\n",
|
||
"import httpx\n",
|
||
"r=httpx.post('https://id.vk.com/oauth2/auth',data={\n",
|
||
" 'state':os.urandom(32).hex(),\n",
|
||
" 'grant_type':'authorization_code',\n",
|
||
" 'code_verifier':code_verifier,\n",
|
||
" 'code':code,\n",
|
||
" 'client_id':VK_CLIENT_ID,\n",
|
||
" 'device_id':device_id,\n",
|
||
" 'redirect_uri': 'https://oauth.vk.com/blank.html'\n",
|
||
"})\n",
|
||
"r.json()\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "1dd76a96",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"class T():\n",
|
||
" def json(self):\n",
|
||
" return {'refresh_token': 'vk2.a.----',\n",
|
||
" 'access_token': 'vk2.a.-',\n",
|
||
" 'token_type': 'Bearer',\n",
|
||
" 'expires_in': 3600,\n",
|
||
" 'user_id': 888082464,\n",
|
||
" 'state': '',\n",
|
||
" 'scope': 'photos wall offline'}\n",
|
||
"\n",
|
||
"z=T()\n",
|
||
"z.json()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "935136ea",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"refresh_token=r.json()['refresh_token']\n",
|
||
"refresh_token"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "330eb2f4",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import httpx\n",
|
||
"import os\n",
|
||
"z=httpx.post('https://id.vk.com/oauth2/auth', data={\n",
|
||
" 'grant_type':'refresh_token',\n",
|
||
" 'refresh_token':refresh_token,\n",
|
||
" 'client_id':51852444,\n",
|
||
" 'device_id':device_id,\n",
|
||
" 'state': os.urandom(32).hex(),\n",
|
||
"})\n",
|
||
"z.json()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "8996e0b9",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"print(f'\\n\\n{z.json()['refresh_token']}\\n\\n')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "da4184df",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"users.search"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "282d1110",
|
||
"metadata": {},
|
||
"source": [
|
||
"q\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Строка поискового запроса. Например, Вася Бабич.\n",
|
||
"sort\n",
|
||
"\n",
|
||
"integer\n",
|
||
"\n",
|
||
"Сортировка результатов. Возможные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" 1 — по дате регистрации,\n",
|
||
" •\n",
|
||
" 0 — по популярности.\n",
|
||
"\n",
|
||
"offset\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Смещение относительно первого найденного пользователя для выборки определенного подмножества.\n",
|
||
"count\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Количество возвращаемых пользователей.\n",
|
||
"\n",
|
||
" Обратите внимание, даже при использовании параметра offset для получения информации доступны только первые 1000 результатов.\n",
|
||
"\n",
|
||
"fields\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Список дополнительных полей профилей, которые необходимо вернуть. См. подробное описание. Доступные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" about,\n",
|
||
" •\n",
|
||
" activities,\n",
|
||
" •\n",
|
||
" bdate,\n",
|
||
" •\n",
|
||
" blacklisted,\n",
|
||
" •\n",
|
||
" blacklisted_by_me\n",
|
||
" •\n",
|
||
" books,\n",
|
||
" •\n",
|
||
" can_post,\n",
|
||
" •\n",
|
||
" can_see_all_posts,\n",
|
||
" •\n",
|
||
" can_see_audio,\n",
|
||
" •\n",
|
||
" can_send_friend_request,\n",
|
||
" •\n",
|
||
" can_write_private_message,\n",
|
||
" •\n",
|
||
" career,\n",
|
||
" •\n",
|
||
" city,\n",
|
||
" •\n",
|
||
" common_count,\n",
|
||
" •\n",
|
||
" connections,\n",
|
||
" •\n",
|
||
" contacts,\n",
|
||
" •\n",
|
||
" country,\n",
|
||
" •\n",
|
||
" crop_photo,\n",
|
||
" •\n",
|
||
" domain,\n",
|
||
" •\n",
|
||
" education,\n",
|
||
" •\n",
|
||
" exports,\n",
|
||
" •\n",
|
||
" followers_count,\n",
|
||
" •\n",
|
||
" friend_status,\n",
|
||
" •\n",
|
||
" games,\n",
|
||
" •\n",
|
||
" has_mobile,\n",
|
||
" •\n",
|
||
" has_photo,\n",
|
||
" •\n",
|
||
" home_town,\n",
|
||
" •\n",
|
||
" interests,\n",
|
||
" •\n",
|
||
" is_favorite,\n",
|
||
" •\n",
|
||
" is_friend,\n",
|
||
" •\n",
|
||
" is_hidden_from_feed,\n",
|
||
" •\n",
|
||
" last_seen,\n",
|
||
" •\n",
|
||
" lists,\n",
|
||
" •\n",
|
||
" maiden_name,\n",
|
||
" •\n",
|
||
" military,\n",
|
||
" •\n",
|
||
" movies,\n",
|
||
" •\n",
|
||
" music,\n",
|
||
" •\n",
|
||
" nickname,\n",
|
||
" •\n",
|
||
" occupation,\n",
|
||
" •\n",
|
||
" online,\n",
|
||
" •\n",
|
||
" personal,\n",
|
||
" •\n",
|
||
" photo_100,\n",
|
||
" •\n",
|
||
" photo_200,\n",
|
||
" •\n",
|
||
" photo_200_orig,\n",
|
||
" •\n",
|
||
" photo_400_orig,\n",
|
||
" •\n",
|
||
" photo_50,\n",
|
||
" •\n",
|
||
" photo_id,\n",
|
||
" •\n",
|
||
" photo_max,\n",
|
||
" •\n",
|
||
" photo_max_orig,\n",
|
||
" •\n",
|
||
" quotes,\n",
|
||
" •\n",
|
||
" relation,\n",
|
||
" •\n",
|
||
" relatives,\n",
|
||
" •\n",
|
||
" schools,\n",
|
||
" •\n",
|
||
" screen_name,\n",
|
||
" •\n",
|
||
" sex,\n",
|
||
" •\n",
|
||
" site,\n",
|
||
" •\n",
|
||
" status,\n",
|
||
" •\n",
|
||
" timezone,\n",
|
||
" •\n",
|
||
" tv,\n",
|
||
" •\n",
|
||
" universities,\n",
|
||
" •\n",
|
||
" verified,\n",
|
||
" •\n",
|
||
" wall_comments.\n",
|
||
"\n",
|
||
"city\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор города.\n",
|
||
"city_id\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор города для обратной совместимости. Используйте city\n",
|
||
"country\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор страны.\n",
|
||
"country_id\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор страны для обратной совместимости. Используйте country\n",
|
||
"hometown\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Название города строкой.\n",
|
||
"university_country\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор страны, в которой пользователи закончили ВУЗ.\n",
|
||
"university\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор ВУЗа.\n",
|
||
"university_year\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Год окончания ВУЗа.\n",
|
||
"university_faculty\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор факультета.\n",
|
||
"university_chair\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор кафедры.\n",
|
||
"sex\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Пол. Возможные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" 1 — женщина,\n",
|
||
" •\n",
|
||
" 2 — мужчина,\n",
|
||
" •\n",
|
||
" 0 — любой (по умолчанию).\n",
|
||
"\n",
|
||
"status\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Семейное положение. Возможные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" 1 — не женат (не замужем),\n",
|
||
" •\n",
|
||
" 2 — встречается,\n",
|
||
" •\n",
|
||
" 3 — помолвлен(-а),\n",
|
||
" •\n",
|
||
" 4 — женат (замужем),\n",
|
||
" •\n",
|
||
" 5 — всё сложно,\n",
|
||
" •\n",
|
||
" 6 — в активном поиске,\n",
|
||
" •\n",
|
||
" 7 — влюблен(-а),\n",
|
||
" •\n",
|
||
" 8 — в гражданском браке.\n",
|
||
"\n",
|
||
"age_from\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Возраст, от.\n",
|
||
"age_to\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Возраст, до.\n",
|
||
"birth_day\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"День рождения.\n",
|
||
"birth_month\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Месяц рождения.\n",
|
||
"birth_year\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Год рождения.\n",
|
||
"online\n",
|
||
"\n",
|
||
"checkbox\n",
|
||
"\n",
|
||
"Учитывать ли статус «онлайн». Возможные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" 1 — искать только пользователей онлайн,\n",
|
||
" •\n",
|
||
" 0 — искать по всем пользователям.\n",
|
||
"\n",
|
||
"has_photo\n",
|
||
"\n",
|
||
"checkbox\n",
|
||
"\n",
|
||
"Учитывать ли наличие фото. Возможные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" 1 — искать только пользователей с фотографией,\n",
|
||
" •\n",
|
||
" 0 — искать по всем пользователям.\n",
|
||
"\n",
|
||
"school_country\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор страны, в которой пользователи закончили школу.\n",
|
||
"school_city\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор города, в котором пользователи закончили школу.\n",
|
||
"school_class\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Буква класса.\n",
|
||
"school\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Идентификатор школы, которую закончили пользователи.\n",
|
||
"school_year\n",
|
||
"\n",
|
||
"positive\n",
|
||
"\n",
|
||
"Год окончания школы.\n",
|
||
"religion\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Религиозные взгляды.\n",
|
||
"company\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Название компании, в которой работают пользователи.\n",
|
||
"position\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Название должности.\n",
|
||
"group_id\n",
|
||
"\n",
|
||
"integer\n",
|
||
"\n",
|
||
"Идентификатор группы, среди пользователей которой необходимо проводить поиск.\n",
|
||
"from_list\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Разделы среди которых нужно осуществить поиск, перечисленные через запятую. Возможные значения:\n",
|
||
"\n",
|
||
" •\n",
|
||
" friends — искать среди друзей,\n",
|
||
" •\n",
|
||
" subscriptions — искать среди друзей и подписок пользователя.\n",
|
||
"\n",
|
||
"screen_ref\n",
|
||
"\n",
|
||
"string\n",
|
||
"\n",
|
||
"Реферер, откуда был вызван метод\n",
|
||
"from_group_id\n",
|
||
"\n",
|
||
"integer\n",
|
||
"Результат\n",
|
||
"\n",
|
||
"После успешного выполнения возвращает объект, содержащий число результатов в поле count и массив объектов, описывающих пользователей в поле items."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": ".venv",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.14.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|