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

Введение

В данной статье будет рассказано, как можно создавать и обновлять пользователей через DealApp 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": "[email protected]",
"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": "[email protected]",
"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": "[email protected]",
"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
Ответ при этом будет приходить такой же как и при создании пользователя:

Отделы (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 [email protected] Головной Отдел Супервизор
Иван Михалевич (спец. ОП) 402 [email protected] Головной Отдел Оператор
Мария Юрченко (спец. ОП) 403 [email protected] Головной Отдел Оператор
Юлия Иванова (спец. ОП) 405 [email protected] Головной Отдел Оператор
В этом файле указаны следующие колонки: ФИО, 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="[email protected]"
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 [email protected]
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