Загрузить портрет
Управляет потретами пользователей организации. Работает только для пользователей, созданных на домене организации.
Пример:
curl --request PUT 'https://cloud-api.<ваш_домен>/v1/api360/directory/org/{orgId}/users/{userId}/avatar' \
--header 'Authorization: OAuth token' \
--header 'Content-Type: image/png' \
--data-binary '@path/to/avatar.png'
Request
PUT
https://cloud-api.<ваш_домен>/v1/api360/directory/org/{orgId}/users/{userId}/avatar
Path parameters
|
Name |
Description |
|
orgId |
Type: integer Идентификатор организации. |
|
userId |
Type: string<uint64> Идентификатор сотрудника. Example: `` |
Body
application/json
{}
Type: object
Responses
200 OK
Запрос успешно выполнен.
Body
application/json
{
"url": "example"
}
|
Name |
Description |
|
url |
Type: string Ссылка на портрет. Example: |
400 Bad Request
Некорректный запрос.
Body
application/json
{
"code": 0,
"message": "example",
"details": [
{
"@type": "example"
}
]
}
|
Name |
Description |
|
code |
Type: integer Код ошибки. |
|
details |
Type: protobufAny[] Дополнительные сведения об ошибке. Example
|
|
message |
Type: string Описание ошибки. Example: |
protobufAny
|
Name |
Description |
|
@type |
Type: string Example: |
|
[additional] |
Type: unknown Example: |
Example
{
"@type": "example"
}
401 Unauthorized
Пользователь не авторизован.
Body
application/json
{
"code": 0,
"message": "example",
"details": [
{
"@type": "example"
}
]
}
|
Name |
Description |
|
code |
Type: integer Код ошибки. |
|
details |
Type: protobufAny[] Дополнительные сведения об ошибке. Example
|
|
message |
Type: string Описание ошибки. Example: |
403 Forbidden
У пользователя или приложения нет прав на доступ к ресурсу, запрос отклонен.
Body
application/json
{
"code": 0,
"message": "example",
"details": [
{
"@type": "example"
}
]
}
|
Name |
Description |
|
code |
Type: integer Код ошибки. |
|
details |
Type: protobufAny[] Дополнительные сведения об ошибке. Example
|
|
message |
Type: string Описание ошибки. Example: |
404 Not Found
Запрашиваемый ресурс не найден.
Body
application/json
{
"code": 0,
"message": "example",
"details": [
{
"@type": "example"
}
]
}
|
Name |
Description |
|
code |
Type: integer Код ошибки. |
|
details |
Type: protobufAny[] Дополнительные сведения об ошибке. Example
|
|
message |
Type: string Описание ошибки. Example: |
500 Internal Server Error
Внутренняя ошибка сервиса. Попробуйте повторно отправить запрос через некоторое время.
Body
application/json
{
"code": 0,
"message": "example",
"details": [
{
"@type": "example"
}
]
}
|
Name |
Description |
|
code |
Type: integer Код ошибки. |
|
details |
Type: protobufAny[] Дополнительные сведения об ошибке. Example
|
|
message |
Type: string Описание ошибки. Example: |
Поиск пользователя по адресу электронной почты и загрузка аватара
-
Найдите пользователя по адресу электронной почты с помощью метода Просмотреть список:
- В качестве фильтра используйте query-параметр
email. - Замените
{orgId}на идентификатор вашей организации.
USER_ID=$(curl -s \ -H "Authorization: OAuth $TOKEN" \ "https://cloud-api.<ваш_домен>/v1/api360/directory/org/{orgId}/users/?email=ivan-petrov@example.com" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['users'][0]['id'])") echo "User ID: $USER_ID" - В качестве фильтра используйте query-параметр
-
Загрузите аватар для найденного пользователя:
- Замените
{orgId}на идентификатор вашей организации. - Укажите расположение аватара в файле
photo.jpg.
curl -s -X PUT \ -H "Authorization: OAuth $TOKEN" \ -H "Content-Type: image/jpeg" \ --data-binary @photo.jpg \ "https://cloud-api.<ваш_домен>/v1/api360/directory/org/{orgId}/users/$USER_ID/avatar" - Замените
Массовая загрузка аватаров для пользователей
Требования
-
Python 3
-
Модуль requests, установите с помощью команды:
pip install requests
Подготовка и запуск скрипта загрузки
Чтобы загрузить аватары для нескольких пользователей одновременно:
-
Подготовьте файлы изображений в формате JPG, JPEG, PNG.
-
Переименуйте файлы изображений. В названии укажите адрес электронной почты пользователя или его логин (
nickname) и расширение файла. Примеры: ivan@<ваш_домен>.jpg или ivan.jpeg.Скрипт берет из имени файла только часть до последней точки. Если имя файла ivan@<ваш_домен>.png, скрипт проверит наличие аккаунта с адресом ivan@<ваш_домен>. Имена доменов с любым количеством точек работают корректно.
Используйте поиск по адресу электронной почты
Он выполняется за один запрос. Поиск по логину перебирает аккаунты всех сотрудников организации. Если в организации много сотрудников, используйте в названиях файлов адрес электронной почты.
-
Разместите все файлы в одном каталоге.
-
Экспортируйте переменные:
export CLOUD_API_URL=https://cloud-api.<ваш_домен> export OAUTH_TOKEN=y0_AgAAAA... export ORG_ID=11Замените значения для
OAUTH_TOKENиORG_IDна собственные. -
Сохраните локально скрипт массовой загрузки аватаров пользователей upload_avatars_bulk.py.
Скрипт upload_avatars_bulk.py
""" Массовая загрузка аватаров пользователей. Скрипт ищет в указанном каталоге файлы вида <идентификатор>.<ext> и загружает их как аватары соответствующих пользователей организации. Формат имени файла: ivan@<ваш_домен>.jpg — поиск по email (один запрос с фильтром) robot-forms.jpeg — поиск по логину пользователя (перебор страниц) Переменные окружения: CLOUD_API_URL — базовый URL инсталляции, например https://cloud-api.<ваш_домен> OAUTH_TOKEN — OAuth-токен администратора организации ORG_ID — идентификатор организации Использование: python upload_avatars_bulk.py /path/to/photos/ python upload_avatars_bulk.py # текущий каталог python upload_avatars_bulk.py --dry-run # только проверить, не загружать """ import os import sys import mimetypes import argparse import requests from pathlib import Path from typing import List, Optional, Tuple BASE_URL = os.environ["CLOUD_API_URL"].rstrip("/") + "/v1/api360/directory" ORG_ID = os.environ["ORG_ID"] HEADERS = {"Authorization": f"OAuth {os.environ['OAUTH_TOKEN']}"} IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png"} class ApiError(Exception): def __init__(self, status_code, message): self.status_code = status_code self.message = message super().__init__(f"HTTP {status_code}: {message}") def _raise_for_response(resp: requests.Response) -> None: if resp.ok: return try: message = resp.json().get("message") or resp.text except Exception: message = resp.text raise ApiError(resp.status_code, message) def find_user_by_email(email: str) -> Optional[dict]: resp = requests.get( f"{BASE_URL}/org/{ORG_ID}/users/", headers=HEADERS, params={"email": email, "per_page": 1}, timeout=30, ) _raise_for_response(resp) users = resp.json().get("users", []) return users[0] if users else None def find_user_by_nickname(nickname: str) -> Optional[dict]: page = 1 while True: resp = requests.get( f"{BASE_URL}/org/{ORG_ID}/users/", headers=HEADERS, params={"page": page, "per_page": 100}, timeout=30, ) _raise_for_response(resp) data = resp.json() for user in data.get("users", []): if user["nickname"] == nickname: return user if page >= data.get("pages", 1): return None page += 1 def find_user(identifier: str) -> Optional[dict]: if "@" in identifier: return find_user_by_email(identifier) return find_user_by_nickname(identifier) def upload_avatar(user_id: int, file_path: Path) -> str: mime, _ = mimetypes.guess_type(str(file_path)) if not mime or not mime.startswith("image/"): mime = "image/jpeg" resp = requests.put( f"{BASE_URL}/org/{ORG_ID}/users/{user_id}/avatar", headers={**HEADERS, "Content-Type": mime}, data=file_path.read_bytes(), timeout=30, ) _raise_for_response(resp) return resp.json()["url"] def collect_files(directory: Path) -> List[Tuple[str, Path]]: """Возвращает список (identifier, path). identifier — email (с @) или логин пользователя (без @).""" result = [] for f in sorted(directory.iterdir()): if f.suffix.lower() not in IMAGE_EXTENSIONS: continue result.append((f.stem, f)) return result def main(): parser = argparse.ArgumentParser(description="Массовая загрузка аватаров по email или логину пользователя") parser.add_argument("directory", nargs="?", default=".", help="Каталог с фотографиями") parser.add_argument("--dry-run", action="store_true", help="Только проверить файлы, не загружать") args = parser.parse_args() directory = Path(args.directory) if not directory.is_dir(): print(f"Ошибка: '{directory}' не является каталогом.", file=sys.stderr) sys.exit(1) files = collect_files(directory) if not files: print("Файлы вида <email>.jpg / <email>.png не найдены.") return print(f"Найдено файлов: {len(files)}\n") ok = failed = skipped = 0 for identifier, path in files: print(f"{path.name}") try: user = find_user(identifier) except ApiError as e: print(f" ошибка при поиске пользователя: {e.message}") failed += 1 continue if not user: label = "email" if "@" in identifier else "логину" print(f" пользователь по {label} '{identifier}' не найден — пропускаю") skipped += 1 continue user_id = user["id"] print(f" → {user['nickname']} (id={user_id})", end="") if args.dry_run: print(" [dry-run, пропускаю]") skipped += 1 continue try: url = upload_avatar(user_id, path) print(f"\n ✓ {url}") ok += 1 except ApiError as e: print(f"\n ✗ {e.message}") failed += 1 print(f"\nИтого: загружено {ok}, пропущено {skipped}, ошибок {failed}.") if failed: sys.exit(1) if __name__ == "__main__": for var in ("CLOUD_API_URL", "OAUTH_TOKEN", "ORG_ID"): if not os.environ.get(var): print(f"Ошибка: переменная окружения {var} не задана.", file=sys.stderr) sys.exit(1) main() -
Проверьте работу скрипта без реальной загрузки файлов:
python upload_avatars_bulk.py ./<путь_к_каталогу_с_файлами>/ --dry-run -
Если скрипт отработал без ошибок, запустите его без параметра
--dry-run:python upload_avatars_bulk.py ./<путь_к_каталогу_с_файлами>/
Пример вывода
Найдено файлов: 4
ivan@<ваш_домен>.jpg
→ ivan-petrov (id=1130000000001656)
✓ https://avatars.<ваш_домен>/get-yapic/OYJoSi7oxLXsb9zMCgaI2na5f2U-1/normal
maria@<ваш_домен>.png
→ maria-sidorova (id=1130000000001657)
✓ https://avatars.<ваш_домен>/get-yapic/AbCdEfGhIjKlMnOp/normal
organization-owner.jpeg
→ organization-owner (id=1130000000000001)
✓ https://avatars.<ваш_домен>/get-yapic/XyZaBcDeFgHiJkLm/normal
unknown@<ваш_домен>.jpg
пользователь по email 'unknown@<ваш_домен>' не найден — пропускаю
Итого: загружено 3, пропущено 1, ошибок 0.