配置自定义脚本
管理员可以通过自定义脚本的配置方式, 把上游身份系统中的用户字段, 经过脚本运算, 转化成腾讯统一身份的用户字段。
比如以Active Directory作为上游, 把AD中的用户同步至统一身份中, 如果AD中没有邮箱信息, 那么可以通过user.sAMAccountName + "@example.com"
来转化用户的邮箱字段。
基础语法
-
脚本注释: 支持//或者/* */的方式, 比如
1// this is a comment2user.sAMAccountName + "@example.com" -
常量:
类型 说明 bool true或false int 整形, 比如 1000 float 浮点, 比如 0.5 string 字符串, 需要用""或''括起来, 比如"hello" array 数组,比如["first", "second", "third"] map 字典,比如{first:1, second:2, third:3} nil 空值, 类似于其他编程语言中的null -
运算符:
分类 说明 数学运算 + - * /
, 比如user.age * 2
比较运算 == != > < >= <=
, 比如user.age >= 30
逻辑运算 not
或!
,and
或&&
,or
或||
, 比如user.authed && user.type == "employee"
条件运算 ?:
三元操作符, 比如user.age >= 30 ? "tea" : "cola"
字符运算 +
拼接,contains
包含,startsWith
开头,endsWith
结尾, 比如user.name startsWith "zhang"
字典成员访问 支持 []
或.
的方式从字典中访问特定的成员, 比如user.name
或user["name"]
数组下标成员访问 支持 []
的方式从数组中访问特定下标的成员, 比如user.hobbies[0]
-
变量声明:
1let x = 5;2let y = 2;3x * y -
内置函数
-
字符串操作
函数名 说明 示例 upper(str) 把字符转换成大写 upper("hello")
返回"HELLO"lower(str) 把字符转换成小写 lower("HELLO")
返回"hello"title(str) 首字母大写 title("hello")
返回"Hello"hasPrefix(str,prefix) 判断是否前缀开头 hasPrefix("hello", "he")
返回truehasSuffix(str,suffix) 判断是否后缀结尾 hasSuffix("hello", "lo")
返回truetrimPrefix(str,suffix) 去除字符串的指定前缀 trimPrefix("helloWorld", "hello")
返回"World"trimSuffix(str,suffix) 去除字符串的指定前缀 trimSuffix("helloWorld", ",World")
返回"hello" -
数字操作
函数名 说明 示例 max(n1,n2) 取大值 max(10,20)
返回20min(n1,n2) 取小值 min(10,20)
返回10abs(n) 取绝对值 abs(-10)
返回10 -
数组操作
函数名 说明 示例 all(arr,predicate) 当数组中所有元素满足predicate时返回true all([1,2,3,4], # >0)
返回trueany(arr,predicate) 当数组中任意元素满足predicate时返回true any([1,0,2,-1], # >0)
返回truenone(arr,predicate) 当数组中所有元素都不满足predicate时返回true none([-1,-2,-3,-4], # >0)
返回truefilter(arr,predicate) 过滤数组中所有满足predicate的元素 filter([1,2,3,4], # >=3)
返回[3,4]len(arr) 返回数组长度 len([1,2,3,4])
返回4 -
map操作
函数名 说明 示例 keys(map) 返回map中的所有key keys({name:"zhangsan",age:20})
返回["age","name"]values(map) 返回map中的所有值 values({name:"zhangsan",age:20})
返回[20,"zhangsan"]len(map) 返回map长度 len({name:"zhangsan",age:20})
返回2 -
类型转化
函数名 说明 示例 int(v) 把整形字符串转化为integer, 若转化字符串为非整形,则报错 int("123")
返回123float(v) 把浮点型字符串转化为float, 若转化字符串为非浮点型,则报错 float("1.5")
返回1.5string(v) 把任意类型转化为string string(1.5)
返回"1.5"toJSON(v) 化为json string toJSON({name:"zhangsan", age:20})
返回'{ "age": 20, "name": "zhangsan" }'fromJSON(str) 把json string反序列化 fromJSON('{ "age": 20, "name": "zhangsan" }')
返回一个map对象toBase64(str) base64编码 toBase64("hello")
返回"aGVsbG8="fromBase64(str) base64解码 fromBase64("aGVsbG8=")
返回"hello" -
其他
函数名 说明 示例 ddExtAttr(key, extension) 获取钉钉用户扩展字段 ddExtAttr("name","{\"name\":\"张三\",\"hobby\":\"football\"}")
返回"张三"
-
常见自定义脚本场景
此章节将罗列用户常见的自定义脚本场景,我们以飞书提供的数据结构为例:
1{2 "union_id": "on_94a1ee5551019f18cd73d9f111898cf2",3 "user_id": "3e3cf96b",4 "open_id": "ou_7dab8a3d3cdcc9da365777c7ad535d62",5 "name": "张三",6 "en_name": "SanZhang",7 "nickname": "AlexZhang",8 "email": "zhangsan@gmail.com",9 "mobile": "+8613011111111",10 "mobile_visible": false,11 "gender": 1,12 "avatar": {13 "avatar_72": "https://foo.icon.com/xxxx",14 "avatar_240": "https://foo.icon.com/xxxx",15 "avatar_640": "https://foo.icon.com/xxxx",16 "avatar_origin": "https://foo.icon.com/xxxx"17 },18 "status": {19 "is_frozen": false,20 "is_resigned": false,21 "is_activated": true,22 "is_exited": false,23 "is_unjoin": false24 },25 "department_ids": [26 "od-4e6ac4d14bcd5071a37a39de902c7141"27 ],28 "leader_user_id": "ou_7dab8a3d3cdcc9da365777c7ad535d62",29 "city": "杭州",30 "country": "CN",31 "work_station": "北楼-H34",32 "join_time": 2147483647,33 "is_tenant_manager": false,34 "employee_no": "1",35 "employee_type": 1,36 "orders": [{37 "department_id": "od-4e6ac4d14bcd5071a37a39de902c7141",38 "user_order": 100,39 "department_order": 100,40 "is_primary_dept": true41 }],42 "custom_attrs": [{43 "type": "TEXT",44 "id": "DemoId",45 "value": {46 "text": "DemoText",47 "url": "http://www.fs.cn",48 "pc_url": "http://www.fs.cn",49 "option_value": "option",50 "name": "name",51 "picture_url": "https://xxxxxxxxxxxxxxxxxx",52 "generic_user": {53 "id": "9b2fabg5",54 "type": 155 }56 }57 }],58 "enterprise_email": "demo@mail.com",59 "job_title": "xxxxx",60 "geo": "cn",61 "job_level_id": "mga5oa8ayjlp9rb",62 "job_family_id": "mga5oa8ayjlp9rb",63 "assign_info": [{64 "subscription_id": "7079609167680782300",65 "license_plan_key": "suite_enterprise_e5",66 "product_name": "旗舰版E5",67 "i18n_name": {68 "zh_cn": "zh_cn_name",69 "ja_jp": "ja_jp_name",70 "en_us": "en_name"71 },72 "start_time": "1674981000",73 "end_time": "1674991000"74 }],75 "department_path": [{76 "department_id": "od-4e6ac4d14bcd5071a37a39de902c7141",77 "department_name": {78 "name": "测试部门名1",79 "i18n_name": {80 "zh_cn": "测试部门名1",81 "ja_jp": "試験部署名1",82 "en_us": "Testingdepartmentname1"83 }84 },85 "department_path": {86 "department_ids": [87 "od-4e6ac4d14bcd5071a37a39de902c7141"88 ],89 "department_path_name": {90 "name": "测试部门名1",91 "i18n_name": {92 "zh_cn": "测试部门名1",93 "ja_jp": "試験部署名1",94 "en_us": "Testingdepartmentname1"95 }96 }97 }98 }],99 "dotted_line_leader_user_ids": [100 "ou_7dab8a3d3cdcc9da365777c7ad535d62"101 ]102}
场景一:单层级数据获取
举例:假如我们需要获取以上数据中的en_name
字段属性。此时我们的脚本可以编写为user.en_name
场景二:多层级数据获取
举例:假如我们需要获取以上数据中的avatar_72
字段属性。此时我们的脚本可以编写为user.avatar.avatar_72
场景三:多层级数组下标数据获取
举例:假如我们需要获取以上数据中的zh_cn
字段属性。此时我们的脚本可以编写为user.department_path[0].department_name.i18n_name.zh_cn
场景四:数据拼装
举例:假如我们需要获取以上数据中的nickname
字段属性,并将nickname
字段拼接企业邮箱后缀形成企业邮箱地址存储。此时我们的脚本可以编写为user.nickname + "@example.com"
场景五:数据截取
举例:假如我们需要获取以上数据中的enterprise_email
字段属性,但我们不需要@
以后的字符。此时我们的脚本可以编写为user.nickname + "@example.com"
场景六:数据选择
举例:假如我们需要获取以上数据中的mobile
字段属性,但我们仅需要中国区手机号,即:数据前有+86
的才会存储。此时我们的脚本可以编写为user.mobile startsWith "+86" ? user.mobile : ""
场景七:数据大小写转换
举例:假如我们需要获取以上数据中的nickname
字段属性,但是要求nickname
全部转换为大写。此时我们的脚本可以编写为upper(user.nickname)
场景八:数据转型
举例:假如我们需要获取以上数据中的user_order
字段属性,但是要求user_order
必须转换成String型才能进行存储。此时我们的脚本可以编写为string(user.orders[0].user_order)
常见问题
user.
前缀: 认证源和数据源中对用户属性的引用必须以user.
前缀开头, 比如user.name + "@example.com"- 不存在的key报错: 比如
user.invalid + "_ok"
, 若引用的字段invalid不存在, 则脚本语法报错, 可使用val(user.invalid, "default") + "_ok"
代替