mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-04 20:10:35 +08:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5846e337c7 | ||
![]() |
44f4de1440 | ||
![]() |
27adeb4620 | ||
![]() |
5c107db43b | ||
![]() |
27187b3a54 | ||
![]() |
14fcedcc5d | ||
![]() |
e7c015f288 | ||
![]() |
c4819602ec |
@@ -150,7 +150,7 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
||||
|
||||
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||
if method == "POST" {
|
||||
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" {
|
||||
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") {
|
||||
return true
|
||||
} else if urlPath == "/api/update-user" {
|
||||
// Allow ordinary users to update their own information
|
||||
|
@@ -56,6 +56,17 @@ type Captcha struct {
|
||||
SubType string `json:"subType"`
|
||||
}
|
||||
|
||||
// this API is used by "Api URL" of Flarum's FoF Passport plugin
|
||||
// https://github.com/FriendsOfFlarum/passport
|
||||
type LaravelResponse struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
EmailVerifiedAt string `json:"email_verified_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Signup
|
||||
// @Tag Login API
|
||||
// @Title Signup
|
||||
@@ -418,7 +429,7 @@ func (c *ApiController) GetUserinfo() {
|
||||
// @Title UserInfo2
|
||||
// @Tag Account API
|
||||
// @Description return Laravel compatible user information according to OAuth 2.0
|
||||
// @Success 200 {object} LaravelResponse The Response object
|
||||
// @Success 200 {object} controllers.LaravelResponse The Response object
|
||||
// @router /user [get]
|
||||
func (c *ApiController) GetUserinfo2() {
|
||||
user, ok := c.RequireSignedInUser()
|
||||
@@ -426,17 +437,6 @@ func (c *ApiController) GetUserinfo2() {
|
||||
return
|
||||
}
|
||||
|
||||
// this API is used by "Api URL" of Flarum's FoF Passport plugin
|
||||
// https://github.com/FriendsOfFlarum/passport
|
||||
type LaravelResponse struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
EmailVerifiedAt string `json:"email_verified_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
response := LaravelResponse{
|
||||
Id: user.Id,
|
||||
Name: user.Name,
|
||||
|
@@ -222,7 +222,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
// @Param redirectUri query string true "redirect uri"
|
||||
// @Param scope query string true "scope"
|
||||
// @Param state query string true "state"
|
||||
// @Success 200 {object} Response The Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /get-app-login [get]
|
||||
func (c *ApiController) GetApplicationLogin() {
|
||||
clientId := c.Input().Get("clientId")
|
||||
|
@@ -26,7 +26,7 @@ import (
|
||||
// @Title Enforce
|
||||
// @Tag Enforce API
|
||||
// @Description Call Casbin Enforce API
|
||||
// @Param body body object.CasbinRequest true "Casbin request"
|
||||
// @Param body body []string true "Casbin request"
|
||||
// @Param permissionId query string false "permission id"
|
||||
// @Param modelId query string false "model id"
|
||||
// @Param resourceId query string false "resource id"
|
||||
@@ -43,7 +43,7 @@ func (c *ApiController) Enforce() {
|
||||
return
|
||||
}
|
||||
|
||||
var request object.CasbinRequest
|
||||
var request []string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -60,7 +60,10 @@ func (c *ApiController) Enforce() {
|
||||
res := []bool{}
|
||||
keyRes := []string{}
|
||||
|
||||
enforceResult, err := enforcer.Enforce(request...)
|
||||
// type transformation
|
||||
interfaceRequest := util.StringToInterfaceArray(request)
|
||||
|
||||
enforceResult, err := enforcer.Enforce(interfaceRequest...)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -87,7 +90,7 @@ func (c *ApiController) Enforce() {
|
||||
res := []bool{}
|
||||
keyRes := []string{}
|
||||
|
||||
enforceResult, err := object.Enforce(permission, &request)
|
||||
enforceResult, err := object.Enforce(permission, request)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -129,7 +132,7 @@ func (c *ApiController) Enforce() {
|
||||
return
|
||||
}
|
||||
|
||||
enforceResult, err := object.Enforce(firstPermission, &request, permissionIds...)
|
||||
enforceResult, err := object.Enforce(firstPermission, request, permissionIds...)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -146,7 +149,7 @@ func (c *ApiController) Enforce() {
|
||||
// @Title BatchEnforce
|
||||
// @Tag Enforce API
|
||||
// @Description Call Casbin BatchEnforce API
|
||||
// @Param body body object.CasbinRequest true "array of casbin requests"
|
||||
// @Param body body []string true "array of casbin requests"
|
||||
// @Param permissionId query string false "permission id"
|
||||
// @Param modelId query string false "model id"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
@@ -156,7 +159,7 @@ func (c *ApiController) BatchEnforce() {
|
||||
modelId := c.Input().Get("modelId")
|
||||
enforcerId := c.Input().Get("enforcerId")
|
||||
|
||||
var requests []object.CasbinRequest
|
||||
var requests [][]string
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
@@ -173,7 +176,10 @@ func (c *ApiController) BatchEnforce() {
|
||||
res := [][]bool{}
|
||||
keyRes := []string{}
|
||||
|
||||
enforceResult, err := enforcer.BatchEnforce(requests)
|
||||
// type transformation
|
||||
interfaceRequests := util.StringToInterfaceArray2d(requests)
|
||||
|
||||
enforceResult, err := enforcer.BatchEnforce(interfaceRequests)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -200,7 +206,7 @@ func (c *ApiController) BatchEnforce() {
|
||||
res := [][]bool{}
|
||||
keyRes := []string{}
|
||||
|
||||
enforceResult, err := object.BatchEnforce(permission, &requests)
|
||||
enforceResult, err := object.BatchEnforce(permission, requests)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -236,7 +242,7 @@ func (c *ApiController) BatchEnforce() {
|
||||
return
|
||||
}
|
||||
|
||||
enforceResult, err := object.BatchEnforce(firstPermission, &requests, permissionIds...)
|
||||
enforceResult, err := object.BatchEnforce(firstPermission, requests, permissionIds...)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
@@ -138,7 +138,7 @@ func (c *ApiController) AddEnforcer() {
|
||||
// @Title DeleteEnforcer
|
||||
// @Tag Enforcer API
|
||||
// @Description delete enforcer
|
||||
// @Param body body object.Enforce true "The enforcer object"
|
||||
// @Param body body object.Enforcer true "The enforcer object"
|
||||
// @Success 200 {object} object.Enforcer
|
||||
// @router /delete-enforcer [post]
|
||||
func (c *ApiController) DeleteEnforcer() {
|
||||
|
@@ -42,7 +42,7 @@ type LdapSyncResp struct {
|
||||
// @Tag Account API
|
||||
// @Description get ldap users
|
||||
// Param id string true "id"
|
||||
// @Success 200 {object} LdapResp The Response object
|
||||
// @Success 200 {object} controllers.LdapResp The Response object
|
||||
// @router /get-ldap-users [get]
|
||||
func (c *ApiController) GetLdapUsers() {
|
||||
id := c.Input().Get("id")
|
||||
@@ -250,7 +250,7 @@ func (c *ApiController) DeleteLdap() {
|
||||
// @Tag Account API
|
||||
// @Description sync ldap users
|
||||
// @Param id query string true "id"
|
||||
// @Success 200 {object} LdapSyncResp The Response object
|
||||
// @Success 200 {object} controllers.LdapSyncResp The Response object
|
||||
// @router /sync-ldap-users [post]
|
||||
func (c *ApiController) SyncLdapUsers() {
|
||||
id := c.Input().Get("id")
|
||||
|
@@ -73,7 +73,7 @@ func (c *ApiController) MfaSetupInitiate() {
|
||||
// @Description setup verify totp
|
||||
// @param secret form string true "MFA secret"
|
||||
// @param passcode form string true "MFA passcode"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /mfa/setup/verify [post]
|
||||
func (c *ApiController) MfaSetupVerify() {
|
||||
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
||||
@@ -104,7 +104,7 @@ func (c *ApiController) MfaSetupVerify() {
|
||||
// @param owner form string true "owner of user"
|
||||
// @param name form string true "name of user"
|
||||
// @param type form string true "MFA auth type"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /mfa/setup/enable [post]
|
||||
func (c *ApiController) MfaSetupEnable() {
|
||||
owner := c.Ctx.Request.Form.Get("owner")
|
||||
@@ -143,7 +143,7 @@ func (c *ApiController) MfaSetupEnable() {
|
||||
// @Description: Delete MFA
|
||||
// @param owner form string true "owner of user"
|
||||
// @param name form string true "name of user"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-mfa/ [post]
|
||||
func (c *ApiController) DeleteMfa() {
|
||||
owner := c.Ctx.Request.Form.Get("owner")
|
||||
@@ -176,7 +176,7 @@ func (c *ApiController) DeleteMfa() {
|
||||
// @param owner form string true "owner of user"
|
||||
// @param name form string true "name of user"
|
||||
// @param id form string true "id of user's MFA props"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /set-preferred-mfa [post]
|
||||
func (c *ApiController) SetPreferredMfa() {
|
||||
mfaType := c.Ctx.Request.Form.Get("mfaType")
|
||||
|
@@ -178,7 +178,7 @@ func (c *ApiController) DeleteOrganization() {
|
||||
// @Tag Organization API
|
||||
// @Description get default application
|
||||
// @Param id query string true "organization id"
|
||||
// @Success 200 {object} Response The Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /get-default-application [get]
|
||||
func (c *ApiController) GetDefaultApplication() {
|
||||
userId := c.GetSessionUsername()
|
||||
|
@@ -51,9 +51,14 @@ type NotificationForm struct {
|
||||
// @Param clientId query string true "The clientId of the application"
|
||||
// @Param clientSecret query string true "The clientSecret of the application"
|
||||
// @Param from body controllers.EmailForm true "Details of the email request"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /api/send-email [post]
|
||||
func (c *ApiController) SendEmail() {
|
||||
user, ok := c.RequireSignedInUser()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var emailForm EmailForm
|
||||
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm)
|
||||
@@ -108,8 +113,13 @@ func (c *ApiController) SendEmail() {
|
||||
}
|
||||
|
||||
code := "123456"
|
||||
|
||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||
content := fmt.Sprintf(emailForm.Content, code)
|
||||
content := strings.Replace(provider.Content, "%s", code, 1)
|
||||
if user != nil {
|
||||
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
|
||||
}
|
||||
|
||||
for _, receiver := range emailForm.Receivers {
|
||||
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
|
||||
if err != nil {
|
||||
@@ -128,7 +138,7 @@ func (c *ApiController) SendEmail() {
|
||||
// @Param clientId query string true "The clientId of the application"
|
||||
// @Param clientSecret query string true "The clientSecret of the application"
|
||||
// @Param from body controllers.SmsForm true "Details of the sms request"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /api/send-sms [post]
|
||||
func (c *ApiController) SendSms() {
|
||||
provider, err := c.GetProviderFromContext("SMS")
|
||||
@@ -166,7 +176,7 @@ func (c *ApiController) SendSms() {
|
||||
// @Tag Service API
|
||||
// @Description This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
|
||||
// @Param from body controllers.NotificationForm true "Details of the notification request"
|
||||
// @Success 200 {object} Response object
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /api/send-notification [post]
|
||||
func (c *ApiController) SendNotification() {
|
||||
provider, err := c.GetProviderFromContext("Notification")
|
||||
|
104
object/ormer.go
104
object/ormer.go
@@ -234,12 +234,32 @@ func (a *Ormer) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Group))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(User))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Group))
|
||||
err = a.Engine.Sync2(new(Application))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Provider))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Resource))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Cert))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -269,17 +289,7 @@ func (a *Ormer) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Provider))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Application))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Resource))
|
||||
err = a.Engine.Sync2(new(Session))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -289,26 +299,6 @@ func (a *Ormer) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(VerificationRecord))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Webhook))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Syncer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Cert))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Product))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -319,6 +309,36 @@ func (a *Ormer) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Plan))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Pricing))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Subscription))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Syncer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Webhook))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(VerificationRecord))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Ldap))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -333,24 +353,4 @@ func (a *Ormer) createTable() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Session))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Subscription))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Plan))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Pricing))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@@ -284,24 +284,28 @@ func removeGroupingPolicies(permission *Permission) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type CasbinRequest = []interface{}
|
||||
|
||||
func Enforce(permission *Permission, request *CasbinRequest, permissionIds ...string) (bool, error) {
|
||||
func Enforce(permission *Permission, request []string, permissionIds ...string) (bool, error) {
|
||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return enforcer.Enforce(*request...)
|
||||
// type transformation
|
||||
interfaceRequest := util.StringToInterfaceArray(request)
|
||||
|
||||
return enforcer.Enforce(interfaceRequest...)
|
||||
}
|
||||
|
||||
func BatchEnforce(permission *Permission, requests *[]CasbinRequest, permissionIds ...string) ([]bool, error) {
|
||||
func BatchEnforce(permission *Permission, requests [][]string, permissionIds ...string) ([]bool, error) {
|
||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return enforcer.BatchEnforce(*requests)
|
||||
// type transformation
|
||||
interfaceRequests := util.StringToInterfaceArray2d(requests)
|
||||
|
||||
return enforcer.BatchEnforce(interfaceRequests)
|
||||
}
|
||||
|
||||
func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) ([]string, error) {
|
||||
|
@@ -52,7 +52,7 @@ type Provider struct {
|
||||
Port int `json:"port"`
|
||||
DisableSsl bool `json:"disableSsl"` // If the provider type is WeChat, DisableSsl means EnableQRCode
|
||||
Title string `xorm:"varchar(100)" json:"title"`
|
||||
Content string `xorm:"varchar(1000)" json:"content"` // If provider type is WeChat, Content means QRCode string by Base64 encoding
|
||||
Content string `xorm:"varchar(2000)" json:"content"` // If provider type is WeChat, Content means QRCode string by Base64 encoding
|
||||
Receiver string `xorm:"varchar(100)" json:"receiver"`
|
||||
|
||||
RegionId string `xorm:"varchar(100)" json:"regionId"`
|
||||
|
@@ -72,6 +72,10 @@ func GetTruncatedPath(provider *Provider, fullFilePath string, limit int) string
|
||||
}
|
||||
|
||||
func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
|
||||
if provider.Domain != "" && !strings.HasPrefix(provider.Domain, "http://") && !strings.HasPrefix(provider.Domain, "https://") {
|
||||
provider.Domain = fmt.Sprintf("https://%s", provider.Domain)
|
||||
}
|
||||
|
||||
escapedPath := util.UrlJoin(provider.PathPrefix, fullFilePath)
|
||||
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
|
||||
|
||||
@@ -79,9 +83,6 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
|
||||
if provider.Type != "Local File System" {
|
||||
// provider.Domain = "https://cdn.casbin.com/casdoor/"
|
||||
host = util.GetUrlHost(provider.Domain)
|
||||
if !strings.HasPrefix(host, "http://") && !strings.HasPrefix(host, "https://") {
|
||||
host = fmt.Sprintf("https://%s", host)
|
||||
}
|
||||
} else {
|
||||
// provider.Domain = "http://localhost:8000" or "https://door.casdoor.com"
|
||||
host = util.UrlJoin(provider.Domain, "/files")
|
||||
@@ -90,9 +91,12 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
|
||||
host = util.UrlJoin(host, provider.Bucket)
|
||||
}
|
||||
|
||||
fileUrl := util.UrlJoin(host, escapePath(objectKey))
|
||||
fileUrl := ""
|
||||
if host != "" {
|
||||
fileUrl = util.UrlJoin(host, escapePath(objectKey))
|
||||
}
|
||||
|
||||
if hasTimestamp {
|
||||
if fileUrl != "" && hasTimestamp {
|
||||
fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime())
|
||||
}
|
||||
|
||||
|
@@ -886,6 +886,18 @@ func (user *User) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", user.Owner, user.Name)
|
||||
}
|
||||
|
||||
func (user *User) GetFriendlyName() string {
|
||||
if user.FirstName != "" && user.LastName != "" {
|
||||
return fmt.Sprintf("%s, %s", user.FirstName, user.LastName)
|
||||
} else if user.DisplayName != "" {
|
||||
return user.DisplayName
|
||||
} else if user.Name != "" {
|
||||
return user.Name
|
||||
} else {
|
||||
return user.Id
|
||||
}
|
||||
}
|
||||
|
||||
func isUserIdGlobalAdmin(userId string) bool {
|
||||
return strings.HasPrefix(userId, "built-in/") || strings.HasPrefix(userId, "app/")
|
||||
}
|
||||
|
@@ -89,7 +89,10 @@ func SendVerificationCodeToEmail(organization *Organization, user *User, provide
|
||||
}
|
||||
|
||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||
content := fmt.Sprintf(provider.Content, code)
|
||||
content := strings.Replace(provider.Content, "%s", code, 1)
|
||||
if user != nil {
|
||||
content = strings.Replace(content, "%{user.friendlyName}", user.GetFriendlyName(), 1)
|
||||
}
|
||||
|
||||
if err := IsAllowSend(user, remoteAddr, provider.Category); err != nil {
|
||||
return err
|
||||
|
@@ -73,6 +73,12 @@ func initAPI() {
|
||||
beego.Router("/api/get-default-application", &controllers.ApiController{}, "GET:GetDefaultApplication")
|
||||
beego.Router("/api/get-organization-names", &controllers.ApiController{}, "GET:GetOrganizationNames")
|
||||
|
||||
beego.Router("/api/get-groups", &controllers.ApiController{}, "GET:GetGroups")
|
||||
beego.Router("/api/get-group", &controllers.ApiController{}, "GET:GetGroup")
|
||||
beego.Router("/api/update-group", &controllers.ApiController{}, "POST:UpdateGroup")
|
||||
beego.Router("/api/add-group", &controllers.ApiController{}, "POST:AddGroup")
|
||||
beego.Router("/api/delete-group", &controllers.ApiController{}, "POST:DeleteGroup")
|
||||
|
||||
beego.Router("/api/get-global-users", &controllers.ApiController{}, "GET:GetGlobalUsers")
|
||||
beego.Router("/api/get-users", &controllers.ApiController{}, "GET:GetUsers")
|
||||
beego.Router("/api/get-sorted-users", &controllers.ApiController{}, "GET:GetSortedUsers")
|
||||
@@ -85,11 +91,34 @@ func initAPI() {
|
||||
beego.Router("/api/upload-users", &controllers.ApiController{}, "POST:UploadUsers")
|
||||
beego.Router("/api/remove-user-from-group", &controllers.ApiController{}, "POST:RemoveUserFromGroup")
|
||||
|
||||
beego.Router("/api/get-groups", &controllers.ApiController{}, "GET:GetGroups")
|
||||
beego.Router("/api/get-group", &controllers.ApiController{}, "GET:GetGroup")
|
||||
beego.Router("/api/update-group", &controllers.ApiController{}, "POST:UpdateGroup")
|
||||
beego.Router("/api/add-group", &controllers.ApiController{}, "POST:AddGroup")
|
||||
beego.Router("/api/delete-group", &controllers.ApiController{}, "POST:DeleteGroup")
|
||||
beego.Router("/api/get-applications", &controllers.ApiController{}, "GET:GetApplications")
|
||||
beego.Router("/api/get-application", &controllers.ApiController{}, "GET:GetApplication")
|
||||
beego.Router("/api/get-user-application", &controllers.ApiController{}, "GET:GetUserApplication")
|
||||
beego.Router("/api/get-organization-applications", &controllers.ApiController{}, "GET:GetOrganizationApplications")
|
||||
beego.Router("/api/update-application", &controllers.ApiController{}, "POST:UpdateApplication")
|
||||
beego.Router("/api/add-application", &controllers.ApiController{}, "POST:AddApplication")
|
||||
beego.Router("/api/delete-application", &controllers.ApiController{}, "POST:DeleteApplication")
|
||||
|
||||
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
|
||||
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider")
|
||||
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders")
|
||||
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider")
|
||||
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider")
|
||||
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider")
|
||||
|
||||
beego.Router("/api/get-resources", &controllers.ApiController{}, "GET:GetResources")
|
||||
beego.Router("/api/get-resource", &controllers.ApiController{}, "GET:GetResource")
|
||||
beego.Router("/api/update-resource", &controllers.ApiController{}, "POST:UpdateResource")
|
||||
beego.Router("/api/add-resource", &controllers.ApiController{}, "POST:AddResource")
|
||||
beego.Router("/api/delete-resource", &controllers.ApiController{}, "POST:DeleteResource")
|
||||
beego.Router("/api/upload-resource", &controllers.ApiController{}, "POST:UploadResource")
|
||||
|
||||
beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts")
|
||||
beego.Router("/api/get-global-certs", &controllers.ApiController{}, "GET:GetGlobalCerts")
|
||||
beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert")
|
||||
beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert")
|
||||
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
|
||||
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
|
||||
|
||||
beego.Router("/api/get-roles", &controllers.ApiController{}, "GET:GetRoles")
|
||||
beego.Router("/api/get-role", &controllers.ApiController{}, "GET:GetRole")
|
||||
@@ -107,12 +136,6 @@ func initAPI() {
|
||||
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
||||
beego.Router("/api/upload-permissions", &controllers.ApiController{}, "POST:UploadPermissions")
|
||||
|
||||
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
||||
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
||||
beego.Router("/api/get-all-objects", &controllers.ApiController{}, "GET:GetAllObjects")
|
||||
beego.Router("/api/get-all-actions", &controllers.ApiController{}, "GET:GetAllActions")
|
||||
beego.Router("/api/get-all-roles", &controllers.ApiController{}, "GET:GetAllRoles")
|
||||
|
||||
beego.Router("/api/get-models", &controllers.ApiController{}, "GET:GetModels")
|
||||
beego.Router("/api/get-model", &controllers.ApiController{}, "GET:GetModel")
|
||||
beego.Router("/api/update-model", &controllers.ApiController{}, "POST:UpdateModel")
|
||||
@@ -135,53 +158,11 @@ func initAPI() {
|
||||
beego.Router("/api/add-enforcer", &controllers.ApiController{}, "POST:AddEnforcer")
|
||||
beego.Router("/api/delete-enforcer", &controllers.ApiController{}, "POST:DeleteEnforcer")
|
||||
|
||||
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
||||
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
||||
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "GET:GetEmailAndPhone")
|
||||
beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode")
|
||||
beego.Router("/api/verify-code", &controllers.ApiController{}, "POST:VerifyCode")
|
||||
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
|
||||
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")
|
||||
beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha")
|
||||
|
||||
beego.Router("/api/get-ldap-users", &controllers.ApiController{}, "GET:GetLdapUsers")
|
||||
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
|
||||
beego.Router("/api/get-ldap", &controllers.ApiController{}, "GET:GetLdap")
|
||||
beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap")
|
||||
beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap")
|
||||
beego.Router("/api/delete-ldap", &controllers.ApiController{}, "POST:DeleteLdap")
|
||||
beego.Router("/api/sync-ldap-users", &controllers.ApiController{}, "POST:SyncLdapUsers")
|
||||
|
||||
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
|
||||
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider")
|
||||
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders")
|
||||
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider")
|
||||
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider")
|
||||
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider")
|
||||
|
||||
beego.Router("/api/get-applications", &controllers.ApiController{}, "GET:GetApplications")
|
||||
beego.Router("/api/get-application", &controllers.ApiController{}, "GET:GetApplication")
|
||||
beego.Router("/api/get-user-application", &controllers.ApiController{}, "GET:GetUserApplication")
|
||||
beego.Router("/api/get-organization-applications", &controllers.ApiController{}, "GET:GetOrganizationApplications")
|
||||
beego.Router("/api/update-application", &controllers.ApiController{}, "POST:UpdateApplication")
|
||||
beego.Router("/api/add-application", &controllers.ApiController{}, "POST:AddApplication")
|
||||
beego.Router("/api/delete-application", &controllers.ApiController{}, "POST:DeleteApplication")
|
||||
|
||||
beego.Router("/api/get-resources", &controllers.ApiController{}, "GET:GetResources")
|
||||
beego.Router("/api/get-resource", &controllers.ApiController{}, "GET:GetResource")
|
||||
beego.Router("/api/update-resource", &controllers.ApiController{}, "POST:UpdateResource")
|
||||
beego.Router("/api/add-resource", &controllers.ApiController{}, "POST:AddResource")
|
||||
beego.Router("/api/delete-resource", &controllers.ApiController{}, "POST:DeleteResource")
|
||||
beego.Router("/api/upload-resource", &controllers.ApiController{}, "POST:UploadResource")
|
||||
|
||||
beego.Router("/api/get-tokens", &controllers.ApiController{}, "GET:GetTokens")
|
||||
beego.Router("/api/get-token", &controllers.ApiController{}, "GET:GetToken")
|
||||
beego.Router("/api/update-token", &controllers.ApiController{}, "POST:UpdateToken")
|
||||
beego.Router("/api/add-token", &controllers.ApiController{}, "POST:AddToken")
|
||||
beego.Router("/api/delete-token", &controllers.ApiController{}, "POST:DeleteToken")
|
||||
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
|
||||
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
|
||||
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
|
||||
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
||||
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
||||
beego.Router("/api/get-all-objects", &controllers.ApiController{}, "GET:GetAllObjects")
|
||||
beego.Router("/api/get-all-actions", &controllers.ApiController{}, "GET:GetAllActions")
|
||||
beego.Router("/api/get-all-roles", &controllers.ApiController{}, "GET:GetAllRoles")
|
||||
|
||||
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
|
||||
beego.Router("/api/get-session", &controllers.ApiController{}, "GET:GetSingleSession")
|
||||
@@ -190,43 +171,11 @@ func initAPI() {
|
||||
beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession")
|
||||
beego.Router("/api/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
|
||||
|
||||
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
||||
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
||||
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")
|
||||
beego.Router("/api/add-webhook", &controllers.ApiController{}, "POST:AddWebhook")
|
||||
beego.Router("/api/delete-webhook", &controllers.ApiController{}, "POST:DeleteWebhook")
|
||||
|
||||
beego.Router("/api/get-syncers", &controllers.ApiController{}, "GET:GetSyncers")
|
||||
beego.Router("/api/get-syncer", &controllers.ApiController{}, "GET:GetSyncer")
|
||||
beego.Router("/api/update-syncer", &controllers.ApiController{}, "POST:UpdateSyncer")
|
||||
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
||||
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
||||
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
|
||||
|
||||
beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts")
|
||||
beego.Router("/api/get-global-certs", &controllers.ApiController{}, "GET:GetGlobalCerts")
|
||||
beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert")
|
||||
beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert")
|
||||
beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert")
|
||||
beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert")
|
||||
|
||||
beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions")
|
||||
beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription")
|
||||
beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription")
|
||||
beego.Router("/api/add-subscription", &controllers.ApiController{}, "POST:AddSubscription")
|
||||
beego.Router("/api/delete-subscription", &controllers.ApiController{}, "POST:DeleteSubscription")
|
||||
|
||||
beego.Router("/api/get-plans", &controllers.ApiController{}, "GET:GetPlans")
|
||||
beego.Router("/api/get-plan", &controllers.ApiController{}, "GET:GetPlan")
|
||||
beego.Router("/api/update-plan", &controllers.ApiController{}, "POST:UpdatePlan")
|
||||
beego.Router("/api/add-plan", &controllers.ApiController{}, "POST:AddPlan")
|
||||
beego.Router("/api/delete-plan", &controllers.ApiController{}, "POST:DeletePlan")
|
||||
|
||||
beego.Router("/api/get-pricings", &controllers.ApiController{}, "GET:GetPricings")
|
||||
beego.Router("/api/get-pricing", &controllers.ApiController{}, "GET:GetPricing")
|
||||
beego.Router("/api/update-pricing", &controllers.ApiController{}, "POST:UpdatePricing")
|
||||
beego.Router("/api/add-pricing", &controllers.ApiController{}, "POST:AddPricing")
|
||||
beego.Router("/api/delete-pricing", &controllers.ApiController{}, "POST:DeletePricing")
|
||||
beego.Router("/api/get-tokens", &controllers.ApiController{}, "GET:GetTokens")
|
||||
beego.Router("/api/get-token", &controllers.ApiController{}, "GET:GetToken")
|
||||
beego.Router("/api/update-token", &controllers.ApiController{}, "POST:UpdateToken")
|
||||
beego.Router("/api/add-token", &controllers.ApiController{}, "POST:AddToken")
|
||||
beego.Router("/api/delete-token", &controllers.ApiController{}, "POST:DeleteToken")
|
||||
|
||||
beego.Router("/api/get-products", &controllers.ApiController{}, "GET:GetProducts")
|
||||
beego.Router("/api/get-product", &controllers.ApiController{}, "GET:GetProduct")
|
||||
@@ -244,6 +193,64 @@ func initAPI() {
|
||||
beego.Router("/api/notify-payment/?:owner/?:payment", &controllers.ApiController{}, "POST:NotifyPayment")
|
||||
beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment")
|
||||
|
||||
beego.Router("/api/get-plans", &controllers.ApiController{}, "GET:GetPlans")
|
||||
beego.Router("/api/get-plan", &controllers.ApiController{}, "GET:GetPlan")
|
||||
beego.Router("/api/update-plan", &controllers.ApiController{}, "POST:UpdatePlan")
|
||||
beego.Router("/api/add-plan", &controllers.ApiController{}, "POST:AddPlan")
|
||||
beego.Router("/api/delete-plan", &controllers.ApiController{}, "POST:DeletePlan")
|
||||
|
||||
beego.Router("/api/get-pricings", &controllers.ApiController{}, "GET:GetPricings")
|
||||
beego.Router("/api/get-pricing", &controllers.ApiController{}, "GET:GetPricing")
|
||||
beego.Router("/api/update-pricing", &controllers.ApiController{}, "POST:UpdatePricing")
|
||||
beego.Router("/api/add-pricing", &controllers.ApiController{}, "POST:AddPricing")
|
||||
beego.Router("/api/delete-pricing", &controllers.ApiController{}, "POST:DeletePricing")
|
||||
|
||||
beego.Router("/api/get-subscriptions", &controllers.ApiController{}, "GET:GetSubscriptions")
|
||||
beego.Router("/api/get-subscription", &controllers.ApiController{}, "GET:GetSubscription")
|
||||
beego.Router("/api/update-subscription", &controllers.ApiController{}, "POST:UpdateSubscription")
|
||||
beego.Router("/api/add-subscription", &controllers.ApiController{}, "POST:AddSubscription")
|
||||
beego.Router("/api/delete-subscription", &controllers.ApiController{}, "POST:DeleteSubscription")
|
||||
|
||||
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
|
||||
beego.Router("/api/get-version-info", &controllers.ApiController{}, "GET:GetVersionInfo")
|
||||
beego.Router("/api/health", &controllers.ApiController{}, "GET:Health")
|
||||
beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo")
|
||||
beego.Handler("/api/metrics", promhttp.Handler())
|
||||
|
||||
beego.Router("/api/get-syncers", &controllers.ApiController{}, "GET:GetSyncers")
|
||||
beego.Router("/api/get-syncer", &controllers.ApiController{}, "GET:GetSyncer")
|
||||
beego.Router("/api/update-syncer", &controllers.ApiController{}, "POST:UpdateSyncer")
|
||||
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
||||
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
||||
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
|
||||
|
||||
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
||||
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
||||
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")
|
||||
beego.Router("/api/add-webhook", &controllers.ApiController{}, "POST:AddWebhook")
|
||||
beego.Router("/api/delete-webhook", &controllers.ApiController{}, "POST:DeleteWebhook")
|
||||
|
||||
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
|
||||
beego.Router("/api/check-user-password", &controllers.ApiController{}, "POST:CheckUserPassword")
|
||||
beego.Router("/api/get-email-and-phone", &controllers.ApiController{}, "GET:GetEmailAndPhone")
|
||||
beego.Router("/api/send-verification-code", &controllers.ApiController{}, "POST:SendVerificationCode")
|
||||
beego.Router("/api/verify-code", &controllers.ApiController{}, "POST:VerifyCode")
|
||||
beego.Router("/api/verify-captcha", &controllers.ApiController{}, "POST:VerifyCaptcha")
|
||||
beego.Router("/api/reset-email-or-phone", &controllers.ApiController{}, "POST:ResetEmailOrPhone")
|
||||
beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha")
|
||||
|
||||
beego.Router("/api/get-ldap-users", &controllers.ApiController{}, "GET:GetLdapUsers")
|
||||
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
|
||||
beego.Router("/api/get-ldap", &controllers.ApiController{}, "GET:GetLdap")
|
||||
beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap")
|
||||
beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap")
|
||||
beego.Router("/api/delete-ldap", &controllers.ApiController{}, "POST:DeleteLdap")
|
||||
beego.Router("/api/sync-ldap-users", &controllers.ApiController{}, "POST:SyncLdapUsers")
|
||||
|
||||
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
|
||||
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
|
||||
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
|
||||
|
||||
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
|
||||
beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms")
|
||||
beego.Router("/api/send-notification", &controllers.ApiController{}, "POST:SendNotification")
|
||||
@@ -259,13 +266,6 @@ func initAPI() {
|
||||
beego.Router("/api/delete-mfa", &controllers.ApiController{}, "POST:DeleteMfa")
|
||||
beego.Router("/api/set-preferred-mfa", &controllers.ApiController{}, "POST:SetPreferredMfa")
|
||||
|
||||
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
|
||||
beego.Router("/api/get-version-info", &controllers.ApiController{}, "GET:GetVersionInfo")
|
||||
beego.Router("/api/health", &controllers.ApiController{}, "GET:Health")
|
||||
beego.Router("/api/get-prometheus-info", &controllers.ApiController{}, "GET:GetPrometheusInfo")
|
||||
|
||||
beego.Handler("/api/metrics", promhttp.Handler())
|
||||
|
||||
beego.Router("/.well-known/openid-configuration", &controllers.RootController{}, "GET:GetOidcDiscovery")
|
||||
beego.Router("/.well-known/jwks", &controllers.RootController{}, "*:GetJwks")
|
||||
|
||||
|
@@ -811,9 +811,9 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -839,9 +839,9 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,9 +881,9 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -935,7 +935,10 @@
|
||||
"description": "array of casbin requests",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/object.CasbinRequest"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1108,7 +1111,7 @@
|
||||
"description": "The enforcer object",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/object.Enforce"
|
||||
"$ref": "#/definitions/object.Enforcer"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -1187,9 +1190,9 @@
|
||||
"operationId": "ApiController.DeleteMfa",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1657,7 +1660,10 @@
|
||||
"description": "Casbin request",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/object.CasbinRequest"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1809,7 +1815,7 @@
|
||||
"200": {
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1962,7 +1968,7 @@
|
||||
"200": {
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2208,7 +2214,7 @@
|
||||
"200": {
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/LdapResp"
|
||||
"$ref": "#/definitions/controllers.LdapResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3826,9 +3832,9 @@
|
||||
"operationId": "ApiController.MfaSetupEnable",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3860,9 +3866,9 @@
|
||||
"operationId": "ApiController.MfaSetupVerify",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3996,9 +4002,9 @@
|
||||
"operationId": "ApiController.SetPreferredMfa",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "object",
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Response"
|
||||
"$ref": "#/definitions/controllers.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4057,7 +4063,7 @@
|
||||
"200": {
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/LdapSyncResp"
|
||||
"$ref": "#/definitions/controllers.LdapSyncResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4925,7 +4931,7 @@
|
||||
"200": {
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/LaravelResponse"
|
||||
"$ref": "#/definitions/controllers.LaravelResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5131,22 +5137,6 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"LaravelResponse": {
|
||||
"title": "LaravelResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"LdapResp": {
|
||||
"title": "LdapResp",
|
||||
"type": "object"
|
||||
},
|
||||
"LdapSyncResp": {
|
||||
"title": "LdapSyncResp",
|
||||
"type": "object"
|
||||
},
|
||||
"Response": {
|
||||
"title": "Response",
|
||||
"type": "object"
|
||||
},
|
||||
"casbin.Enforcer": {
|
||||
"title": "Enforcer",
|
||||
"type": "object"
|
||||
@@ -5179,6 +5169,66 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"controllers.LaravelResponse": {
|
||||
"title": "LaravelResponse",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"email_verified_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"controllers.LdapResp": {
|
||||
"title": "LdapResp",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"existUuids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"users": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/object.LdapUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"controllers.LdapSyncResp": {
|
||||
"title": "LdapSyncResp",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"exist": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/object.LdapUser"
|
||||
}
|
||||
},
|
||||
"failed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/object.LdapUser"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"controllers.NotificationForm": {
|
||||
"title": "NotificationForm",
|
||||
"type": "object",
|
||||
@@ -5236,10 +5286,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"jose.JSONWebKey": {
|
||||
"title": "JSONWebKey",
|
||||
"type": "object"
|
||||
},
|
||||
"model.Model": {
|
||||
"title": "Model",
|
||||
"type": "object"
|
||||
@@ -5368,6 +5414,14 @@
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"failedSigninLimit": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"failedSigninfrozenTime": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"forgetUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5480,12 +5534,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"object.CasbinRequest": {
|
||||
"title": "CasbinRequest",
|
||||
"type": "array",
|
||||
"items": {
|
||||
}
|
||||
},
|
||||
"object.Cert": {
|
||||
"title": "Cert",
|
||||
"type": "object",
|
||||
@@ -5527,10 +5575,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"object.Enforce": {
|
||||
"title": "Enforce",
|
||||
"type": "object"
|
||||
},
|
||||
"object.Enforcer": {
|
||||
"title": "Enforcer",
|
||||
"type": "object",
|
||||
@@ -5771,6 +5815,66 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"object.LdapUser": {
|
||||
"title": "LdapUser",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"EmailAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"Mail": {
|
||||
"type": "string"
|
||||
},
|
||||
"MobileTelephoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"PostalAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"RegisteredAddress": {
|
||||
"type": "string"
|
||||
},
|
||||
"TelephoneNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"cn": {
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gidNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"memberOf": {
|
||||
"type": "string"
|
||||
},
|
||||
"mobile": {
|
||||
"type": "string"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
},
|
||||
"uidNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"userPrincipalName": {
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"object.ManagedAccount": {
|
||||
"title": "ManagedAccount",
|
||||
"type": "object",
|
||||
@@ -7529,22 +7633,6 @@
|
||||
],
|
||||
"example": "Paid"
|
||||
},
|
||||
"protocol.CredentialAssertion": {
|
||||
"title": "CredentialAssertion",
|
||||
"type": "object"
|
||||
},
|
||||
"protocol.CredentialAssertionResponse": {
|
||||
"title": "CredentialAssertionResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"protocol.CredentialCreation": {
|
||||
"title": "CredentialCreation",
|
||||
"type": "object"
|
||||
},
|
||||
"protocol.CredentialCreationResponse": {
|
||||
"title": "CredentialCreationResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"util.SystemInfo": {
|
||||
"title": "SystemInfo",
|
||||
"type": "object",
|
||||
|
@@ -525,9 +525,9 @@ paths:
|
||||
$ref: '#/definitions/controllers.EmailForm'
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/api/send-notification:
|
||||
post:
|
||||
tags:
|
||||
@@ -543,9 +543,9 @@ paths:
|
||||
$ref: '#/definitions/controllers.NotificationForm'
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/api/send-sms:
|
||||
post:
|
||||
tags:
|
||||
@@ -571,9 +571,9 @@ paths:
|
||||
$ref: '#/definitions/controllers.SmsForm'
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/api/verify-code:
|
||||
post:
|
||||
tags:
|
||||
@@ -606,7 +606,9 @@ paths:
|
||||
description: array of casbin requests
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/object.CasbinRequest'
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
- in: query
|
||||
name: permissionId
|
||||
description: permission id
|
||||
@@ -718,7 +720,7 @@ paths:
|
||||
description: The enforcer object
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/object.Enforce'
|
||||
$ref: '#/definitions/object.Enforcer'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
@@ -768,9 +770,9 @@ paths:
|
||||
operationId: ApiController.DeleteMfa
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/delete-model:
|
||||
post:
|
||||
tags:
|
||||
@@ -1071,7 +1073,9 @@ paths:
|
||||
description: Casbin request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/object.CasbinRequest'
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
- in: query
|
||||
name: permissionId
|
||||
description: permission id
|
||||
@@ -1172,7 +1176,7 @@ paths:
|
||||
"200":
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/get-application:
|
||||
get:
|
||||
tags:
|
||||
@@ -1272,7 +1276,7 @@ paths:
|
||||
"200":
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/get-email-and-phone:
|
||||
get:
|
||||
tags:
|
||||
@@ -1433,7 +1437,7 @@ paths:
|
||||
"200":
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/LdapResp'
|
||||
$ref: '#/definitions/controllers.LdapResp'
|
||||
/api/get-ldaps:
|
||||
get:
|
||||
tags:
|
||||
@@ -2496,9 +2500,9 @@ paths:
|
||||
operationId: ApiController.MfaSetupEnable
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/mfa/setup/initiate:
|
||||
post:
|
||||
tags:
|
||||
@@ -2518,9 +2522,9 @@ paths:
|
||||
operationId: ApiController.MfaSetupVerify
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/notify-payment:
|
||||
post:
|
||||
tags:
|
||||
@@ -2607,9 +2611,9 @@ paths:
|
||||
operationId: ApiController.SetPreferredMfa
|
||||
responses:
|
||||
"200":
|
||||
description: object
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
$ref: '#/definitions/controllers.Response'
|
||||
/api/signup:
|
||||
post:
|
||||
tags:
|
||||
@@ -2648,7 +2652,7 @@ paths:
|
||||
"200":
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/LdapSyncResp'
|
||||
$ref: '#/definitions/controllers.LdapSyncResp'
|
||||
/api/unlink:
|
||||
post:
|
||||
tags:
|
||||
@@ -3219,7 +3223,7 @@ paths:
|
||||
"200":
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/LaravelResponse'
|
||||
$ref: '#/definitions/controllers.LaravelResponse'
|
||||
/api/userinfo:
|
||||
get:
|
||||
tags:
|
||||
@@ -3351,18 +3355,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/definitions/object.TokenError'
|
||||
definitions:
|
||||
LaravelResponse:
|
||||
title: LaravelResponse
|
||||
type: object
|
||||
LdapResp:
|
||||
title: LdapResp
|
||||
type: object
|
||||
LdapSyncResp:
|
||||
title: LdapSyncResp
|
||||
type: object
|
||||
Response:
|
||||
title: Response
|
||||
type: object
|
||||
casbin.Enforcer:
|
||||
title: Enforcer
|
||||
type: object
|
||||
@@ -3385,6 +3377,46 @@ definitions:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
controllers.LaravelResponse:
|
||||
title: LaravelResponse
|
||||
type: object
|
||||
properties:
|
||||
created_at:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
email_verified_at:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
updated_at:
|
||||
type: string
|
||||
controllers.LdapResp:
|
||||
title: LdapResp
|
||||
type: object
|
||||
properties:
|
||||
existUuids:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
users:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.LdapUser'
|
||||
controllers.LdapSyncResp:
|
||||
title: LdapSyncResp
|
||||
type: object
|
||||
properties:
|
||||
exist:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.LdapUser'
|
||||
failed:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.LdapUser'
|
||||
controllers.NotificationForm:
|
||||
title: NotificationForm
|
||||
type: object
|
||||
@@ -3514,6 +3546,12 @@ definitions:
|
||||
expireInHours:
|
||||
type: integer
|
||||
format: int64
|
||||
failedSigninLimit:
|
||||
type: integer
|
||||
format: int64
|
||||
failedSigninfrozenTime:
|
||||
type: integer
|
||||
format: int64
|
||||
forgetUrl:
|
||||
type: string
|
||||
formBackgroundUrl:
|
||||
@@ -3588,11 +3626,6 @@ definitions:
|
||||
$ref: '#/definitions/object.ThemeData'
|
||||
tokenFormat:
|
||||
type: string
|
||||
object.CasbinRequest:
|
||||
title: CasbinRequest
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.CasbinRequest'
|
||||
object.Cert:
|
||||
title: Cert
|
||||
type: object
|
||||
@@ -3621,9 +3654,6 @@ definitions:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
object.Enforce:
|
||||
title: Enforce
|
||||
type: object
|
||||
object.Enforcer:
|
||||
title: Enforcer
|
||||
type: object
|
||||
@@ -3786,6 +3816,46 @@ definitions:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
object.LdapUser:
|
||||
title: LdapUser
|
||||
type: object
|
||||
properties:
|
||||
EmailAddress:
|
||||
type: string
|
||||
Mail:
|
||||
type: string
|
||||
MobileTelephoneNumber:
|
||||
type: string
|
||||
PostalAddress:
|
||||
type: string
|
||||
RegisteredAddress:
|
||||
type: string
|
||||
TelephoneNumber:
|
||||
type: string
|
||||
address:
|
||||
type: string
|
||||
cn:
|
||||
type: string
|
||||
displayName:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
gidNumber:
|
||||
type: string
|
||||
groupId:
|
||||
type: string
|
||||
memberOf:
|
||||
type: string
|
||||
mobile:
|
||||
type: string
|
||||
uid:
|
||||
type: string
|
||||
uidNumber:
|
||||
type: string
|
||||
userPrincipalName:
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
object.ManagedAccount:
|
||||
title: ManagedAccount
|
||||
type: object
|
||||
|
10
util/path.go
10
util/path.go
@@ -72,7 +72,15 @@ func GetUrlPath(urlString string) string {
|
||||
}
|
||||
|
||||
func GetUrlHost(urlString string) string {
|
||||
u, _ := url.Parse(urlString)
|
||||
if urlString == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
u, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s://%s", u.Scheme, u.Host)
|
||||
}
|
||||
|
||||
|
@@ -322,3 +322,23 @@ func GetUsernameFromEmail(email string) string {
|
||||
return tokens[0]
|
||||
}
|
||||
}
|
||||
|
||||
func StringToInterfaceArray(array []string) []interface{} {
|
||||
var interfaceArray []interface{}
|
||||
for _, v := range array {
|
||||
interfaceArray = append(interfaceArray, v)
|
||||
}
|
||||
return interfaceArray
|
||||
}
|
||||
|
||||
func StringToInterfaceArray2d(arrays [][]string) [][]interface{} {
|
||||
var interfaceArrays [][]interface{}
|
||||
for _, req := range arrays {
|
||||
var interfaceArray []interface{}
|
||||
for _, r := range req {
|
||||
interfaceArray = append(interfaceArray, r)
|
||||
}
|
||||
interfaceArrays = append(interfaceArrays, interfaceArray)
|
||||
}
|
||||
return interfaceArrays
|
||||
}
|
||||
|
111
web/src/App.js
111
web/src/App.js
@@ -15,62 +15,62 @@
|
||||
import React, {Component} from "react";
|
||||
import "./App.less";
|
||||
import {Helmet} from "react-helmet";
|
||||
import Dashboard from "./basic/Dashboard";
|
||||
import ShortcutsPage from "./basic/ShortcutsPage";
|
||||
import * as Setting from "./Setting";
|
||||
import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs";
|
||||
import {AppstoreTwoTone, BarsOutlined, DeploymentUnitOutlined, DollarTwoTone, DownOutlined, GithubOutlined, HomeTwoTone, InfoCircleFilled, LockTwoTone, LogoutOutlined, SafetyCertificateTwoTone, SettingOutlined, SettingTwoTone, ShareAltOutlined, WalletTwoTone} from "@ant-design/icons";
|
||||
import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result, Tooltip} from "antd";
|
||||
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
|
||||
import AccountPage from "./account/AccountPage";
|
||||
import Dashboard from "./basic/Dashboard";
|
||||
import ShortcutsPage from "./basic/ShortcutsPage";
|
||||
import AppListPage from "./basic/AppListPage";
|
||||
import OrganizationListPage from "./OrganizationListPage";
|
||||
import OrganizationEditPage from "./OrganizationEditPage";
|
||||
import GroupEditPage from "./GroupEdit";
|
||||
import GroupListPage from "./GroupList";
|
||||
import GroupTreePage from "./GroupTreePage";
|
||||
import UserListPage from "./UserListPage";
|
||||
import UserEditPage from "./UserEditPage";
|
||||
import ApplicationListPage from "./ApplicationListPage";
|
||||
import ApplicationEditPage from "./ApplicationEditPage";
|
||||
import ProviderListPage from "./ProviderListPage";
|
||||
import ProviderEditPage from "./ProviderEditPage";
|
||||
import ResourceListPage from "./ResourceListPage";
|
||||
import CertListPage from "./CertListPage";
|
||||
import CertEditPage from "./CertEditPage";
|
||||
import RoleListPage from "./RoleListPage";
|
||||
import RoleEditPage from "./RoleEditPage";
|
||||
import PermissionListPage from "./PermissionListPage";
|
||||
import PermissionEditPage from "./PermissionEditPage";
|
||||
import ModelListPage from "./ModelListPage";
|
||||
import ModelEditPage from "./ModelEditPage";
|
||||
import AdapterListPage from "./AdapterListPage";
|
||||
import AdapterEditPage from "./AdapterEditPage";
|
||||
import EnforcerEditPage from "./EnforcerEditPage";
|
||||
import EnforcerListPage from "./EnforcerListPage";
|
||||
import GroupTreePage from "./GroupTreePage";
|
||||
import GroupEditPage from "./GroupEdit";
|
||||
import GroupListPage from "./GroupList";
|
||||
import ProviderListPage from "./ProviderListPage";
|
||||
import ProviderEditPage from "./ProviderEditPage";
|
||||
import ApplicationListPage from "./ApplicationListPage";
|
||||
import ApplicationEditPage from "./ApplicationEditPage";
|
||||
import ResourceListPage from "./ResourceListPage";
|
||||
import LdapEditPage from "./LdapEditPage";
|
||||
import LdapSyncPage from "./LdapSyncPage";
|
||||
import SessionListPage from "./SessionListPage";
|
||||
import TokenListPage from "./TokenListPage";
|
||||
import TokenEditPage from "./TokenEditPage";
|
||||
import WebhookListPage from "./WebhookListPage";
|
||||
import WebhookEditPage from "./WebhookEditPage";
|
||||
import SyncerListPage from "./SyncerListPage";
|
||||
import SyncerEditPage from "./SyncerEditPage";
|
||||
import CertListPage from "./CertListPage";
|
||||
import CertEditPage from "./CertEditPage";
|
||||
import SubscriptionListPage from "./SubscriptionListPage";
|
||||
import SubscriptionEditPage from "./SubscriptionEditPage";
|
||||
import PricingListPage from "./PricingListPage";
|
||||
import PricingEditPage from "./PricingEditPage";
|
||||
import PlanListPage from "./PlanListPage";
|
||||
import PlanEditPage from "./PlanEditPage";
|
||||
import ProductListPage from "./ProductListPage";
|
||||
import ProductEditPage from "./ProductEditPage";
|
||||
import ProductBuyPage from "./ProductBuyPage";
|
||||
import PaymentListPage from "./PaymentListPage";
|
||||
import PaymentEditPage from "./PaymentEditPage";
|
||||
import PaymentResultPage from "./PaymentResultPage";
|
||||
import ModelListPage from "./ModelListPage";
|
||||
import ModelEditPage from "./ModelEditPage";
|
||||
import AdapterListPage from "./AdapterListPage";
|
||||
import AdapterEditPage from "./AdapterEditPage";
|
||||
import SessionListPage from "./SessionListPage";
|
||||
import MfaSetupPage from "./auth/MfaSetupPage";
|
||||
import PricingListPage from "./PricingListPage";
|
||||
import PricingEditPage from "./PricingEditPage";
|
||||
import PlanListPage from "./PlanListPage";
|
||||
import PlanEditPage from "./PlanEditPage";
|
||||
import SubscriptionListPage from "./SubscriptionListPage";
|
||||
import SubscriptionEditPage from "./SubscriptionEditPage";
|
||||
import SystemInfo from "./SystemInfo";
|
||||
import AccountPage from "./account/AccountPage";
|
||||
import AppListPage from "./basic/AppListPage";
|
||||
import SyncerListPage from "./SyncerListPage";
|
||||
import SyncerEditPage from "./SyncerEditPage";
|
||||
import WebhookListPage from "./WebhookListPage";
|
||||
import WebhookEditPage from "./WebhookEditPage";
|
||||
import LdapEditPage from "./LdapEditPage";
|
||||
import LdapSyncPage from "./LdapSyncPage";
|
||||
import MfaSetupPage from "./auth/MfaSetupPage";
|
||||
import CustomGithubCorner from "./common/CustomGithubCorner";
|
||||
import * as Conf from "./Conf";
|
||||
|
||||
@@ -514,48 +514,47 @@ class App extends Component {
|
||||
<Route exact path="/groups/:organizationName/:groupName" render={(props) => this.renderLoginIfNotLoggedIn(<GroupEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/users" render={(props) => this.renderLoginIfNotLoggedIn(<UserListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/users/:organizationName/:userName" render={(props) => <UserEditPage account={this.state.account} {...props} />} />
|
||||
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/applications/:organizationName/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs/:organizationName/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/roles" render={(props) => this.renderLoginIfNotLoggedIn(<RoleListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/roles/:organizationName/:roleName" render={(props) => this.renderLoginIfNotLoggedIn(<RoleEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/permissions" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/permissions/:organizationName/:permissionName" render={(props) => this.renderLoginIfNotLoggedIn(<PermissionEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/models" render={(props) => this.renderLoginIfNotLoggedIn(<ModelListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/models/:organizationName/:modelName" render={(props) => this.renderLoginIfNotLoggedIn(<ModelEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/enforcers" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/enforcers/:organizationName/:enforcerName" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/adapters" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/adapters/:organizationName/:adapterName" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/applications/:organizationName/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />
|
||||
{/* <Route exact path="/resources/:resourceName" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceEditPage account={this.state.account} {...props} />)}/>*/}
|
||||
<Route exact path="/ldap/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/ldap/sync/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapSyncPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/tokens" render={(props) => this.renderLoginIfNotLoggedIn(<TokenListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/enforcers" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/enforcers/:organizationName/:enforcerName" render={(props) => this.renderLoginIfNotLoggedIn(<EnforcerEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/sessions" render={(props) => this.renderLoginIfNotLoggedIn(<SessionListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/tokens" render={(props) => this.renderLoginIfNotLoggedIn(<TokenListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/tokens/:tokenName" render={(props) => this.renderLoginIfNotLoggedIn(<TokenEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/webhooks" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs/:organizationName/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/plans" render={(props) => this.renderLoginIfNotLoggedIn(<PlanListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/plans/:organizationName/:planName" render={(props) => this.renderLoginIfNotLoggedIn(<PlanEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/pricings" render={(props) => this.renderLoginIfNotLoggedIn(<PricingListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/pricings/:organizationName/:pricingName" render={(props) => this.renderLoginIfNotLoggedIn(<PricingEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/subscriptions" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/subscriptions/:organizationName/:subscriptionName" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/products" render={(props) => this.renderLoginIfNotLoggedIn(<ProductListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/products/:organizationName/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/products/:organizationName/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/payments/:organizationName/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/payments/:organizationName/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/plans" render={(props) => this.renderLoginIfNotLoggedIn(<PlanListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/plans/:organizationName/:planName" render={(props) => this.renderLoginIfNotLoggedIn(<PlanEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/pricings" render={(props) => this.renderLoginIfNotLoggedIn(<PricingListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/pricings/:organizationName/:pricingName" render={(props) => this.renderLoginIfNotLoggedIn(<PricingEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/subscriptions" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/subscriptions/:organizationName/:subscriptionName" render={(props) => this.renderLoginIfNotLoggedIn(<SubscriptionEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/webhooks" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/webhooks/:webhookName" render={(props) => this.renderLoginIfNotLoggedIn(<WebhookEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/ldap/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/ldap/sync/:organizationName/:ldapId" render={(props) => this.renderLoginIfNotLoggedIn(<LdapSyncPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/mfa/setup" render={(props) => this.renderLoginIfNotLoggedIn(<MfaSetupPage account={this.state.account} onfinish={() => this.setState({requiredEnableMfa: false})} {...props} />)} />
|
||||
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
||||
<Route exact path="/sysinfo" render={(props) => this.renderLoginIfNotLoggedIn(<SystemInfo account={this.state.account} {...props} />)} />
|
||||
<Route path="" render={() => <Result status="404" title="404 NOT FOUND" subTitle={i18next.t("general:Sorry, the page you visited does not exist.")}
|
||||
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>} />} />
|
||||
</Switch>
|
||||
|
@@ -29,6 +29,14 @@ import {CaptchaPreview} from "./common/CaptchaPreview";
|
||||
import {CountryCodeSelect} from "./common/select/CountryCodeSelect";
|
||||
import * as Web3Auth from "./auth/Web3Auth";
|
||||
|
||||
import {Controlled as CodeMirror} from "react-codemirror2";
|
||||
import "codemirror/lib/codemirror.css";
|
||||
|
||||
require("codemirror/theme/material-darker.css");
|
||||
require("codemirror/mode/htmlmixed/htmlmixed");
|
||||
require("codemirror/mode/xml/xml");
|
||||
require("codemirror/mode/css/css");
|
||||
|
||||
const {Option} = Select;
|
||||
const {TextArea} = Input;
|
||||
|
||||
@@ -480,7 +488,7 @@ class ProviderEditPage extends React.Component {
|
||||
this.updateProviderField("port", 465);
|
||||
this.updateProviderField("disableSsl", false);
|
||||
this.updateProviderField("title", "Casdoor Verification Code");
|
||||
this.updateProviderField("content", "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes.");
|
||||
this.updateProviderField("content", Setting.getDefaultHtmlEmailContent());
|
||||
this.updateProviderField("receiver", this.props.account.email);
|
||||
} else if (value === "SMS") {
|
||||
this.updateProviderField("type", "Twilio SMS");
|
||||
@@ -966,22 +974,47 @@ class ProviderEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("provider:Email content"), i18next.t("provider:Email content - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<TextArea autoSize={{minRows: 3, maxRows: 100}} value={this.state.provider.content} onChange={e => {
|
||||
this.updateProviderField("content", e.target.value);
|
||||
}} />
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => this.updateProviderField("content", "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes.")} >
|
||||
{i18next.t("provider:Reset to Default Text")}
|
||||
</Button>
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary" onClick={() => this.updateProviderField("content", Setting.getDefaultHtmlEmailContent())} >
|
||||
{i18next.t("provider:Reset to Default HTML")}
|
||||
</Button>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{height: "300px", margin: "10px"}}>
|
||||
<CodeMirror
|
||||
value={this.state.provider.content}
|
||||
options={{mode: "htmlmixed", theme: "material-darker"}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.updateProviderField("content", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={1} />
|
||||
<Col span={Setting.isMobile() ? 22 : 11}>
|
||||
<div style={{margin: "10px"}}>
|
||||
<div dangerouslySetInnerHTML={{__html: this.state.provider.content.replace("%s", "123456").replace("%{user.friendlyName}", Setting.getFriendlyUserName(this.props.account))}} />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Row style={{marginTop: "20px"}}>
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Test Email"), i18next.t("provider:Test Email - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={4} >
|
||||
<Input value={this.state.provider.receiver} placeholder = {i18next.t("user:Input your email")} onChange={e => {
|
||||
this.updateProviderField("receiver", e.target.value);
|
||||
}} />
|
||||
<Col span={4}>
|
||||
<Input value={this.state.provider.receiver} placeholder={i18next.t("user:Input your email")}
|
||||
onChange={e => {
|
||||
this.updateProviderField("receiver", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
{["Azure ACS"].includes(this.state.provider.type) ? null : (
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} type="primary" onClick={() => ProviderEditTestEmail.connectSmtpServer(this.state.provider)} >
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => ProviderEditTestEmail.connectSmtpServer(this.state.provider)} >
|
||||
{i18next.t("provider:Test SMTP Connection")}
|
||||
</Button>
|
||||
)}
|
||||
|
@@ -1405,3 +1405,53 @@ export function getCurrencySymbol(currency) {
|
||||
return currency;
|
||||
}
|
||||
}
|
||||
|
||||
export function getFriendlyUserName(account) {
|
||||
if (account.firstName !== "" && account.lastName !== "") {
|
||||
return `${account.firstName}, ${account.lastName}`;
|
||||
} else if (account.displayName !== "") {
|
||||
return account.displayName;
|
||||
} else if (account.name !== "") {
|
||||
return account.name;
|
||||
} else {
|
||||
return account.id;
|
||||
}
|
||||
}
|
||||
|
||||
export function getDefaultHtmlEmailContent() {
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Verification Code Email</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; }
|
||||
.email-container { width: 600px; margin: 0 auto; }
|
||||
.header { text-align: center; }
|
||||
.code { font-size: 24px; margin: 20px 0; text-align: center; }
|
||||
.footer { font-size: 12px; text-align: center; margin-top: 50px; }
|
||||
.footer a { color: #000; text-decoration: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="email-container">
|
||||
<div class="header">
|
||||
<h3>Casbin Organization</h3>
|
||||
<img src="https://cdn.casbin.org/img/casdoor-logo_1185x256.png" alt="Casdoor Logo" width="300">
|
||||
</div>
|
||||
<p><strong>%{user.friendlyName}</strong>, here is your verification code</p>
|
||||
<p>Use this code for your transaction. It's valid for 5 minutes</p>
|
||||
<div class="code">
|
||||
%s
|
||||
</div>
|
||||
<p>Thanks</p>
|
||||
<p>Casbin Team</p>
|
||||
<hr>
|
||||
<div class="footer">
|
||||
<p>Casdoor is a brand operated by Casbin organization. For more info please refer to <a href="https://casdoor.org">https://casdoor.org</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ export function connectSmtpServer(provider) {
|
||||
testEmailProvider(provider)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", "provider:SMTP connected successfully");
|
||||
Setting.showMessage("success", i18next.t("provider:SMTP connected successfully"));
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
}
|
||||
|
Reference in New Issue
Block a user