From e5a189e0f416ae757bef44ffdeaabdc66aebe4a1 Mon Sep 17 00:00:00 2001
From: Yaodong Yu <2814461814@qq.com>
Date: Sat, 19 Aug 2023 12:23:15 +0800
Subject: [PATCH] fix: remove isGlobalAdmin field in user (#2235)
* refactor: remove isGlobalAdmin field in user
* fix: upload xlsx
* fix: remove field in account table
---
controllers/account.go | 1 -
controllers/auth.go | 3 +-
controllers/base.go | 2 +-
controllers/link.go | 4 +-
init_data.json.template | 1 -
ldap/server.go | 2 +-
object/check.go | 4 +-
object/check_util.go | 4 +-
object/init.go | 2 -
object/mfa.go | 4 +-
object/oidc_discovery.go | 2 +-
object/syncer_util.go | 3 -
object/token.go | 1 -
object/token_jwt.go | 2 -
object/user.go | 13 +-
object/user_upload.go | 13 +-
object/user_util.go | 7 +-
swagger/swagger.json | 517 +++++-------------------
swagger/swagger.yml | 353 ++++------------
web/src/OrganizationListPage.js | 1 -
web/src/Setting.js | 2 +-
web/src/UserEditPage.js | 13 -
web/src/UserListPage.js | 13 -
web/src/WebhookEditPage.js | 1 -
web/src/common/OAuthWidget.js | 2 +-
web/src/table/AccountTable.js | 3 +-
web/src/table/SyncerTableColumnTable.js | 2 +-
xlsx/user_test.xlsx | Bin 10977 -> 10948 bytes
28 files changed, 212 insertions(+), 763 deletions(-)
diff --git a/controllers/account.go b/controllers/account.go
index 21adfde9..cf41e429 100644
--- a/controllers/account.go
+++ b/controllers/account.go
@@ -171,7 +171,6 @@ func (c *ApiController) Signup() {
Region: authForm.Region,
Score: initScore,
IsAdmin: false,
- IsGlobalAdmin: false,
IsForbidden: false,
IsDeleted: false,
SignupApplication: application.Name,
diff --git a/controllers/auth.go b/controllers/auth.go
index 5897f140..dfa5275b 100644
--- a/controllers/auth.go
+++ b/controllers/auth.go
@@ -70,7 +70,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}
// check user's tag
- if !user.IsGlobalAdmin && !user.IsAdmin && len(application.Tags) > 0 {
+ if !user.IsGlobalAdmin() && !user.IsAdmin && len(application.Tags) > 0 {
// only users with the tag that is listed in the application tags can login
if !util.InSlice(application.Tags, user.Tag) {
c.ResponseError(fmt.Sprintf(c.T("auth:User's tag: %s is not listed in the application's tags"), user.Tag))
@@ -589,7 +589,6 @@ func (c *ApiController) Login() {
Region: userInfo.CountryCode,
Score: initScore,
IsAdmin: false,
- IsGlobalAdmin: false,
IsForbidden: false,
IsDeleted: false,
SignupApplication: application.Name,
diff --git a/controllers/base.go b/controllers/base.go
index cd1e3082..25e79639 100644
--- a/controllers/base.go
+++ b/controllers/base.go
@@ -79,7 +79,7 @@ func (c *ApiController) isGlobalAdmin() (bool, *object.User) {
return false, nil
}
- return user.Owner == "built-in" || user.IsGlobalAdmin, user
+ return user.IsGlobalAdmin(), user
}
func (c *ApiController) getCurrentUser() *object.User {
diff --git a/controllers/link.go b/controllers/link.go
index 1fe96b4c..aa4c81ae 100644
--- a/controllers/link.go
+++ b/controllers/link.go
@@ -45,13 +45,13 @@ func (c *ApiController) Unlink() {
// the user will be unlinked from the provider
unlinkedUser := form.User
- if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin {
+ if user.Id != unlinkedUser.Id && !user.IsGlobalAdmin() {
// if the user is not the same as the one we are unlinking, we need to make sure the user is the global admin.
c.ResponseError(c.T("link:You are not the global admin, you can't unlink other users"))
return
}
- if user.Id == unlinkedUser.Id && !user.IsGlobalAdmin {
+ if user.Id == unlinkedUser.Id && !user.IsGlobalAdmin() {
// if the user is unlinking themselves, should check the provider can be unlinked, if not, we should return an error.
application, err := object.GetApplicationByUser(user)
if err != nil {
diff --git a/init_data.json.template b/init_data.json.template
index e33cee8e..6330a074 100644
--- a/init_data.json.template
+++ b/init_data.json.template
@@ -123,7 +123,6 @@
"score": 2000,
"ranking": 1,
"isAdmin": true,
- "isGlobalAdmin": true,
"isForbidden": false,
"isDeleted": false,
"signupApplication": "",
diff --git a/ldap/server.go b/ldap/server.go
index 4ac99c5a..bee379a1 100644
--- a/ldap/server.go
+++ b/ldap/server.go
@@ -62,7 +62,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
return
}
- if bindOrg == "built-in" || bindUser.IsGlobalAdmin {
+ if bindOrg == "built-in" || bindUser.IsGlobalAdmin() {
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
} else if bindUser.IsAdmin {
m.Client.IsOrgAdmin = true
diff --git a/object/check.go b/object/check.go
index 365071f9..22e42abf 100644
--- a/object/check.go
+++ b/object/check.go
@@ -141,7 +141,7 @@ func checkSigninErrorTimes(user *User, lang string) string {
// reset the error times
user.SigninWrongTimes = 0
- UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, user.IsGlobalAdmin)
+ UpdateUser(user.GetId(), user, []string{"signin_wrong_times"}, false)
}
return ""
@@ -319,7 +319,7 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
if requestUser == nil {
return false, fmt.Errorf(i18n.Translate(lang, "check:Session outdated, please login again"))
}
- if requestUser.IsGlobalAdmin {
+ if requestUser.IsGlobalAdmin() {
hasPermission = true
} else if requestUserId == userId {
hasPermission = true
diff --git a/object/check_util.go b/object/check_util.go
index 85d7935e..822cfd0d 100644
--- a/object/check_util.go
+++ b/object/check_util.go
@@ -42,7 +42,7 @@ func resetUserSigninErrorTimes(user *User) {
return
}
user.SigninWrongTimes = 0
- UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
+ UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, false)
}
func recordSigninErrorInfo(user *User, lang string, options ...bool) string {
@@ -61,7 +61,7 @@ func recordSigninErrorInfo(user *User, lang string, options ...bool) string {
}
// update user
- UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
+ UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, false)
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
if leftChances == 0 && enableCaptcha {
return fmt.Sprint(i18n.Translate(lang, "check:password or code is incorrect"))
diff --git a/object/init.go b/object/init.go
index 63c353b4..fd90fca6 100644
--- a/object/init.go
+++ b/object/init.go
@@ -73,7 +73,6 @@ func getBuiltInAccountItems() []*AccountItem {
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
- {Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
@@ -145,7 +144,6 @@ func initBuiltInUser() {
Score: 2000,
Ranking: 1,
IsAdmin: true,
- IsGlobalAdmin: true,
IsForbidden: false,
IsDeleted: false,
SignupApplication: "app-built-in",
diff --git a/object/mfa.go b/object/mfa.go
index 3e17e16c..acaaad7a 100644
--- a/object/mfa.go
+++ b/object/mfa.go
@@ -84,7 +84,7 @@ func MfaRecover(user *User, recoveryCode string) error {
return fmt.Errorf("recovery code not found")
}
- _, err := UpdateUser(user.GetId(), user, []string{"recovery_codes"}, user.IsAdminUser())
+ _, err := UpdateUser(user.GetId(), user, []string{"recovery_codes"}, false)
if err != nil {
return err
}
@@ -181,7 +181,7 @@ func DisabledMultiFactorAuth(user *User) error {
func SetPreferredMultiFactorAuth(user *User, mfaType string) error {
user.PreferredMfaType = mfaType
- _, err := UpdateUser(user.GetId(), user, []string{"preferred_mfa_type"}, user.IsAdminUser())
+ _, err := UpdateUser(user.GetId(), user, []string{"preferred_mfa_type"}, false)
if err != nil {
return err
}
diff --git a/object/oidc_discovery.go b/object/oidc_discovery.go
index 3d10e293..e1da6a8f 100644
--- a/object/oidc_discovery.go
+++ b/object/oidc_discovery.go
@@ -103,7 +103,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
SubjectTypesSupported: []string{"public"},
IdTokenSigningAlgValuesSupported: []string{"RS256"},
ScopesSupported: []string{"openid", "email", "profile", "address", "phone", "offline_access"},
- ClaimsSupported: []string{"iss", "ver", "sub", "aud", "iat", "exp", "id", "type", "displayName", "avatar", "permanentAvatar", "email", "phone", "location", "affiliation", "title", "homepage", "bio", "tag", "region", "language", "score", "ranking", "isOnline", "isAdmin", "isGlobalAdmin", "isForbidden", "signupApplication", "ldap"},
+ ClaimsSupported: []string{"iss", "ver", "sub", "aud", "iat", "exp", "id", "type", "displayName", "avatar", "permanentAvatar", "email", "phone", "location", "affiliation", "title", "homepage", "bio", "tag", "region", "language", "score", "ranking", "isOnline", "isAdmin", "isForbidden", "signupApplication", "ldap"},
RequestParameterSupported: true,
RequestObjectSigningAlgValuesSupported: []string{"HS256", "HS384", "HS512"},
EndSessionEndpoint: fmt.Sprintf("%s/api/logout", originBackend),
diff --git a/object/syncer_util.go b/object/syncer_util.go
index e6c0c4b3..f872cea4 100644
--- a/object/syncer_util.go
+++ b/object/syncer_util.go
@@ -154,8 +154,6 @@ func (syncer *Syncer) setUserByKeyValue(user *User, key string, value string) {
user.IsOnline = util.ParseBool(value)
case "IsAdmin":
user.IsAdmin = util.ParseBool(value)
- case "IsGlobalAdmin":
- user.IsGlobalAdmin = util.ParseBool(value)
case "IsForbidden":
user.IsForbidden = util.ParseBool(value)
case "IsDeleted":
@@ -289,7 +287,6 @@ func (syncer *Syncer) getMapFromOriginalUser(user *OriginalUser) map[string]stri
m["IsDefaultAvatar"] = util.BoolToString(user.IsDefaultAvatar)
m["IsOnline"] = util.BoolToString(user.IsOnline)
m["IsAdmin"] = util.BoolToString(user.IsAdmin)
- m["IsGlobalAdmin"] = util.BoolToString(user.IsGlobalAdmin)
m["IsForbidden"] = util.BoolToString(user.IsForbidden)
m["IsDeleted"] = util.BoolToString(user.IsDeleted)
m["CreatedIp"] = user.CreatedIp
diff --git a/object/token.go b/object/token.go
index fa8be8e3..3a81c765 100644
--- a/object/token.go
+++ b/object/token.go
@@ -824,7 +824,6 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
Type: "normal-user",
CreatedTime: util.GetCurrentTime(),
IsAdmin: false,
- IsGlobalAdmin: false,
IsForbidden: false,
IsDeleted: false,
Properties: map[string]string{
diff --git a/object/token_jwt.go b/object/token_jwt.go
index d0063fbb..4a5785a2 100644
--- a/object/token_jwt.go
+++ b/object/token_jwt.go
@@ -73,7 +73,6 @@ type UserWithoutThirdIdp struct {
IsDefaultAvatar bool `json:"isDefaultAvatar"`
IsOnline bool `json:"isOnline"`
IsAdmin bool `json:"isAdmin"`
- IsGlobalAdmin bool `json:"isGlobalAdmin"`
IsForbidden bool `json:"isForbidden"`
IsDeleted bool `json:"isDeleted"`
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
@@ -154,7 +153,6 @@ func getUserWithoutThirdIdp(user *User) *UserWithoutThirdIdp {
IsDefaultAvatar: user.IsDefaultAvatar,
IsOnline: user.IsOnline,
IsAdmin: user.IsAdmin,
- IsGlobalAdmin: user.IsGlobalAdmin,
IsForbidden: user.IsForbidden,
IsDeleted: user.IsDeleted,
SignupApplication: user.SignupApplication,
diff --git a/object/user.go b/object/user.go
index 3d7e404a..6ebda178 100644
--- a/object/user.go
+++ b/object/user.go
@@ -83,7 +83,6 @@ type User struct {
IsDefaultAvatar bool `json:"isDefaultAvatar"`
IsOnline bool `json:"isOnline"`
IsAdmin bool `json:"isAdmin"`
- IsGlobalAdmin bool `json:"isGlobalAdmin"`
IsForbidden bool `json:"isForbidden"`
IsDeleted bool `json:"isDeleted"`
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
@@ -530,7 +529,7 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
columns = []string{
"owner", "display_name", "avatar",
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
- "is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
+ "is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret",
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
@@ -891,5 +890,13 @@ func (user *User) IsApplicationAdmin(application *Application) bool {
return false
}
- return (user.Owner == application.Organization && user.IsAdmin) || user.IsGlobalAdmin
+ return (user.Owner == application.Organization && user.IsAdmin) || user.IsGlobalAdmin()
+}
+
+func (user *User) IsGlobalAdmin() bool {
+ if user == nil {
+ return false
+ }
+
+ return user.Owner == "built-in"
}
diff --git a/object/user_upload.go b/object/user_upload.go
index 2e8537cc..8bdd71bd 100644
--- a/object/user_upload.go
+++ b/object/user_upload.go
@@ -124,15 +124,14 @@ func UploadUsers(owner string, fileId string) (bool, error) {
IsDefaultAvatar: false,
IsOnline: parseLineItemBool(&line, 31),
IsAdmin: parseLineItemBool(&line, 32),
- IsGlobalAdmin: parseLineItemBool(&line, 33),
- IsForbidden: parseLineItemBool(&line, 34),
- IsDeleted: parseLineItemBool(&line, 35),
- SignupApplication: parseLineItem(&line, 36),
+ IsForbidden: parseLineItemBool(&line, 33),
+ IsDeleted: parseLineItemBool(&line, 34),
+ SignupApplication: parseLineItem(&line, 35),
Hash: "",
PreHash: "",
- CreatedIp: parseLineItem(&line, 37),
- LastSigninTime: parseLineItem(&line, 38),
- LastSigninIp: parseLineItem(&line, 39),
+ CreatedIp: parseLineItem(&line, 36),
+ LastSigninTime: parseLineItem(&line, 37),
+ LastSigninIp: parseLineItem(&line, 38),
Ldap: "",
Properties: map[string]string{},
}
diff --git a/object/user_util.go b/object/user_util.go
index 2122f5b1..44185c7c 100644
--- a/object/user_util.go
+++ b/object/user_util.go
@@ -310,10 +310,7 @@ func CheckPermissionForUpdateUser(oldUser, newUser *User, isAdmin bool, lang str
item := GetAccountItemByName("Is admin", organization)
itemsChanged = append(itemsChanged, item)
}
- if oldUser.IsGlobalAdmin != newUser.IsGlobalAdmin {
- item := GetAccountItemByName("Is global admin", organization)
- itemsChanged = append(itemsChanged, item)
- }
+
if oldUser.IsForbidden != newUser.IsForbidden {
item := GetAccountItemByName("Is forbidden", organization)
itemsChanged = append(itemsChanged, item)
@@ -351,5 +348,5 @@ func (user *User) IsAdminUser() bool {
return false
}
- return user.IsAdmin || user.IsGlobalAdmin
+ return user.IsAdmin || user.IsGlobalAdmin()
}
diff --git a/swagger/swagger.json b/swagger/swagger.json
index c9e61e14..d87081aa 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -131,34 +131,6 @@
}
}
},
- "/api/add-chat": {
- "post": {
- "tags": [
- "Chat API"
- ],
- "description": "add chat",
- "operationId": "ApiController.AddChat",
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "The details of the chat",
- "required": true,
- "schema": {
- "$ref": "#/definitions/object.Chat"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/controllers.Response"
- }
- }
- }
- }
- },
"/api/add-enforcer": {
"post": {
"tags": [
@@ -243,34 +215,6 @@
}
}
},
- "/api/add-message": {
- "post": {
- "tags": [
- "Message API"
- ],
- "description": "add message",
- "operationId": "ApiController.AddMessage",
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "The details of the message",
- "required": true,
- "schema": {
- "$ref": "#/definitions/object.Message"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/controllers.Response"
- }
- }
- }
- }
- },
"/api/add-model": {
"post": {
"tags": [
@@ -1077,34 +1021,6 @@
}
}
},
- "/api/delete-chat": {
- "post": {
- "tags": [
- "Chat API"
- ],
- "description": "delete chat",
- "operationId": "ApiController.DeleteChat",
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "The details of the chat",
- "required": true,
- "schema": {
- "$ref": "#/definitions/object.Chat"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/controllers.Response"
- }
- }
- }
- }
- },
"/api/delete-enforcer": {
"post": {
"tags": [
@@ -1189,34 +1105,6 @@
}
}
},
- "/api/delete-message": {
- "post": {
- "tags": [
- "Message API"
- ],
- "description": "delete message",
- "operationId": "ApiController.DeleteMessage",
- "parameters": [
- {
- "in": "body",
- "name": "body",
- "description": "The details of the message",
- "required": true,
- "schema": {
- "$ref": "#/definitions/object.Message"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/controllers.Response"
- }
- }
- }
- }
- },
"/api/delete-mfa/": {
"post": {
"tags": [
@@ -1964,56 +1852,18 @@
}
}
},
- "/api/get-chat": {
+ "/api/get-dashboard": {
"get": {
"tags": [
- "Chat API"
- ],
- "description": "get chat",
- "operationId": "ApiController.GetChat",
- "parameters": [
- {
- "in": "query",
- "name": "id",
- "description": "The id ( owner/name ) of the chat",
- "required": true,
- "type": "string"
- }
+ "GetDashboard API"
],
+ "description": "get information of dashboard",
+ "operationId": "ApiController.GetDashboard",
"responses": {
"200": {
"description": "The Response object",
"schema": {
- "$ref": "#/definitions/object.Chat"
- }
- }
- }
- }
- },
- "/api/get-chats": {
- "get": {
- "tags": [
- "Chat API"
- ],
- "description": "get chats",
- "operationId": "ApiController.GetChats",
- "parameters": [
- {
- "in": "query",
- "name": "owner",
- "description": "The owner of chats",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/object.Chat"
- }
+ "$ref": "#/definitions/controllers.Response"
}
}
}
@@ -2319,87 +2169,6 @@
}
}
},
- "/api/get-message": {
- "get": {
- "tags": [
- "Message API"
- ],
- "description": "get message",
- "operationId": "ApiController.GetMessage",
- "parameters": [
- {
- "in": "query",
- "name": "id",
- "description": "The id ( owner/name ) of the message",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/object.Message"
- }
- }
- }
- }
- },
- "/api/get-message-answer": {
- "get": {
- "tags": [
- "Message API"
- ],
- "description": "get message answer",
- "operationId": "ApiController.GetMessageAnswer",
- "parameters": [
- {
- "in": "query",
- "name": "id",
- "description": "The id ( owner/name ) of the message",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/object.Message"
- }
- }
- }
- }
- },
- "/api/get-messages": {
- "get": {
- "tags": [
- "Message API"
- ],
- "description": "get messages",
- "operationId": "ApiController.GetMessages",
- "parameters": [
- {
- "in": "query",
- "name": "owner",
- "description": "The owner of messages",
- "required": true,
- "type": "string"
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/object.Message"
- }
- }
- }
- }
- }
- },
"/api/get-model": {
"get": {
"tags": [
@@ -4481,41 +4250,6 @@
}
}
},
- "/api/update-chat": {
- "post": {
- "tags": [
- "Chat API"
- ],
- "description": "update chat",
- "operationId": "ApiController.UpdateChat",
- "parameters": [
- {
- "in": "query",
- "name": "id",
- "description": "The id ( owner/name ) of the chat",
- "required": true,
- "type": "string"
- },
- {
- "in": "body",
- "name": "body",
- "description": "The details of the chat",
- "required": true,
- "schema": {
- "$ref": "#/definitions/object.Chat"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/controllers.Response"
- }
- }
- }
- }
- },
"/api/update-enforcer": {
"post": {
"tags": [
@@ -4614,41 +4348,6 @@
}
}
},
- "/api/update-message": {
- "post": {
- "tags": [
- "Message API"
- ],
- "description": "update message",
- "operationId": "ApiController.UpdateMessage",
- "parameters": [
- {
- "in": "query",
- "name": "id",
- "description": "The id ( owner/name ) of the message",
- "required": true,
- "type": "string"
- },
- {
- "in": "body",
- "name": "body",
- "description": "The details of the message",
- "required": true,
- "schema": {
- "$ref": "#/definitions/object.Message"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "The Response object",
- "schema": {
- "$ref": "#/definitions/controllers.Response"
- }
- }
- }
- }
- },
"/api/update-model": {
"post": {
"tags": [
@@ -5431,6 +5130,14 @@
}
},
"definitions": {
+ "1183.0xc000639290.false": {
+ "title": "false",
+ "type": "object"
+ },
+ "1217.0xc0006392c0.false": {
+ "title": "false",
+ "type": "object"
+ },
"LaravelResponse": {
"title": "LaravelResponse",
"type": "object"
@@ -5484,16 +5191,10 @@
"type": "object",
"properties": {
"data": {
- "additionalProperties": {
- "description": "support string, struct or []struct",
- "type": "string"
- }
+ "$ref": "#/definitions/1183.0xc000639290.false"
},
"data2": {
- "additionalProperties": {
- "description": "support string, struct or []struct",
- "type": "string"
- }
+ "$ref": "#/definitions/1217.0xc0006392c0.false"
},
"msg": {
"type": "string"
@@ -5531,10 +5232,18 @@
"title": "JSONWebKey",
"type": "object"
},
+ "model.Model": {
+ "title": "Model",
+ "type": "object"
+ },
"object": {
"title": "object",
"type": "object"
},
+ "object.\u0026{197049 0xc000a2cd50 false}": {
+ "title": "\u0026{197049 0xc000a2cd50 false}",
+ "type": "object"
+ },
"object.AccountItem": {
"title": "AccountItem",
"type": "object",
@@ -5557,16 +5266,41 @@
"title": "Adapter",
"type": "object",
"properties": {
- "Engine": {
- "$ref": "#/definitions/xorm.Engine"
- },
- "dataSourceName": {
+ "createdTime": {
"type": "string"
},
- "dbName": {
+ "database": {
"type": "string"
},
- "driverName": {
+ "databaseType": {
+ "type": "string"
+ },
+ "host": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owner": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "port": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "table": {
+ "type": "string"
+ },
+ "tableNamePrefix": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "user": {
"type": "string"
}
}
@@ -5728,7 +5462,7 @@
"title": "CasbinRequest",
"type": "array",
"items": {
- "$ref": "#/definitions/object.CasbinRequest"
+ "$ref": "#/definitions/object.\u0026{197049 0xc000a2cd50 false}"
}
},
"object.Cert": {
@@ -5778,52 +5512,6 @@
}
}
},
- "object.Chat": {
- "title": "Chat",
- "type": "object",
- "properties": {
- "category": {
- "type": "string"
- },
- "createdTime": {
- "type": "string"
- },
- "displayName": {
- "type": "string"
- },
- "messageCount": {
- "type": "integer",
- "format": "int64"
- },
- "name": {
- "type": "string"
- },
- "organization": {
- "type": "string"
- },
- "owner": {
- "type": "string"
- },
- "type": {
- "type": "string"
- },
- "updatedTime": {
- "type": "string"
- },
- "user1": {
- "type": "string"
- },
- "user2": {
- "type": "string"
- },
- "users": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
"object.Enforce": {
"title": "Enforce",
"type": "object"
@@ -5844,12 +5532,14 @@
"displayName": {
"type": "string"
},
- "isEnabled": {
- "type": "boolean"
- },
"model": {
"type": "string"
},
+ "modelCfg": {
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
"name": {
"type": "string"
},
@@ -6084,36 +5774,6 @@
}
}
},
- "object.Message": {
- "title": "Message",
- "type": "object",
- "properties": {
- "author": {
- "type": "string"
- },
- "chat": {
- "type": "string"
- },
- "createdTime": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "organization": {
- "type": "string"
- },
- "owner": {
- "type": "string"
- },
- "replyTo": {
- "type": "string"
- },
- "text": {
- "type": "string"
- }
- }
- },
"object.MfaItem": {
"title": "MfaItem",
"type": "object",
@@ -6169,9 +5829,6 @@
"displayName": {
"type": "string"
},
- "isEnabled": {
- "type": "boolean"
- },
"modelText": {
"type": "string"
},
@@ -6349,6 +6006,24 @@
}
}
},
+ "object.Ormer": {
+ "title": "Ormer",
+ "type": "object",
+ "properties": {
+ "Engine": {
+ "$ref": "#/definitions/xorm.Engine"
+ },
+ "dataSourceName": {
+ "type": "string"
+ },
+ "dbName": {
+ "type": "string"
+ },
+ "driverName": {
+ "type": "string"
+ }
+ }
+ },
"object.Payment": {
"title": "Payment",
"type": "object",
@@ -6386,7 +6061,7 @@
"name": {
"type": "string"
},
- "organization": {
+ "outOrderId": {
"type": "string"
},
"owner": {
@@ -6424,7 +6099,7 @@
"type": "string"
},
"state": {
- "type": "string"
+ "$ref": "#/definitions/pp.PaymentState"
},
"tag": {
"type": "string"
@@ -7124,9 +6799,6 @@
"$ref": "#/definitions/object.TableColumn"
}
},
- "tablePrimaryKey": {
- "type": "string"
- },
"type": {
"type": "string"
},
@@ -7145,6 +6817,9 @@
"isHashed": {
"type": "boolean"
},
+ "isKey": {
+ "type": "boolean"
+ },
"name": {
"type": "string"
},
@@ -7464,9 +7139,6 @@
"isForbidden": {
"type": "boolean"
},
- "isGlobalAdmin": {
- "type": "boolean"
- },
"isOnline": {
"type": "boolean"
},
@@ -7692,6 +7364,9 @@
"vk": {
"type": "string"
},
+ "web3onboard": {
+ "type": "string"
+ },
"webauthnCredentials": {
"type": "array",
"items": {
@@ -7811,6 +7486,18 @@
}
}
},
+ "pp.PaymentState": {
+ "title": "PaymentState",
+ "type": "string",
+ "enum": [
+ "PaymentStatePaid = \"Paid\"",
+ "PaymentStateCreated = \"Created\"",
+ "PaymentStateCanceled = \"Canceled\"",
+ "PaymentStateTimeout = \"Timeout\"",
+ "PaymentStateError = \"Error\""
+ ],
+ "example": "Paid"
+ },
"protocol.CredentialAssertion": {
"title": "CredentialAssertion",
"type": "object"
@@ -7871,6 +7558,10 @@
"xorm.Engine": {
"title": "Engine",
"type": "object"
+ },
+ "xormadapter.Adapter": {
+ "title": "Adapter",
+ "type": "object"
}
},
"securityDefinitions": {
@@ -7879,9 +7570,5 @@
"name": "Authorization",
"in": "header"
}
- },
- "externalDocs": {
- "description": "Find out more about Casdoor",
- "url": "https://casdoor.org/"
}
}
\ No newline at end of file
diff --git a/swagger/swagger.yml b/swagger/swagger.yml
index 21ee9a40..4a22816a 100644
--- a/swagger/swagger.yml
+++ b/swagger/swagger.yml
@@ -85,24 +85,6 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
- /api/add-chat:
- post:
- tags:
- - Chat API
- description: add chat
- operationId: ApiController.AddChat
- parameters:
- - in: body
- name: body
- description: The details of the chat
- required: true
- schema:
- $ref: '#/definitions/object.Chat'
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/controllers.Response'
/api/add-enforcer:
post:
tags:
@@ -157,24 +139,6 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
- /api/add-message:
- post:
- tags:
- - Message API
- description: add message
- operationId: ApiController.AddMessage
- parameters:
- - in: body
- name: body
- description: The details of the message
- required: true
- schema:
- $ref: '#/definitions/object.Message'
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/controllers.Response'
/api/add-model:
post:
tags:
@@ -696,24 +660,6 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
- /api/delete-chat:
- post:
- tags:
- - Chat API
- description: delete chat
- operationId: ApiController.DeleteChat
- parameters:
- - in: body
- name: body
- description: The details of the chat
- required: true
- schema:
- $ref: '#/definitions/object.Chat'
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/controllers.Response'
/api/delete-enforcer:
post:
tags:
@@ -768,24 +714,6 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
- /api/delete-message:
- post:
- tags:
- - Message API
- description: delete message
- operationId: ApiController.DeleteMessage
- parameters:
- - in: body
- name: body
- description: The details of the message
- required: true
- schema:
- $ref: '#/definitions/object.Message'
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/controllers.Response'
/api/delete-mfa/:
post:
tags:
@@ -1271,42 +1199,17 @@ paths:
type: array
items:
$ref: '#/definitions/object.Cert'
- /api/get-chat:
+ /api/get-dashboard:
get:
tags:
- - Chat API
- description: get chat
- operationId: ApiController.GetChat
- parameters:
- - in: query
- name: id
- description: The id ( owner/name ) of the chat
- required: true
- type: string
+ - GetDashboard API
+ description: get information of dashboard
+ operationId: ApiController.GetDashboard
responses:
"200":
description: The Response object
schema:
- $ref: '#/definitions/object.Chat'
- /api/get-chats:
- get:
- tags:
- - Chat API
- description: get chats
- operationId: ApiController.GetChats
- parameters:
- - in: query
- name: owner
- description: The owner of chats
- required: true
- type: string
- responses:
- "200":
- description: The Response object
- schema:
- type: array
- items:
- $ref: '#/definitions/object.Chat'
+ $ref: '#/definitions/controllers.Response'
/api/get-default-application:
get:
tags:
@@ -1503,59 +1406,6 @@ paths:
type: array
items:
$ref: '#/definitions/object.Ldap'
- /api/get-message:
- get:
- tags:
- - Message API
- description: get message
- operationId: ApiController.GetMessage
- parameters:
- - in: query
- name: id
- description: The id ( owner/name ) of the message
- required: true
- type: string
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/object.Message'
- /api/get-message-answer:
- get:
- tags:
- - Message API
- description: get message answer
- operationId: ApiController.GetMessageAnswer
- parameters:
- - in: query
- name: id
- description: The id ( owner/name ) of the message
- required: true
- type: string
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/object.Message'
- /api/get-messages:
- get:
- tags:
- - Message API
- description: get messages
- operationId: ApiController.GetMessages
- parameters:
- - in: query
- name: owner
- description: The owner of messages
- required: true
- type: string
- responses:
- "200":
- description: The Response object
- schema:
- type: array
- items:
- $ref: '#/definitions/object.Message'
/api/get-model:
get:
tags:
@@ -2925,29 +2775,6 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
- /api/update-chat:
- post:
- tags:
- - Chat API
- description: update chat
- operationId: ApiController.UpdateChat
- parameters:
- - in: query
- name: id
- description: The id ( owner/name ) of the chat
- required: true
- type: string
- - in: body
- name: body
- description: The details of the chat
- required: true
- schema:
- $ref: '#/definitions/object.Chat'
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/controllers.Response'
/api/update-enforcer:
post:
tags:
@@ -3012,29 +2839,6 @@ paths:
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
- /api/update-message:
- post:
- tags:
- - Message API
- description: update message
- operationId: ApiController.UpdateMessage
- parameters:
- - in: query
- name: id
- description: The id ( owner/name ) of the message
- required: true
- type: string
- - in: body
- name: body
- description: The details of the message
- required: true
- schema:
- $ref: '#/definitions/object.Message'
- responses:
- "200":
- description: The Response object
- schema:
- $ref: '#/definitions/controllers.Response'
/api/update-model:
post:
tags:
@@ -3549,6 +3353,12 @@ paths:
schema:
$ref: '#/definitions/controllers.Response'
definitions:
+ 1183.0xc000639290.false:
+ title: "false"
+ type: object
+ 1217.0xc0006392c0.false:
+ title: "false"
+ type: object
LaravelResponse:
title: LaravelResponse
type: object
@@ -3588,13 +3398,9 @@ definitions:
type: object
properties:
data:
- additionalProperties:
- description: support string, struct or []struct
- type: string
+ $ref: '#/definitions/1183.0xc000639290.false'
data2:
- additionalProperties:
- description: support string, struct or []struct
- type: string
+ $ref: '#/definitions/1217.0xc0006392c0.false'
msg:
type: string
name:
@@ -3618,9 +3424,15 @@ definitions:
jose.JSONWebKey:
title: JSONWebKey
type: object
+ model.Model:
+ title: Model
+ type: object
object:
title: object
type: object
+ object.&{197049 0xc000a2cd50 false}:
+ title: '&{197049 0xc000a2cd50 false}'
+ type: object
object.AccountItem:
title: AccountItem
type: object
@@ -3637,13 +3449,30 @@ definitions:
title: Adapter
type: object
properties:
- Engine:
- $ref: '#/definitions/xorm.Engine'
- dataSourceName:
+ createdTime:
type: string
- dbName:
+ database:
type: string
- driverName:
+ databaseType:
+ type: string
+ host:
+ type: string
+ name:
+ type: string
+ owner:
+ type: string
+ password:
+ type: string
+ port:
+ type: integer
+ format: int64
+ table:
+ type: string
+ tableNamePrefix:
+ type: string
+ type:
+ type: string
+ user:
type: string
object.Application:
title: Application
@@ -3752,7 +3581,7 @@ definitions:
title: CasbinRequest
type: array
items:
- $ref: '#/definitions/object.CasbinRequest'
+ $ref: '#/definitions/object.&{197049 0xc000a2cd50 false}'
object.Cert:
title: Cert
type: object
@@ -3785,37 +3614,6 @@ definitions:
type: string
type:
type: string
- object.Chat:
- title: Chat
- type: object
- properties:
- category:
- type: string
- createdTime:
- type: string
- displayName:
- type: string
- messageCount:
- type: integer
- format: int64
- name:
- type: string
- organization:
- type: string
- owner:
- type: string
- type:
- type: string
- updatedTime:
- type: string
- user1:
- type: string
- user2:
- type: string
- users:
- type: array
- items:
- type: string
object.Enforce:
title: Enforce
type: object
@@ -3831,10 +3629,11 @@ definitions:
type: string
displayName:
type: string
- isEnabled:
- type: boolean
model:
type: string
+ modelCfg:
+ additionalProperties:
+ type: string
name:
type: string
owner:
@@ -3992,26 +3791,6 @@ definitions:
type: string
username:
type: string
- object.Message:
- title: Message
- type: object
- properties:
- author:
- type: string
- chat:
- type: string
- createdTime:
- type: string
- name:
- type: string
- organization:
- type: string
- owner:
- type: string
- replyTo:
- type: string
- text:
- type: string
object.MfaItem:
title: MfaItem
type: object
@@ -4050,8 +3829,6 @@ definitions:
type: string
displayName:
type: string
- isEnabled:
- type: boolean
modelText:
type: string
name:
@@ -4169,6 +3946,18 @@ definitions:
$ref: '#/definitions/object.ThemeData'
websiteUrl:
type: string
+ object.Ormer:
+ title: Ormer
+ type: object
+ properties:
+ Engine:
+ $ref: '#/definitions/xorm.Engine'
+ dataSourceName:
+ type: string
+ dbName:
+ type: string
+ driverName:
+ type: string
object.Payment:
title: Payment
type: object
@@ -4195,7 +3984,7 @@ definitions:
type: string
name:
type: string
- organization:
+ outOrderId:
type: string
owner:
type: string
@@ -4221,7 +4010,7 @@ definitions:
returnUrl:
type: string
state:
- type: string
+ $ref: '#/definitions/pp.PaymentState'
tag:
type: string
type:
@@ -4692,8 +4481,6 @@ definitions:
type: array
items:
$ref: '#/definitions/object.TableColumn'
- tablePrimaryKey:
- type: string
type:
type: string
user:
@@ -4706,6 +4493,8 @@ definitions:
type: string
isHashed:
type: boolean
+ isKey:
+ type: boolean
name:
type: string
type:
@@ -4920,8 +4709,6 @@ definitions:
type: boolean
isForbidden:
type: boolean
- isGlobalAdmin:
- type: boolean
isOnline:
type: boolean
kakao:
@@ -5073,6 +4860,8 @@ definitions:
type: string
vk:
type: string
+ web3onboard:
+ type: string
webauthnCredentials:
type: array
items:
@@ -5151,6 +4940,16 @@ definitions:
type: string
url:
type: string
+ pp.PaymentState:
+ title: PaymentState
+ type: string
+ enum:
+ - PaymentStatePaid = "Paid"
+ - PaymentStateCreated = "Created"
+ - PaymentStateCanceled = "Canceled"
+ - PaymentStateTimeout = "Timeout"
+ - PaymentStateError = "Error"
+ example: Paid
protocol.CredentialAssertion:
title: CredentialAssertion
type: object
@@ -5195,11 +4994,11 @@ definitions:
xorm.Engine:
title: Engine
type: object
+ xormadapter.Adapter:
+ title: Adapter
+ type: object
securityDefinitions:
AccessToken:
type: apiKey
name: Authorization
in: header
-externalDocs:
- description: Find out more about Casdoor
- url: https://casdoor.org/
diff --git a/web/src/OrganizationListPage.js b/web/src/OrganizationListPage.js
index 897f99f7..e346a23a 100644
--- a/web/src/OrganizationListPage.js
+++ b/web/src/OrganizationListPage.js
@@ -81,7 +81,6 @@ class OrganizationListPage extends BaseListPage {
{name: "Properties", visible: false, viewRule: "Admin", modifyRule: "Admin"},
{name: "Is online", visible: true, viewRule: "Admin", modifyRule: "Admin"},
{name: "Is admin", visible: true, viewRule: "Admin", modifyRule: "Admin"},
- {name: "Is global admin", visible: true, viewRule: "Admin", modifyRule: "Admin"},
{name: "Is forbidden", visible: true, viewRule: "Admin", modifyRule: "Admin"},
{name: "Is deleted", visible: true, viewRule: "Admin", modifyRule: "Admin"},
{Name: "Multi-factor authentication", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
diff --git a/web/src/Setting.js b/web/src/Setting.js
index 22b63c0e..1fa48075 100644
--- a/web/src/Setting.js
+++ b/web/src/Setting.js
@@ -620,7 +620,7 @@ export function isAdminUser(account) {
if (account === undefined || account === null) {
return false;
}
- return account.owner === "built-in" || account.isGlobalAdmin === true;
+ return account.owner === "built-in";
}
export function isLocalAdminUser(account) {
diff --git a/web/src/UserEditPage.js b/web/src/UserEditPage.js
index b7492f5d..f54fb7f8 100644
--- a/web/src/UserEditPage.js
+++ b/web/src/UserEditPage.js
@@ -842,19 +842,6 @@ class UserEditPage extends React.Component {
);
- } else if (accountItem.name === "Is global admin") {
- return (
-
-
- {Setting.getLabel(i18next.t("user:Is global admin"), i18next.t("user:Is global admin - Tooltip"))} :
-
-
- {
- this.updateUserField("isGlobalAdmin", checked);
- }} />
-
-
- );
} else if (accountItem.name === "Is forbidden") {
return (
diff --git a/web/src/UserListPage.js b/web/src/UserListPage.js
index 2708cb89..0c0248d0 100644
--- a/web/src/UserListPage.js
+++ b/web/src/UserListPage.js
@@ -81,7 +81,6 @@ class UserListPage extends BaseListPage {
tag: "staff",
region: "",
isAdmin: (owner === "built-in"),
- isGlobalAdmin: (owner === "built-in"),
IsForbidden: false,
score: this.state.organization.initScore,
isDeleted: false,
@@ -354,18 +353,6 @@ class UserListPage extends BaseListPage {
);
},
},
- {
- title: i18next.t("user:Is global admin"),
- dataIndex: "isGlobalAdmin",
- key: "isGlobalAdmin",
- width: "140px",
- sorter: true,
- render: (text, record, index) => {
- return (
-
- );
- },
- },
{
title: i18next.t("user:Is forbidden"),
dataIndex: "isForbidden",
diff --git a/web/src/WebhookEditPage.js b/web/src/WebhookEditPage.js
index 9f5d6990..72590b23 100644
--- a/web/src/WebhookEditPage.js
+++ b/web/src/WebhookEditPage.js
@@ -79,7 +79,6 @@ const userTemplate = {
"ranking": 10,
"isOnline": false,
"isAdmin": true,
- "isGlobalAdmin": false,
"isForbidden": false,
"isDeleted": false,
"signupApplication": "app-casnode",
diff --git a/web/src/common/OAuthWidget.js b/web/src/common/OAuthWidget.js
index 5bae8305..4b5785b6 100644
--- a/web/src/common/OAuthWidget.js
+++ b/web/src/common/OAuthWidget.js
@@ -188,7 +188,7 @@ class OAuthWidget extends React.Component {
)
) : (
-
+
)
}
diff --git a/web/src/table/AccountTable.js b/web/src/table/AccountTable.js
index a347115d..6c2e0f23 100644
--- a/web/src/table/AccountTable.js
+++ b/web/src/table/AccountTable.js
@@ -100,7 +100,6 @@ class AccountTable extends React.Component {
{name: "Properties", label: i18next.t("user:Properties")},
{name: "Is online", label: i18next.t("user:Is online")},
{name: "Is admin", label: i18next.t("user:Is admin")},
- {name: "Is global admin", label: i18next.t("user:Is global admin")},
{name: "Is forbidden", label: i18next.t("user:Is forbidden")},
{name: "Is deleted", label: i18next.t("user:Is deleted")},
{name: "Multi-factor authentication", label: i18next.t("user:Multi-factor authentication")},
@@ -179,7 +178,7 @@ class AccountTable extends React.Component {
}
let options;
- if (record.viewRule === "Admin" || record.name === "Is admin" || record.name === "Is global admin") {
+ if (record.viewRule === "Admin" || record.name === "Is admin") {
options = [
{id: "Admin", name: "Admin"},
{id: "Immutable", name: "Immutable"},
diff --git a/web/src/table/SyncerTableColumnTable.js b/web/src/table/SyncerTableColumnTable.js
index e602d831..e1aa6f99 100644
--- a/web/src/table/SyncerTableColumnTable.js
+++ b/web/src/table/SyncerTableColumnTable.js
@@ -100,7 +100,7 @@ class SyncerTableColumnTable extends React.Component {
{
["Name", "CreatedTime", "UpdatedTime", "Id", "Type", "Password", "PasswordSalt", "DisplayName", "FirstName", "LastName", "Avatar", "PermanentAvatar",
"Email", "EmailVerified", "Phone", "Location", "Address", "Affiliation", "Title", "IdCardType", "IdCard", "Homepage", "Bio", "Tag", "Region",
- "Language", "Gender", "Birthday", "Education", "Score", "Ranking", "IsDefaultAvatar", "IsOnline", "IsAdmin", "IsGlobalAdmin", "IsForbidden", "IsDeleted", "CreatedIp"]
+ "Language", "Gender", "Birthday", "Education", "Score", "Ranking", "IsDefaultAvatar", "IsOnline", "IsAdmin", "IsForbidden", "IsDeleted", "CreatedIp"]
.map((item, index) => )
}
diff --git a/xlsx/user_test.xlsx b/xlsx/user_test.xlsx
index cb9b7dbad05ec7b02b40297a3e4680cf19c5697a..95d42962eb9d4bb990411857e996aef1af37017b 100644
GIT binary patch
delta 3281
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