Добавление и настройка пользователей через API

Введение

В данной статье будет рассказано, как можно создавать и обновлять пользователей через DealApp API. Все методы, описанные ниже требуют авторизацию через пользователя с настроенными правами по обновлению пользователей. О том, как производить авторизацию, можно прочитать в статье

Доступ через API

Методы API

Пользователи (users)

GET /api/v1/users

Возвращает список пользователей, зарегистрированных в организации.

Параметры для создания пользователя

НазваниеОписание

with_inactive

По умолчанию endpoint возвращает список только активных пользователей. Чтобы получить список всех пользователей (в том числе и неактивных), к запросу нужно добавить параметр with_inactive=true

active

Фильтрует по активному статусу

units_ids

Фильтрует по отделам

roles_ids

Фильтрует по ролям

levels_ids

Фильтрует пользователей по уровню пользователя

invitation_status

Фильтрует по статусу приглашения. Возможные значения: no_invitation_sent, invitation_sent, invitation_accepted, user_blocked

Вместе с фильтрами есть возможность передавать параметр search, который будет фильтровать пользователей по частичному имени или email.

Пример Запроса

curl -X GET -H @headers.txt 'https://api.prod1.dealapp.io/api/v1/users?filters[active]=true&search=petr' | jq

Пример Ответа

{
  "data": [
    {
      "id": "2a6f96ae-c7e5-4a8f-9d56-e60fa30a40a7",
      "type": "users",
      "attributes": {
        "email": "petr.petrov@andrey-demo.com",
        "name": "Петр Петров ",
        "first-name": null,
        "last-name": "Петр Петров",
        "phone-number": null,
        "accepted-invitation": false,
        "integration-uid": "petr.petrov",
        "avatar-url": null,
        "active": true,
        "collisions-on-create": {},
        "invitation-sent": false,
        "last-active-at": null,
        "prefered-locale": "ru"
      },
      "relationships": {
        "role": {
          "data": {
            "id": "40aa6855-d789-4368-ba4a-a2166047f079",
            "type": "roles"
          }
        },
        "unit": {
          "data": {
            "id": "82d98a85-df2b-431c-bd6c-6307d27e89ae",
            "type": "units"
          }
        },
        "level": {
          "data": null
        },
        "origin-integration": {
          "data": null
        }
      }
    }
  ],
  "meta": {
    "page": 1,
    "total-pages": 1,
    "total-count": 1
  }
}

Так же можно добавить в запрос параметр include=unit,role, чтобы вместе с ответом получить вложенную информацию об отделе и роле пользователя. Пример ответа со вложением: get-users-example.json

POST /api/v1/users

Создание пользователя с предоставленными данными.

НазваниеТипОписание

email

string (required)

email для входа пользователя в систему

password

string

Пароль для входа пользователя. Указывать не обязательно.

unit_id

string (uuid) (required)

UUID объекта отдела, в котором будет находиться пользователь. Список отделов можно получить по endpoint'у /api/v1/organization/units

role_id

string (uuid) (required)

UUID объекта роли, с которым будет создаваться пользователь. Список ролей можно получить по endpoint'у /api/v1/organization/roles

last_name

string (required)

Фамилия

first_name

string

Имя и Отчество

integration_uid

string

Идентификатор пользователя в интегрируемой системе. При передаче данных в Custom HTTP интеграциях это поле помогает определить пользователя по данным из поля operator_id.

Пример Запроса

curl -X POST  -H "Content-Type: application/json" -H @headers.txt -d @new-user-attributes.json https://api.prod1.dealapp.io/api/v1/users

Данные Запроса (new-user-attributes.json):

{
  "email": "test-user@test.org",
  "password": "some-password",
  "unit_id": "877408ca-1f18-48ee-b59c-2a72fbbf5729",
  "role_id": "78376e55-a6ca-4e74-94c3-9a6b562abc78",
  "last_name": "Test",
  "first_name": "User",
  "integration_uid": "402"
}

Пример Ответа:

{
  "data": {
    "id": "5dbd25de-f421-40d8-bc6b-f87ad18fba83",
    "type": "users",
    "attributes": {
      "email": "test-user@test.org",
      "name": "Test User",
      "first-name": "User",
      "last-name": "Test",
      "phone-number": null,
      "accepted-invitation": false,
      "integration-uid": "402",
      "avatar-url": null,
      "active": true,
      "collisions-on-create": {},
      "invitation-sent": false,
      "last-active-at": null,
      "prefered-locale": "ru"
    },
    "relationships": {
      "role": {
        "data": {
          "id": "78376e55-a6ca-4e74-94c3-9a6b562abc78",
          "type": "roles"
        }
      },
      "unit": {
        "data": {
          "id": "877408ca-1f18-48ee-b59c-2a72fbbf5729",
          "type": "units"
        }
      },
      "level": {
        "data": null
      },
      "origin-integration": {
        "data": null
      }
    }
  }
}

