Retrieve User (All)
Overview¶
You can use the API to retrieve user records.
Preparations¶
Please Create an API Key before performing API operations.
Supported Versions¶
ApiGetMailAddresses¶
- Pleasanter 1.3.16.0 or later
Request¶
Send json data in the following request format:
| Setting column | Value |
|---|---|
| HTTP Method | POST |
| Content-Type | application/json |
| Character Code | UTF-8 |
| URL | http://{server name}/api/users/get (*1) |
| Body | Refer to the json data below |
(*1) Please edit the {server name} part to suit your environment as appropriate.
For Pleasanter.net, the format is as follows:
https://pleasanter.net/fs/api/users/get
JSON¶
{
"ApiVersion": 1.1,
"ApiKey": "610saf33fg52D3Sas2f7g32...",
"View": {
"ApiGetMailAddresses": true
}
}
*ApiGetMailAddress is optional (not required). If omitted, false is specified. If true is specified, the response will include the email address in an array, as shown in the following example.
Response¶
The following json data format will be returned. Please refer to here for the data layout (password cannot be obtained).
The following column will only be output when executed with the tenant manager's API key.
| Output column | Name displayed on screen |
|---|---|
| LastLoginTime | Last login datetime |
| PasswordExpirationTime | Password expiration datetime |
| PasswordChangeTime | Password change datetime |
| NumberOfLogins | Number of logins |
| NumberOfDenial | Number of failed logins |
| TenantManager | Tenant manager |
| Disabled | Disabled |
| Lockout | Lock |
| LockoutCounter | Lock counter |
(a) When executed with a tenant manager's API key¶
JSON¶
{
"StatusCode": 200,
"Response": {
"Offset": 0,
"PageSize": 200,
"TotalCount": 1,
"Data": [
{
"TenantId": 12345,
"UserId": 12345,
"Ver": 1,
"LoginId": "hayato",
"GlobalId": "",
"Name": "Hayato Nakano",
"UserCode": "",
"Birthday": "2016-03-27T00:00:00",
"Gender": "",
"Language": "ja",
"TimeZone": "Tokyo Standard Time",
"DeptCode": "",
"DeptId": 0,
"Theme": "",
"Body": "",
"LastLoginTime": "2023-08-17T12:00:00",
"PasswordExpirationTime": "2023-08-31T12:00:00",
"PasswordChangeTime": "2023-06-02T12:00:00",
"NumberOfLogins": 100,
"NumberOfDenial": 5,
"TenantManager": false,
"Disabled": false,
"Lockout": false,
"LockoutCounter": 0,
"UserSettings": "{}",
"SecondaryAuthenticationCode": "",
"SecondaryAuthenticationCodeExpirationTime": "1899-12-30T00:00:00",
"LdapSearchRoot": "",
"SynchronizedTime": "1899-12-30T00:00:00",
"Comments": "[]",
"Creator": 2,
"Updator": 1,
"CreatedTime": "2023-04-01T12:00:00",
"UpdatedTime": "2023-08-15T12:00:00",
"MailAddresses": [
"webmaster@example.com",
"info@example.com"
],
"ApiVersion": 1.1,
"ClassHash": {
},
"NumHash": {
},
"DateHash": {
},
"DescriptionHash": {
},
"CheckHash": {
},
"AttachmentsHash": {
}
}
]
}
}
(b) When executed with an API key other than that of the tenant manager¶
JSON¶
{
"StatusCode": 200,
"Response": {
"Offset": 0,
"PageSize": 200,
"TotalCount": 1,
"Data": [
{
"TenantId": 12345,
"UserId": 12345,
"Ver": 1,
"LoginId": "hayato",
"GlobalId": "",
"Name": "Hayato Nakano",
"UserCode": "",
"Birthday": "2016-03-27T00:00:00",
"Gender": "",
"Language": "ja",
"TimeZone": "Tokyo Standard Time",
"DeptCode": "",
"DeptId": 0,
"Theme": "",
"Body": "",
"UserSettings": "{}",
"SecondaryAuthenticationCode": "",
"SecondaryAuthenticationCodeExpirationTime": "1899-12-30T00:00:00",
"LdapSearchRoot": "",
"SynchronizedTime": "1899-12-30T00:00:00",
"Comments": "[]",
"Creator": 2,
"Updator": 1,
"CreatedTime": "2023-04-01T12:00:00",
"UpdatedTime": "2023-08-15T12:00:00",
"MailAddresses": [
"webmaster@example.com",
"info@example.com"
],
"ApiVersion": 1.1,
"ClassHash": {
},
"NumHash": {
},
"DateHash": {
},
"DescriptionHash": {
},
"CheckHash": {
},
"AttachmentsHash": {
}
}
]
}
}
Code Samples¶
Modify 【 ... 】 in the code as necessary.¶
1. Read CSV files from an external system and create/update groups and their parent-child relationships
This sample registers groups and their parent-child relationships
with the Pleasanter Create Group API / Update Group API,
based on CSV files output from an external system.
Overview¶
It receives the organization information of an external system as CSV files,
and builds the group structure with the Pleasanter Create Group and Update Group APIs.
This sample works in two phases.
| Phase | Process |
|---|---|
| Phase1 | Create / update the groups themselves and their members |
| Phase2 | Update the parent-child relationships of the groups |
The process flow is as follows.
- Read the input CSV files
- Get the existing groups from Pleasanter (/api/groups/get)
- Get the existing users from Pleasanter (/api/users/get)
- Phase1 - Decide whether to create or update based on the group name, and register the groups themselves and their members (/api/groups/create or /api/groups/{GroupId}/update)
- Get the existing groups from Pleasanter again (/api/groups/get)
- Phase2 - Update the groups again, including the parent-child relationships (/api/groups/{GroupId}/update)
Prerequisites¶
The users are already registered in Pleasanter
Group names are unique (used to decide whether to create or update)
Input Files¶
There are four input files.
groups.csv¶
Defines the group information.
| Column name | Description |
|---|---|
| group_code | Group identification code |
| group_name | Group name |
| is_active | 1: Enabled / 0: Disabled |
| remark | Description |
Sample
group_code,group_name,is_active,remark
GRP_ADMIN,Administration Headquarters,1,Administration division
GRP_SALES,Sales Headquarters,1,Sales division
GRP_EAST,East Japan Sales Department,1,Sales in East Japan
users.csv¶
Defines the user information.
| Column name | Description |
|---|---|
| user_id | User identification ID |
| login_id | Pleasanter login ID |
| user_name | User name |
| is_active | 1: Enabled / 0: Disabled |
Sample
user_id,login_id,user_name,mail,is_active
0001,yamada.taro,Taro Yamada,yamada@example.co.jp,1
0002,sato.hanako,Hanako Sato,sato@example.co.jp,1
user_group_memberships.csv¶
Defines the member information of the groups.
| Column name | Description |
|---|---|
| user_id | User ID |
| group_code | Group code |
| is_active | 1: Enabled / 0: Disabled |
| is_group_admin | 1: Group administrator / 0: Regular user |
Sample
group_relations.csv¶
Defines the parent-child relationships of the groups.
| Column name | Description |
|---|---|
| parent_group_code | Parent group |
| child_group_code | Child group |
| is_active | 1: Included / 0: Excluded |
Sample
Python(api_group_upsert.py)¶
import csv
import json
from pathlib import Path
import requests
# ==============================
# Pleasanter connection settings
# ==============================
BASE_URL = "【URL】"
API_KEY = "【API key】"
API_VERSION = 1.1
# ==============================
# File settings (change them as appropriate for your environment)
# ==============================
INPUT_DIR = Path("./input")
GROUPS_CSV = INPUT_DIR / "groups.csv"
USERS_CSV = INPUT_DIR / "users.csv"
MEMBERSHIPS_CSV = INPUT_DIR / "user_group_memberships.csv"
RELATIONS_CSV = INPUT_DIR / "group_relations.csv"
# ==============================
# CSV input settings (change them as appropriate for your environment)
# ==============================
def read_csv(path):
with open(path, "r", encoding="utf-8-sig", newline="") as f:
return [
{k.strip(): (v or "").strip() for k, v in row.items()}
for row in csv.DictReader(f)
]
def is_active(row):
return str(row.get("is_active", "1")).strip() == "1"
def to_bool_text(value):
return "True" if str(value).strip() == "1" else "False"
# ==============================
# Pleasanter API operations
# ==============================
def post_json(url, payload):
r = requests.post(
url,
json=payload,
headers={"Content-Type": "application/json"},
timeout=60,
)
r.raise_for_status()
return r.json()
# ==============================
# Get groups
# ==============================
def get_groups():
data = post_json(
f"{BASE_URL}/api/groups/get",
{"ApiVersion": API_VERSION, "ApiKey": API_KEY},
)
return {
row["GroupName"]: row
for row in data.get("Response", {}).get("Data", [])
if row.get("GroupName")
}
# ==============================
# Get users
# ==============================
def get_users():
data = post_json(
f"{BASE_URL}/api/users/get",
{"ApiVersion": API_VERSION, "ApiKey": API_KEY},
)
return {
row["LoginId"]: row
for row in data.get("Response", {}).get("Data", [])
if row.get("LoginId")
}
# ==============================
# Create/update a group
# ==============================
def upsert_group(group_name, payload, existing_groups):
current = existing_groups.get(group_name)
if current:
url = f"{BASE_URL}/api/groups/{current['GroupId']}/update"
result = post_json(url, payload)
print(f"[UPDATE] {group_name}")
else:
url = f"{BASE_URL}/api/groups/create"
result = post_json(url, payload)
print(f"[CREATE] {group_name}")
return result
# ==============================
# Set the group members
# ==============================
def build_member_map(memberships):
result = {}
for row in memberships:
if not is_active(row):
continue
group_code = row["group_code"]
result.setdefault(group_code, []).append(row)
return result
# ==============================
# Build the parent-child relationships
# ==============================
def build_relation_map(relations):
result = {}
for row in relations:
if not is_active(row):
continue
parent_code = row["parent_group_code"]
result.setdefault(parent_code, []).append(row["child_group_code"])
return result
# ==============================
# Build the request payload for Phase1
# ==============================
def build_payload_phase1(group_row, member_rows, users_by_id, pleasanter_users):
members = []
for row in member_rows:
user = users_by_id[row["user_id"]]
login_id = user["login_id"]
pleasanter_user = pleasanter_users[login_id]
user_id = pleasanter_user["UserId"]
is_admin = to_bool_text(row.get("is_group_admin", "0"))
members.append(f"User,{user_id},{is_admin}")
return {
"ApiVersion": API_VERSION,
"ApiKey": API_KEY,
"GroupName": group_row["group_name"],
"Body": group_row.get("remark", ""),
"GroupMembers": members,
"GroupChildren": [],
}
# ==============================
# Build the request payload for Phase2
# ==============================
def build_payload_phase2(
group_row,
member_rows,
child_codes,
users_by_id,
groups_by_code,
pleasanter_users,
existing_groups,
):
members = []
for row in member_rows:
user = users_by_id[row["user_id"]]
login_id = user["login_id"]
pleasanter_user = pleasanter_users[login_id]
user_id = pleasanter_user["UserId"]
is_admin = to_bool_text(row.get("is_group_admin", "0"))
members.append(f"User,{user_id},{is_admin}")
children = []
for child_code in child_codes:
child_name = groups_by_code[child_code]["group_name"]
child_group = existing_groups[child_name]
children.append(f"Group,{child_group['GroupId']},")
return {
"ApiVersion": API_VERSION,
"ApiKey": API_KEY,
"GroupName": group_row["group_name"],
"Body": group_row.get("remark", ""),
"GroupMembers": members,
"GroupChildren": children,
}
# ==============================
# Main process
# ==============================
def main():
groups = read_csv(GROUPS_CSV)
users = read_csv(USERS_CSV)
memberships = read_csv(MEMBERSHIPS_CSV)
relations = read_csv(RELATIONS_CSV)
groups_by_code = {row["group_code"]: row for row in groups}
users_by_id = {row["user_id"]: row for row in users}
members_by_group = build_member_map(memberships)
children_by_parent = build_relation_map(relations)
pleasanter_users = get_users()
existing_groups = get_groups()
# Phase 1: Create/update all groups (without child groups)
print("=== Phase 1 ===")
for group in groups:
payload = build_payload_phase1(
group,
members_by_group.get(group["group_code"], []),
users_by_id,
pleasanter_users,
)
upsert_group(group["group_name"], payload, existing_groups)
existing_groups = get_groups()
# Phase 2: Update the parent-child relationships
print("=== Phase 2 ===")
existing_groups = get_groups()
for group in groups:
payload = build_payload_phase2(
group,
members_by_group.get(group["group_code"], []),
children_by_parent.get(group["group_code"], []),
users_by_id,
groups_by_code,
pleasanter_users,
existing_groups,
)
upsert_group(group["group_name"], payload, existing_groups)
if __name__ == "__main__":
main()
Run¶
Execution Result¶
Confirmation Column in Case of Error¶
・Precautions when using the API and things to check if an error occurs
・FAQ: What to check if modified configuration files or API requests (JSON format) are not recognized correctly
Specification Changes¶
*API specifications have been partially changed since November 2018.**
- The URL format has been changed from '/pleasanter/api_items/xxxx' to '/pleasanter/api/items/xxxx'.
- The Content-Type specification has been changed from 'application/x-www-form-urlencoded' to 'application/json'.