Загрузить портрет

Управляет потретами пользователей организации. Работает только для пользователей, созданных на домене организации.

Пример:

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: example

400 Bad Request

Некорректный запрос.

Body

application/json
{
  "code": 0,
  "message": "example",
  "details": [
    {
      "@type": "example"
    }
  ]
}

Name

Description

code

Type: integer

Код ошибки.

details

Type: protobufAny[]

Дополнительные сведения об ошибке.

Example
[
  {
    "@type": "example"
  }
]

message

Type: string

Описание ошибки.

Example: example

protobufAny

Name

Description

@type

Type: string

Example: example

[additional]

Type: unknown

Example: null

Example
{
  "@type": "example"
}

401 Unauthorized

Пользователь не авторизован.

Body

application/json
{
  "code": 0,
  "message": "example",
  "details": [
    {
      "@type": "example"
    }
  ]
}

Name

Description

code

Type: integer

Код ошибки.

details

Type: protobufAny[]

Дополнительные сведения об ошибке.

Example
[
  {
    "@type": "example"
  }
]

message

Type: string

Описание ошибки.

Example: example

403 Forbidden

У пользователя или приложения нет прав на доступ к ресурсу, запрос отклонен.

Body

application/json
{
  "code": 0,
  "message": "example",
  "details": [
    {
      "@type": "example"
    }
  ]
}

Name

Description

code

Type: integer

Код ошибки.

details

Type: protobufAny[]

Дополнительные сведения об ошибке.

Example
[
  {
    "@type": "example"
  }
]

message

Type: string

Описание ошибки.

Example: example

404 Not Found

Запрашиваемый ресурс не найден.

Body

application/json
{
  "code": 0,
  "message": "example",
  "details": [
    {
      "@type": "example"
    }
  ]
}

Name

Description

code

Type: integer

Код ошибки.

details

Type: protobufAny[]

Дополнительные сведения об ошибке.

Example
[
  {
    "@type": "example"
  }
]

message

Type: string

Описание ошибки.

Example: example

500 Internal Server Error

Внутренняя ошибка сервиса. Попробуйте повторно отправить запрос через некоторое время.

Body

application/json
{
  "code": 0,
  "message": "example",
  "details": [
    {
      "@type": "example"
    }
  ]
}

Name

Description

code

Type: integer

Код ошибки.

details

Type: protobufAny[]

Дополнительные сведения об ошибке.

Example
[
  {
    "@type": "example"
  }
]

message

Type: string

Описание ошибки.

Example: example

Поиск пользователя по адресу электронной почты и загрузка аватара

  1. Найдите пользователя по адресу электронной почты с помощью метода Просмотреть список:

    • В качестве фильтра используйте 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"
    
  2. Загрузите аватар для найденного пользователя:

    • Замените {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
    

Подготовка и запуск скрипта загрузки

Чтобы загрузить аватары для нескольких пользователей одновременно:

  1. Подготовьте файлы изображений в формате JPG, JPEG, PNG.

  2. Переименуйте файлы изображений. В названии укажите адрес электронной почты пользователя или его логин (nickname) и расширение файла. Примеры: ivan@<ваш_домен>.jpg или ivan.jpeg.

    Скрипт берет из имени файла только часть до последней точки. Если имя файла ivan@<ваш_домен>.png, скрипт проверит наличие аккаунта с адресом ivan@<ваш_домен>. Имена доменов с любым количеством точек работают корректно.

    Используйте поиск по адресу электронной почты

    Он выполняется за один запрос. Поиск по логину перебирает аккаунты всех сотрудников организации. Если в организации много сотрудников, используйте в названиях файлов адрес электронной почты.

  3. Разместите все файлы в одном каталоге.

  4. Экспортируйте переменные:

    export CLOUD_API_URL=https://cloud-api.<ваш_домен>
    export OAUTH_TOKEN=y0_AgAAAA...
    export ORG_ID=11
    

    Замените значения для OAUTH_TOKEN и ORG_ID на собственные.

  5. Сохраните локально скрипт массовой загрузки аватаров пользователей 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()
    
  6. Проверьте работу скрипта без реальной загрузки файлов:

    python upload_avatars_bulk.py ./<путь_к_каталогу_с_файлами>/ --dry-run
    
  7. Если скрипт отработал без ошибок, запустите его без параметра --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.