Параметры для обновления пользователя

PUT /api/v1/users/:user_id

Обновить данные пользователя с ID пользователя user_id

НазваниеТипОписание

email

string

last_name

string

first_name

string

active

boolean

role_id

string (uuid)

unit_id

string (uuid)

level_id

string (uuid)

avatar

string (base64)

phone_number

string

integration_uid

string

password

string

password_confirmation

string

prefered_locale

string

Пример запроса

curl -X PUT  -H "Content-Type: application/json" -H @headers.txt -d '{"active": true}' https://api.prod1.dealapp.io/api/v1/users/5dbd25de-f421-40d8-bc6b-f87ad18fba83 | jq

Ответ при этом будет приходить такой же как и при создании пользователя:

Добавление и настройка пользователей через API

Отделы (organization-units)

GET /api/v1/organization/units

Возвращает список существующих отделов организации

Название

name

parent_id

integration_uid

parent_integration_uid

POST /api/v1/organization/units

Создает отдел организации с указанными параметрами

На создание мы принимаем следующие данные: name, integration_uid, parent_id

parent_id это id родительского отдела в DealApp


PUT /api/v1/organization/units/:id

Обновляет отделы организации


Пример загрузки пользователей из CSV с помощью python

В данном разделе будет рассмотрено, как можно загрузить и обновлять список пользователей в автоматическом режиме. Мы напишем скрипт на Python 2.7, так как он встроен в большинство дистрибутивов линукс. Скрипт будет читать данные из CSV файла и делать вызовы на API описанные выше. Мы напишем скрипт таким образом, что мы так же сможем с помощью него обновлять данные о пользователях после того, как пользователи уже будут созданы.

Входные данные

Пример файла для импорта:

users.csv:

ФИО	id	email	Отдел	Роль
Станислав Быков (Рук. ОП)	401	stanislav.bykov@test.org	Головной Отдел	Супервизор
Иван Михалевич (спец. ОП)	402	ivan.mihalevich@test.org	Головной Отдел	Оператор
Мария Юрченко (спец. ОП)	403	maria.yurchenko@test.org	Головной Отдел	Оператор
Юлия Иванова (спец. ОП)	405	yulia.ivanova@test.org	Головной Отдел	Оператор

В этом файле указаны следующие колонки: ФИО, id, email, Отдел, Роль.

  • ФИО - имя и фамилия сотрудника

  • id - уникальный идентификатор клиента, который будет позже использоваться как operator_id в API вызовах Custom Http интеграции

  • Отдел - название отдела, которое должно совпадать с отделом, указанным на вкладке "Структура организации" на странице "Сотрудники и права доступа"

  • Роль - название роли пользователя, которые можно найти на вкладке настройки ролей на странице "Сотрудники и права доступа"

Клиент для работы с DealApp

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

dealapp_client.py:

import sys, time, re, json, os.path, glob, requests, pprint, inspect, csv

from os import path

DEALAPP_API_URL="https://api.prod1.dealapp.io"

def dealapp_path(path):
  return DEALAPP_API_URL + path

class DealAppClient:
  def __init__(self, email, password):
    self.email = email
    self.password = password

  def sign_in(self):
    response = requests.post(
      url=dealapp_path("/auth/sign_in"),
      data=json.dumps({"email": self.email, "password": self.password}),
      headers=self.__default_headers()
    )
    self.__process_jsonapi_response(response)
    self.uid = response.headers["uid"]
    self.client = response.headers["client"]
    self.access_token = response.headers["access-token"]

  def create_user(self, params):
    response = requests.post(
      url=dealapp_path("/api/v1/users"),
      data=json.dumps(params),
      headers=self.__authorized_headers()
    )
    return self.__process_jsonapi_response(response)
    
  def update_user(self, user_id, params):
    response = requests.put(
      url=dealapp_path("/api/v1/users/" + user_id),
      data=json.dumps(params),
      headers=self.__authorized_headers()
    )
    return self.__process_jsonapi_response(response)

  def find_user_by_email(self, email):
    response = requests.get(
      url=dealapp_path("/api/v1/users"),
      params={'search': email},
      headers=self.__authorized_headers()
    )
    users_response = self.__process_jsonapi_response(response)
    if (len(users_response) > 0):
      return users_response[0]
    else:
      return None

  def get_units(self):
    response = requests.get(
      url=dealapp_path("/api/v1/organization/units"),
      headers=self.__authorized_headers()
    )
    return self.__process_jsonapi_response(response)


  def get_roles(self):
    response = requests.get(
      url=dealapp_path("/api/v1/organization/roles"),
      headers=self.__authorized_headers()
    )
    return self.__process_jsonapi_response(response)

  def __process_jsonapi_response(self, response):
    if(response.status_code != 200):
      print("Can't perform request, error response: " + response.text)
      sys.exit(1)
    return json.loads(response.text)["data"]


  def __default_headers(self):
    return {'Content-Type': 'application/json'}

  def __authorized_headers(self):
    return {'Content-Type': 'application/json', 'uid': self.uid, 'access-token': self.access_token, 'client': self.client}

Скрипт для импорта пользователей

# -*- coding: utf-8 -*-

import sys, time, re, json, os.path, glob, requests, pprint, inspect, csv

from dealapp_client import DealAppClient

ADMIN_EMAIL="admin@test.org"
ADMIN_PASSWORD="bestdeal"

def load_users_from_csv(csv_file_path):
  users = []
  with open(csv_file_path, mode='r') as csv_file:
    csv_reader = csv.DictReader(csv_file, delimiter='\t')
    line_count = 0
    for row in csv_reader:
      if line_count == 0:
        line_count += 1
      line_count += 1
      users.append(row)
  return users

def index(l, f):
     return next((i for i in xrange(len(l)) if f(l[i])), None)

def memoize(f):
    memo = {}
    def memoize_wrapper(dealapp_client, name):
        if name not in memo:
            memo[name] = f(dealapp_client, name)
        return memo[name]
    return memoize_wrapper

def get_unit_id_by_unit_name(dealapp_client, unit_name):
  units_response = dealapp_client.get_units()
  unit = units_response[index(units_response, lambda item: (item["attributes"]["name"] == unit_name.decode('utf-8')))]
  return unit["id"]

def get_role_id_by_unit_name(dealapp_client, role_name):
  roles_response = dealapp_client.get_roles()
  role = roles_response[index(roles_response, lambda item: (item["attributes"]["name"] == role_name.decode('utf-8')))]
  return role["id"]

def get_user_params(dealapp_client, user):
  unit_id = memoize(get_unit_id_by_unit_name)(dealapp_client, user["Отдел"])
  role_id = memoize(get_role_id_by_unit_name)(dealapp_client, user["Роль"])
  last_name = user["ФИО"].split(" ", 1)[0]
  first_name = user["ФИО"].split(" ", 1)[1]
  return {
    "last_name": last_name,
    "first_name": first_name,
    "email": user["email"],
    "integration_uid": user["id"],
    "unit_id": unit_id,
    "role_id": role_id
  }

def main():
  dealapp_client = DealAppClient(ADMIN_EMAIL, ADMIN_PASSWORD)
  print("Logging into DealApp as {}".format(ADMIN_EMAIL))
  dealapp_client.sign_in()
  print("Logging Done")

  print("Reading users info from users.csv")
  users = load_users_from_csv("./users.csv")
  for user in users:
    print("Importing {} with id {}".format(user["ФИО"], user["id"]))
    existing_user_info = dealapp_client.find_user_by_email(user["email"])
    user_params = get_user_params(dealapp_client, user)
    if(existing_user_info):
      print("User already exists: updating user {}".format(user["ФИО"]))
      dealapp_client.update_user(existing_user_info["id"], user_params)
      print("User Updated")
    else:
      print("Creating user {}".format(user["ФИО"]))
      dealapp_client.create_user(user_params)
      print("User Created")

if __name__ == '__main__':
    main()

В случае, если все прошло успешно, мы будем видеть следующий текст в консоле после

→ python import_users.py
Logging into DealApp as admin@test.org
Logging Done
Reading users info from users.csv
Importing Станислав Быков (Рук. ОП) with id 401
Creating user Станислав Быков (Рук. ОП)
User Created
Importing Иван Михалевич (спец. ОП) with id 402
Creating user Иван Михалевич (спец. ОП)
User Created
Importing Мария Юрченко (спец. ОП) with id 403
Creating user Мария Юрченко (спец. ОП)
User Created
Importing Юлия Иванова (спец. ОП) with id 405
Creating user Юлия Иванова (спец. ОП)
User Created

Last updated