Compare commits

..

7 Commits

Author SHA1 Message Date
DacongDA
e2e3c1fbb8 feat: support Product.SuccessUrl (#3908) 2025-06-26 22:52:07 +08:00
David
73915ac0a0 feat: fix issue that LDAP user address was not syncing (#3905) 2025-06-26 09:38:16 +08:00
Attack825
bf9d55ff40 feat: add InitCleanupTokens() (#3903) 2025-06-26 09:31:59 +08:00
XiangYe
b36fb50239 feat: fix check bug to allow logged-in users to buy product (#3897) 2025-06-25 10:49:20 +08:00
Øßfusion
4307baa759 feat: fix Tumblr OAuth's wrong scope (#3898) 2025-06-25 09:55:02 +08:00
David
3964bae1df feat: fix org's LDAP table wrong link (#3900) 2025-06-25 09:51:40 +08:00
Yang Luo
d9b97d70be feat: change CRLF to LF for some files 2025-06-24 09:55:00 +08:00
72 changed files with 1244 additions and 1117 deletions

8
.gitattributes vendored
View File

@@ -1,5 +1,5 @@
*.go linguist-detectable=true
*.js linguist-detectable=false
# Declare files that will always have LF line endings on checkout.
# Git will always convert line endings to LF on checkout. You should use this for files that must keep LF endings, even on Windows.
*.go linguist-detectable=true
*.js linguist-detectable=false
# Declare files that will always have LF line endings on checkout.
# Git will always convert line endings to LF on checkout. You should use this for files that must keep LF endings, even on Windows.
*.sh text eol=lf

204
README.md
View File

@@ -1,102 +1,102 @@
<h1 align="center" style="border-bottom: none;">📦⚡️ Casdoor</h1>
<h3 align="center">An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and RADIUS</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
</a>
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
</p>
<p align="center">
<a href="https://goreportcard.com/report/github.com/casdoor/casdoor">
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casdoor/casdoor?style=flat-square" alt="license">
</a>
<a href="https://github.com/casdoor/casdoor/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casdoor/casdoor?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casdoor/casdoor?style=flat-square">
</a>
<a href="https://crowdin.com/project/casdoor-site">
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
</a>
<a href="https://discord.gg/5rPsrAzK7S">
<img alt="Discord" src="https://img.shields.io/discord/1022748306096537660?style=flat-square&logo=discord&label=discord&color=5865F2">
</a>
</p>
<p align="center">
<sup>Sponsored by</sup>
<br>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.casbin.org/img/stytch-white.png">
<source media="(prefers-color-scheme: light)" srcset="https://cdn.casbin.org/img/stytch-charcoal.png">
<img src="https://cdn.casbin.org/img/stytch-charcoal.png" width="275">
</picture>
</a><br/>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin"><b>Build auth with fraud prevention, faster.</b><br/> Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.</a>
<br>
</p>
## Online demo
- Read-only site: https://door.casdoor.com (any modification operation will fail)
- Writable site: https://demo.casdoor.com (original data will be restored for every 5 minutes)
## Documentation
https://casdoor.org
## Install
- By source code: https://casdoor.org/docs/basic/server-installation
- By Docker: https://casdoor.org/docs/basic/try-with-docker
- By Kubernetes Helm: https://casdoor.org/docs/basic/try-with-helm
## How to connect to Casdoor?
https://casdoor.org/docs/how-to-connect/overview
## Casdoor Public API
- Docs: https://casdoor.org/docs/basic/public-api
- Swagger: https://door.casdoor.com/swagger
## Integrations
https://casdoor.org/docs/category/integrations
## How to contact?
- Discord: https://discord.gg/5rPsrAzK7S
- Contact: https://casdoor.org/help
## Contribute
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
### I18n translation
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the `web/` directory, please remember to add what you have added to the `web/src/locales/en/data.json` file.
## License
[Apache-2.0](https://github.com/casdoor/casdoor/blob/master/LICENSE)
<h1 align="center" style="border-bottom: none;">📦⚡️ Casdoor</h1>
<h3 align="center">An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and RADIUS</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
</a>
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
</p>
<p align="center">
<a href="https://goreportcard.com/report/github.com/casdoor/casdoor">
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casdoor/casdoor?style=flat-square" alt="license">
</a>
<a href="https://github.com/casdoor/casdoor/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casdoor/casdoor?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casdoor/casdoor?style=flat-square">
</a>
<a href="https://crowdin.com/project/casdoor-site">
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
</a>
<a href="https://discord.gg/5rPsrAzK7S">
<img alt="Discord" src="https://img.shields.io/discord/1022748306096537660?style=flat-square&logo=discord&label=discord&color=5865F2">
</a>
</p>
<p align="center">
<sup>Sponsored by</sup>
<br>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.casbin.org/img/stytch-white.png">
<source media="(prefers-color-scheme: light)" srcset="https://cdn.casbin.org/img/stytch-charcoal.png">
<img src="https://cdn.casbin.org/img/stytch-charcoal.png" width="275">
</picture>
</a><br/>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin"><b>Build auth with fraud prevention, faster.</b><br/> Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.</a>
<br>
</p>
## Online demo
- Read-only site: https://door.casdoor.com (any modification operation will fail)
- Writable site: https://demo.casdoor.com (original data will be restored for every 5 minutes)
## Documentation
https://casdoor.org
## Install
- By source code: https://casdoor.org/docs/basic/server-installation
- By Docker: https://casdoor.org/docs/basic/try-with-docker
- By Kubernetes Helm: https://casdoor.org/docs/basic/try-with-helm
## How to connect to Casdoor?
https://casdoor.org/docs/how-to-connect/overview
## Casdoor Public API
- Docs: https://casdoor.org/docs/basic/public-api
- Swagger: https://door.casdoor.com/swagger
## Integrations
https://casdoor.org/docs/category/integrations
## How to contact?
- Discord: https://discord.gg/5rPsrAzK7S
- Contact: https://casdoor.org/help
## Contribute
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
### I18n translation
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the `web/` directory, please remember to add what you have added to the `web/src/locales/en/data.json` file.
## License
[Apache-2.0](https://github.com/casdoor/casdoor/blob/master/LICENSE)

View File

@@ -51,6 +51,6 @@ func (c *ApiController) UploadGroups() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("group_upload:Failed to import groups"))
c.ResponseError(c.T("general:Failed to import groups"))
}
}

View File

@@ -49,6 +49,6 @@ func (c *ApiController) UploadPermissions() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("user_upload:Failed to import users"))
c.ResponseError(c.T("general:Failed to import users"))
}
}

View File

@@ -182,7 +182,7 @@ func (c *ApiController) BuyProduct() {
paidUserName := c.Input().Get("userName")
owner, _ := util.GetOwnerAndNameFromId(id)
userId := util.GetId(owner, paidUserName)
if paidUserName != "" && !c.IsAdmin() {
if paidUserName != "" && paidUserName != c.GetSessionUsername() && !c.IsAdmin() {
c.ResponseError(c.T("general:Only admin user can specify user"))
return
}

View File

@@ -49,6 +49,6 @@ func (c *ApiController) UploadRoles() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("user_upload:Failed to import users"))
c.ResponseError(c.T("general:Failed to import users"))
}
}

View File

@@ -67,6 +67,6 @@ func (c *ApiController) UploadUsers() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("user_upload:Failed to import users"))
c.ResponseError(c.T("general:Failed to import users"))
}
}

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Nepodařilo se importovat uživatele",
"Missing parameter": "Chybějící parametr",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Prosím, přihlaste se nejprve",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Nové heslo nemůže obsahovat prázdné místo.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Nepodařilo se importovat uživatele"
},
"util": {
"No application is found for userId: %s": "Pro userId: %s nebyla nalezena žádná aplikace",
"No provider for category: %s is found for application: %s": "Pro kategorii: %s nebyl nalezen žádný poskytovatel pro aplikaci: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Fehler beim Importieren von Benutzern",
"Missing parameter": "Fehlender Parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Bitte zuerst einloggen",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Das neue Passwort darf keine Leerzeichen enthalten.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Fehler beim Importieren von Benutzern"
},
"util": {
"No application is found for userId: %s": "Es wurde keine Anwendung für die Benutzer-ID gefunden: %s",
"No provider for category: %s is found for application: %s": "Kein Anbieter für die Kategorie %s gefunden für die Anwendung: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Error al importar usuarios",
"Missing parameter": "Parámetro faltante",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Por favor, inicia sesión primero",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "La nueva contraseña no puede contener espacios en blanco.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Error al importar usuarios"
},
"util": {
"No application is found for userId: %s": "No se encuentra ninguna aplicación para el Id de usuario: %s",
"No provider for category: %s is found for application: %s": "No se encuentra un proveedor para la categoría: %s para la aplicación: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "عدم موفقیت در وارد کردن کاربران",
"Missing parameter": "پارامتر گمشده",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "لطفاً ابتدا وارد شوید",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "رمز عبور جدید نمی‌تواند حاوی فاصله خالی باشد.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "عدم موفقیت در وارد کردن کاربران"
},
"util": {
"No application is found for userId: %s": "هیچ برنامه‌ای برای userId: %s یافت نشد",
"No provider for category: %s is found for application: %s": "هیچ ارائه‌دهنده‌ای برای دسته‌بندی: %s برای برنامه: %s یافت نشد",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Échec de l'importation des utilisateurs",
"Missing parameter": "Paramètre manquant",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Veuillez d'abord vous connecter",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Le nouveau mot de passe ne peut pas contenir d'espace.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Échec de l'importation des utilisateurs"
},
"util": {
"No application is found for userId: %s": "Aucune application n'a été trouvée pour l'identifiant d'utilisateur : %s",
"No provider for category: %s is found for application: %s": "Aucun fournisseur pour la catégorie: %s n'est trouvé pour l'application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Gagal mengimpor pengguna",
"Missing parameter": "Parameter hilang",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Silahkan login terlebih dahulu",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Sandi baru tidak boleh mengandung spasi kosong.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Gagal mengimpor pengguna"
},
"util": {
"No application is found for userId: %s": "Tidak ditemukan aplikasi untuk userId: %s",
"No provider for category: %s is found for application: %s": "Tidak ditemukan penyedia untuk kategori: %s untuk aplikasi: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "ユーザーのインポートに失敗しました",
"Missing parameter": "不足しているパラメーター",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "最初にログインしてください",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "新しいパスワードにはスペースを含めることはできません。",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "ユーザーのインポートに失敗しました"
},
"util": {
"No application is found for userId: %s": "ユーザーIDに対するアプリケーションが見つかりません %s",
"No provider for category: %s is found for application: %s": "アプリケーション:%sのカテゴリ%sのプロバイダが見つかりません",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "사용자 가져오기를 실패했습니다",
"Missing parameter": "누락된 매개변수",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "먼저 로그인 하십시오",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "새 비밀번호에는 공백이 포함될 수 없습니다.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "사용자 가져오기를 실패했습니다"
},
"util": {
"No application is found for userId: %s": "어플리케이션을 찾을 수 없습니다. userId: %s",
"No provider for category: %s is found for application: %s": "어플리케이션 %s에서 %s 카테고리를 위한 공급자가 찾을 수 없습니다",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Falha ao importar usuários",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Falha ao importar usuários"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Не удалось импортировать пользователей",
"Missing parameter": "Отсутствующий параметр",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Пожалуйста, сначала войдите в систему",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Новый пароль не может содержать пробелы.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Не удалось импортировать пользователей"
},
"util": {
"No application is found for userId: %s": "Не найдено заявки для пользователя с идентификатором: %s",
"No provider for category: %s is found for application: %s": "Нет провайдера для категории: %s для приложения: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Nepodarilo sa importovať používateľov",
"Missing parameter": "Chýbajúci parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Najskôr sa prosím prihláste",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Nové heslo nemôže obsahovať medzery.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Nepodarilo sa importovať používateľov"
},
"util": {
"No application is found for userId: %s": "Nebola nájdená žiadna aplikácia pre userId: %s",
"No provider for category: %s is found for application: %s": "Pre aplikáciu: %s nebol nájdený žiadny poskytovateľ pre kategóriu: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Yeni şifreniz boşluk karakteri içeremez.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Không thể nhập người dùng",
"Missing parameter": "Thiếu tham số",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Vui lòng đăng nhập trước",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "Mật khẩu mới không thể chứa dấu trắng.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"user_upload": {
"Failed to import users": "Không thể nhập người dùng"
},
"util": {
"No application is found for userId: %s": "Không tìm thấy ứng dụng cho ID người dùng: %s",
"No provider for category: %s is found for application: %s": "Không tìm thấy nhà cung cấp cho danh mục: %s cho ứng dụng: %s",

View File

@@ -92,6 +92,8 @@
"the adapter: %s is not found": "适配器: %s 未找到"
},
"general": {
"Failed to import groups": "导入群组失败",
"Failed to import users": "导入用户失败",
"Missing parameter": "缺少参数",
"Only admin user can specify user": "仅管理员用户可以指定用户",
"Please login first": "请先登录",
@@ -162,9 +164,6 @@
"New password cannot contain blank space.": "新密码不可以包含空格",
"the user's owner and name should not be empty": "用户的组织和名称不能为空"
},
"user_upload": {
"Failed to import users": "导入用户失败"
},
"util": {
"No application is found for userId: %s": "未找到用户: %s的应用",
"No provider for category: %s is found for application: %s": "未找到类别为: %s的提供商来满足应用: %s",

View File

@@ -45,6 +45,7 @@ func main() {
object.InitUserManager()
object.InitFromFile()
object.InitCasvisorConfig()
object.InitCleanupTokens()
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
util.SafeGoroutine(func() { controllers.InitCLIDownloader() })

View File

@@ -260,15 +260,15 @@ func AutoAdjustLdapUser(users []LdapUser) []LdapUser {
res := make([]LdapUser, len(users))
for i, user := range users {
res[i] = LdapUser{
UidNumber: user.UidNumber,
Uid: user.Uid,
Cn: user.Cn,
GroupId: user.GidNumber,
Uuid: user.GetLdapUuid(),
DisplayName: user.DisplayName,
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
Mobile: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
RegisteredAddress: util.ReturnAnyNotEmpty(user.PostalAddress, user.RegisteredAddress),
UidNumber: user.UidNumber,
Uid: user.Uid,
Cn: user.Cn,
GroupId: user.GidNumber,
Uuid: user.GetLdapUuid(),
DisplayName: user.DisplayName,
Email: util.ReturnAnyNotEmpty(user.Email, user.EmailAddress, user.Mail),
Mobile: util.ReturnAnyNotEmpty(user.Mobile, user.MobileTelephoneNumber, user.TelephoneNumber),
Address: util.ReturnAnyNotEmpty(user.Address, user.PostalAddress, user.RegisteredAddress),
}
}
return res

View File

@@ -42,6 +42,7 @@ type Product struct {
IsRecharge bool `json:"isRecharge"`
Providers []string `xorm:"varchar(255)" json:"providers"`
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
SuccessUrl string `xorm:"varchar(1000)" json:"successUrl"`
State string `xorm:"varchar(100)" json:"state"`
@@ -213,6 +214,10 @@ func BuyProduct(id string, user *User, providerName, pricingName, planName, host
returnUrl = fmt.Sprintf("%s/buy-plan/%s/%s/result?subscription=%s", originFrontend, owner, pricingName, sub.Name)
}
}
if product.SuccessUrl != "" {
returnUrl = fmt.Sprintf("%s?transactionOwner=%s&transactionName=%s", product.SuccessUrl, owner, paymentName)
}
// Create an order
payReq := &pp.PayReq{
ProviderName: providerName,

86
object/token_cleanup.go Normal file
View File

@@ -0,0 +1,86 @@
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"time"
"github.com/casdoor/casdoor/util"
"github.com/golang-jwt/jwt/v5"
"github.com/robfig/cron/v3"
)
func CleanupTokens(tokenRetentionIntervalAfterExpiry int) error {
var sessions []*Token
err := ormer.Engine.Where("expires_in = ?", 0).Find(&sessions)
if err != nil {
return fmt.Errorf("failed to query expired tokens: %w", err)
}
currentTime := util.String2Time(util.GetCurrentUnixTime())
for _, session := range sessions {
tokenString := session.AccessToken
token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
fmt.Printf("Failed to parse token %s: %v\n", session.Name, err)
continue
}
if claims, ok := token.Claims.(jwt.MapClaims); ok {
exp, ok := claims["exp"].(float64)
if !ok {
fmt.Printf("Token %s does not have an 'exp' claim\n", session.Name)
continue
}
expireTime := time.Unix(int64(exp), 0)
tokenAfterExpiry := currentTime.Sub(expireTime).Seconds()
if tokenAfterExpiry > float64(tokenRetentionIntervalAfterExpiry) {
_, err = ormer.Engine.Delete(session)
if err != nil {
return fmt.Errorf("failed to delete expired token %s: %w", session.Name, err)
}
fmt.Printf("Deleted expired token: %s\n", session.Name)
}
} else {
fmt.Printf("Token %s is not valid\n", session.Name)
}
}
return nil
}
func getTokenRetentionInterval(days int) int {
if days <= 0 {
days = 30
}
return days * 24 * 3600
}
func InitCleanupTokens() {
schedule := "0 0 0 * * ?"
cronJob := cron.New()
_, err := cronJob.AddFunc(schedule, func() {
interval := getTokenRetentionInterval(30)
if err := CleanupTokens(interval); err != nil {
fmt.Printf("Error cleaning up tokens: %v\n", err)
}
})
if err != nil {
fmt.Printf("Error scheduling token cleanup: %v\n", err)
return
}
cronJob.Start()
}

View File

@@ -1,97 +1,97 @@
const CracoLessPlugin = require("craco-less");
const path = require("path");
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/swagger": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/files": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/.well-known/openid-configuration": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/serviceValidate": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/proxyValidate": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/proxy": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/validate": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/scim": {
target: "http://localhost:8000",
changeOrigin: true,
}
},
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {"@primary-color": "rgb(89,54,213)", "@border-radius-base": "5px"},
javascriptEnabled: true,
},
},
},
},
],
webpack: {
configure: (webpackConfig, { env, paths }) => {
paths.appBuild = path.resolve(__dirname, "build-temp");
webpackConfig.output.path = path.resolve(__dirname, "build-temp");
// ignore webpack warnings by source-map-loader
// https://github.com/facebook/create-react-app/pull/11752#issuecomment-1345231546
webpackConfig.ignoreWarnings = [
function ignoreSourcemapsloaderWarnings(warning) {
return (
warning.module &&
warning.module.resource.includes("node_modules") &&
warning.details &&
warning.details.includes("source-map-loader")
);
},
];
// use polyfill Buffer with Webpack 5
// https://viglucci.io/articles/how-to-polyfill-buffer-with-webpack-5
// https://craco.js.org/docs/configuration/webpack/
webpackConfig.resolve.fallback = {
buffer: require.resolve("buffer/"),
process: false,
util: false,
url: false,
zlib: false,
stream: false,
http: false,
https: false,
assert: false,
crypto: false,
os: false,
fs: false,
};
return webpackConfig;
},
},
};
const CracoLessPlugin = require("craco-less");
const path = require("path");
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/swagger": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/files": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/.well-known/openid-configuration": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/serviceValidate": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/proxyValidate": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/proxy": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/cas/validate": {
target: "http://localhost:8000",
changeOrigin: true,
},
"/scim": {
target: "http://localhost:8000",
changeOrigin: true,
}
},
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {"@primary-color": "rgb(89,54,213)", "@border-radius-base": "5px"},
javascriptEnabled: true,
},
},
},
},
],
webpack: {
configure: (webpackConfig, { env, paths }) => {
paths.appBuild = path.resolve(__dirname, "build-temp");
webpackConfig.output.path = path.resolve(__dirname, "build-temp");
// ignore webpack warnings by source-map-loader
// https://github.com/facebook/create-react-app/pull/11752#issuecomment-1345231546
webpackConfig.ignoreWarnings = [
function ignoreSourcemapsloaderWarnings(warning) {
return (
warning.module &&
warning.module.resource.includes("node_modules") &&
warning.details &&
warning.details.includes("source-map-loader")
);
},
];
// use polyfill Buffer with Webpack 5
// https://viglucci.io/articles/how-to-polyfill-buffer-with-webpack-5
// https://craco.js.org/docs/configuration/webpack/
webpackConfig.resolve.fallback = {
buffer: require.resolve("buffer/"),
process: false,
util: false,
url: false,
zlib: false,
stream: false,
http: false,
https: false,
assert: false,
crypto: false,
os: false,
fs: false,
};
return webpackConfig;
},
},
};

View File

@@ -1,21 +1,21 @@
const fs = require("fs");
const path = require("path");
const sourceDir = path.join(__dirname, "build-temp");
const targetDir = path.join(__dirname, "build");
if (!fs.existsSync(sourceDir)) {
// eslint-disable-next-line no-console
console.error(`Source directory "${sourceDir}" does not exist.`);
process.exit(1);
}
if (fs.existsSync(targetDir)) {
fs.rmSync(targetDir, {recursive: true, force: true});
// eslint-disable-next-line no-console
console.log(`Target directory "${targetDir}" has been deleted successfully.`);
}
fs.renameSync(sourceDir, targetDir);
// eslint-disable-next-line no-console
console.log(`Renamed "${sourceDir}" to "${targetDir}" successfully.`);
const fs = require("fs");
const path = require("path");
const sourceDir = path.join(__dirname, "build-temp");
const targetDir = path.join(__dirname, "build");
if (!fs.existsSync(sourceDir)) {
// eslint-disable-next-line no-console
console.error(`Source directory "${sourceDir}" does not exist.`);
process.exit(1);
}
if (fs.existsSync(targetDir)) {
fs.rmSync(targetDir, {recursive: true, force: true});
// eslint-disable-next-line no-console
console.log(`Target directory "${targetDir}" has been deleted successfully.`);
}
fs.renameSync(sourceDir, targetDir);
// eslint-disable-next-line no-console
console.log(`Renamed "${sourceDir}" to "${targetDir}" successfully.`);

View File

@@ -1,36 +1,36 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export const DefaultApplication = "app-built-in";
export const CasvisorUrl = "";
export const ShowGithubCorner = false;
export const IsDemoMode = false;
export const ForceLanguage = "";
export const DefaultLanguage = "en";
export const InitThemeAlgorithm = true;
export const ThemeDefault = {
themeType: "default",
colorPrimary: "#5734d3",
borderRadius: 6,
isCompact: false,
};
export const CustomFooter = null;
// Blank or null to hide Ai Assistant button
export const AiAssistantUrl = "https://ai.casbin.com";
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export const DefaultApplication = "app-built-in";
export const CasvisorUrl = "";
export const ShowGithubCorner = false;
export const IsDemoMode = false;
export const ForceLanguage = "";
export const DefaultLanguage = "en";
export const InitThemeAlgorithm = true;
export const ThemeDefault = {
themeType: "default",
colorPrimary: "#5734d3",
borderRadius: 6,
isCompact: false,
};
export const CustomFooter = null;
// Blank or null to hide Ai Assistant button
export const AiAssistantUrl = "https://ai.casbin.com";

View File

@@ -288,6 +288,16 @@ class ProductEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("product:Success URL"), i18next.t("product:Success URL - Tooltip"))} :
</Col>
<Col span={22} >
<Input prefix={<LinkOutlined />} value={this.state.product.successUrl} onChange={e => {
this.updateProductField("successUrl", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:State"), i18next.t("general:State - Tooltip"))} :

View File

@@ -1,341 +1,341 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {Button, Image, Table, Upload} from "antd";
import {UploadOutlined} from "@ant-design/icons";
import copy from "copy-to-clipboard";
import * as Setting from "./Setting";
import * as ResourceBackend from "./backend/ResourceBackend";
import i18next from "i18next";
import {Link} from "react-router-dom";
import BaseListPage from "./BaseListPage";
import PopconfirmModal from "./common/modal/PopconfirmModal";
class ResourceListPage extends BaseListPage {
constructor(props) {
super(props);
}
componentDidMount() {
this.setState({
fileList: [],
uploading: false,
});
}
deleteResource(i) {
ResourceBackend.deleteResource(this.state.data[i])
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
this.fetch({
pagination: {
...this.state.pagination,
current: this.state.pagination.current > 1 && this.state.data.length === 1 ? this.state.pagination.current - 1 : this.state.pagination.current,
},
});
} else {
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
});
}
handleUpload(info) {
this.setState({uploading: true});
const filename = info.fileList[0].name;
const fullFilePath = `resource/${this.props.account.owner}/${this.props.account.name}/${filename}`;
ResourceBackend.uploadResource(this.props.account.owner, this.props.account.name, "custom", "ResourceListPage", fullFilePath, info.file)
.then(res => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("application:File uploaded successfully"));
const {pagination} = this.state;
this.fetch({pagination});
} else {
Setting.showMessage("error", res.msg);
}
}).finally(() => {
this.setState({uploading: false});
});
}
renderUpload() {
return (
<Upload maxCount={1} accept="image/*,video/*,audio/*,.pdf,.doc,.docx,.csv,.xls,.xlsx" showUploadList={false}
beforeUpload={file => {return false;}} onChange={info => {this.handleUpload(info);}}>
<Button id="upload-button" icon={<UploadOutlined />} loading={this.state.uploading} type="primary" size="small">
{i18next.t("resource:Upload a file...")}
</Button>
</Upload>
);
}
renderTable(resources) {
const columns = [
{
title: i18next.t("general:Provider"),
dataIndex: "provider",
key: "provider",
width: "150px",
sorter: true,
...this.getColumnSearchProps("provider"),
render: (text, record, index) => {
return (
<Link to={`/providers/${record.owner}/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Application"),
dataIndex: "application",
key: "application",
width: "80px",
sorter: true,
...this.getColumnSearchProps("application"),
render: (text, record, index) => {
return (
<Link to={`/applications/${record.owner}/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:User"),
dataIndex: "user",
key: "user",
width: "80px",
sorter: true,
...this.getColumnSearchProps("user"),
render: (text, record, index) => {
return (
<Link to={`/users/${record.owner}/${record.user}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("resource:Parent"),
dataIndex: "parent",
key: "parent",
width: "80px",
sorter: true,
...this.getColumnSearchProps("parent"),
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "150px",
sorter: true,
...this.getColumnSearchProps("name"),
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
key: "createdTime",
width: "150px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
},
},
{
title: i18next.t("user:Tag"),
dataIndex: "tag",
key: "tag",
width: "80px",
sorter: true,
...this.getColumnSearchProps("tag"),
},
// {
// title: i18next.t("resource:File name"),
// dataIndex: 'fileName',
// key: 'fileName',
// width: '120px',
// sorter: (a, b) => a.fileName.localeCompare(b.fileName),
// },
{
title: i18next.t("provider:Type"),
dataIndex: "fileType",
key: "fileType",
width: "80px",
sorter: true,
...this.getColumnSearchProps("fileType"),
},
{
title: i18next.t("resource:Format"),
dataIndex: "fileFormat",
key: "fileFormat",
width: "80px",
sorter: true,
...this.getColumnSearchProps("fileFormat"),
},
{
title: i18next.t("resource:File size"),
dataIndex: "fileSize",
key: "fileSize",
width: "100px",
sorter: true,
render: (text, record, index) => {
return Setting.getFriendlyFileSize(text);
},
},
{
title: i18next.t("general:Preview"),
dataIndex: "preview",
key: "preview",
width: "100px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
if (record.fileType === "image") {
const errorImage = "data:image/png;base64,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";
return (
<Image
width={200}
src={record.url}
fallback={errorImage}
/>
);
} else if (record.fileType === "video") {
return (
<video width={200} controls>
<source src={record.url} type="video/mp4" />
</video>
);
}
},
},
{
title: i18next.t("general:URL"),
dataIndex: "url",
key: "url",
width: "120px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return (
<div>
<Button onClick={() => {
copy(record.url);
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
}}
>
{i18next.t("resource:Copy Link")}
</Button>
</div>
);
},
},
{
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "70px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return (
<div>
<PopconfirmModal
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
onConfirm={() => this.deleteResource(index)}
okText={i18next.t("general:OK")}
cancelText={i18next.t("general:Cancel")}
>
</PopconfirmModal>
</div>
);
},
},
];
const paginationProps = {
total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
<div>
<Table scroll={{x: "max-content"}} columns={columns} dataSource={resources} rowKey="name" size="middle" bordered pagination={paginationProps}
title={() => (
<div>
{i18next.t("general:Resources")}&nbsp;&nbsp;&nbsp;&nbsp;
{/* <Button type="primary" size="small" onClick={this.addResource.bind(this)}>{i18next.t("general:Add")}</Button>*/}
{
this.renderUpload()
}
</div>
)}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
</div>
);
}
fetch = (params = {}) => {
const field = params.searchedColumn, value = params.searchText;
const sortField = params.sortField, sortOrder = params.sortOrder;
this.setState({loading: true});
ResourceBackend.getResources(Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), this.props.account.name, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
.then((res) => {
this.setState({
loading: false,
});
if (res.status === "ok") {
this.setState({
data: res.data,
pagination: {
...params.pagination,
total: res.data2,
},
searchText: params.searchText,
searchedColumn: params.searchedColumn,
});
} else {
if (res.data.includes("Please login first")) {
this.setState({
loading: false,
isAuthorized: false,
});
}
}
});
};
}
export default ResourceListPage;
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {Button, Image, Table, Upload} from "antd";
import {UploadOutlined} from "@ant-design/icons";
import copy from "copy-to-clipboard";
import * as Setting from "./Setting";
import * as ResourceBackend from "./backend/ResourceBackend";
import i18next from "i18next";
import {Link} from "react-router-dom";
import BaseListPage from "./BaseListPage";
import PopconfirmModal from "./common/modal/PopconfirmModal";
class ResourceListPage extends BaseListPage {
constructor(props) {
super(props);
}
componentDidMount() {
this.setState({
fileList: [],
uploading: false,
});
}
deleteResource(i) {
ResourceBackend.deleteResource(this.state.data[i])
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
this.fetch({
pagination: {
...this.state.pagination,
current: this.state.pagination.current > 1 && this.state.data.length === 1 ? this.state.pagination.current - 1 : this.state.pagination.current,
},
});
} else {
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
}
})
.catch(error => {
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
});
}
handleUpload(info) {
this.setState({uploading: true});
const filename = info.fileList[0].name;
const fullFilePath = `resource/${this.props.account.owner}/${this.props.account.name}/${filename}`;
ResourceBackend.uploadResource(this.props.account.owner, this.props.account.name, "custom", "ResourceListPage", fullFilePath, info.file)
.then(res => {
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("application:File uploaded successfully"));
const {pagination} = this.state;
this.fetch({pagination});
} else {
Setting.showMessage("error", res.msg);
}
}).finally(() => {
this.setState({uploading: false});
});
}
renderUpload() {
return (
<Upload maxCount={1} accept="image/*,video/*,audio/*,.pdf,.doc,.docx,.csv,.xls,.xlsx" showUploadList={false}
beforeUpload={file => {return false;}} onChange={info => {this.handleUpload(info);}}>
<Button id="upload-button" icon={<UploadOutlined />} loading={this.state.uploading} type="primary" size="small">
{i18next.t("resource:Upload a file...")}
</Button>
</Upload>
);
}
renderTable(resources) {
const columns = [
{
title: i18next.t("general:Provider"),
dataIndex: "provider",
key: "provider",
width: "150px",
sorter: true,
...this.getColumnSearchProps("provider"),
render: (text, record, index) => {
return (
<Link to={`/providers/${record.owner}/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Application"),
dataIndex: "application",
key: "application",
width: "80px",
sorter: true,
...this.getColumnSearchProps("application"),
render: (text, record, index) => {
return (
<Link to={`/applications/${record.owner}/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:User"),
dataIndex: "user",
key: "user",
width: "80px",
sorter: true,
...this.getColumnSearchProps("user"),
render: (text, record, index) => {
return (
<Link to={`/users/${record.owner}/${record.user}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("resource:Parent"),
dataIndex: "parent",
key: "parent",
width: "80px",
sorter: true,
...this.getColumnSearchProps("parent"),
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "150px",
sorter: true,
...this.getColumnSearchProps("name"),
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
key: "createdTime",
width: "150px",
sorter: true,
render: (text, record, index) => {
return Setting.getFormattedDate(text);
},
},
{
title: i18next.t("user:Tag"),
dataIndex: "tag",
key: "tag",
width: "80px",
sorter: true,
...this.getColumnSearchProps("tag"),
},
// {
// title: i18next.t("resource:File name"),
// dataIndex: 'fileName',
// key: 'fileName',
// width: '120px',
// sorter: (a, b) => a.fileName.localeCompare(b.fileName),
// },
{
title: i18next.t("provider:Type"),
dataIndex: "fileType",
key: "fileType",
width: "80px",
sorter: true,
...this.getColumnSearchProps("fileType"),
},
{
title: i18next.t("resource:Format"),
dataIndex: "fileFormat",
key: "fileFormat",
width: "80px",
sorter: true,
...this.getColumnSearchProps("fileFormat"),
},
{
title: i18next.t("resource:File size"),
dataIndex: "fileSize",
key: "fileSize",
width: "100px",
sorter: true,
render: (text, record, index) => {
return Setting.getFriendlyFileSize(text);
},
},
{
title: i18next.t("general:Preview"),
dataIndex: "preview",
key: "preview",
width: "100px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
if (record.fileType === "image") {
const errorImage = "data:image/png;base64,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";
return (
<Image
width={200}
src={record.url}
fallback={errorImage}
/>
);
} else if (record.fileType === "video") {
return (
<video width={200} controls>
<source src={record.url} type="video/mp4" />
</video>
);
}
},
},
{
title: i18next.t("general:URL"),
dataIndex: "url",
key: "url",
width: "120px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return (
<div>
<Button onClick={() => {
copy(record.url);
Setting.showMessage("success", i18next.t("general:Copied to clipboard successfully"));
}}
>
{i18next.t("resource:Copy Link")}
</Button>
</div>
);
},
},
{
title: i18next.t("general:Action"),
dataIndex: "",
key: "op",
width: "70px",
fixed: (Setting.isMobile()) ? "false" : "right",
render: (text, record, index) => {
return (
<div>
<PopconfirmModal
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
onConfirm={() => this.deleteResource(index)}
okText={i18next.t("general:OK")}
cancelText={i18next.t("general:Cancel")}
>
</PopconfirmModal>
</div>
);
},
},
];
const paginationProps = {
total: this.state.pagination.total,
showQuickJumper: true,
showSizeChanger: true,
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
};
return (
<div>
<Table scroll={{x: "max-content"}} columns={columns} dataSource={resources} rowKey="name" size="middle" bordered pagination={paginationProps}
title={() => (
<div>
{i18next.t("general:Resources")}&nbsp;&nbsp;&nbsp;&nbsp;
{/* <Button type="primary" size="small" onClick={this.addResource.bind(this)}>{i18next.t("general:Add")}</Button>*/}
{
this.renderUpload()
}
</div>
)}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
</div>
);
}
fetch = (params = {}) => {
const field = params.searchedColumn, value = params.searchText;
const sortField = params.sortField, sortOrder = params.sortOrder;
this.setState({loading: true});
ResourceBackend.getResources(Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), this.props.account.name, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
.then((res) => {
this.setState({
loading: false,
});
if (res.status === "ok") {
this.setState({
data: res.data,
pagination: {
...params.pagination,
total: res.data2,
},
searchText: params.searchText,
searchedColumn: params.searchedColumn,
});
} else {
if (res.data.includes("Please login first")) {
this.setState({
loading: false,
isAuthorized: false,
});
}
}
});
};
}
export default ResourceListPage;

View File

@@ -1,30 +1,30 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import * as Setting from "../Setting";
class OdicDiscoveryPage extends React.Component {
UNSAFE_componentWillMount() {
if (Setting.isLocalhost()) {
Setting.goToLink(`${Setting.ServerUrl}/.well-known/openid-configuration`);
}
}
render() {
return null;
}
}
export default OdicDiscoveryPage;
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import * as Setting from "../Setting";
class OdicDiscoveryPage extends React.Component {
UNSAFE_componentWillMount() {
if (Setting.isLocalhost()) {
Setting.goToLink(`${Setting.ServerUrl}/.well-known/openid-configuration`);
}
}
render() {
return null;
}
}
export default OdicDiscoveryPage;

View File

@@ -278,7 +278,7 @@ const authInfo = {
endpoint: "https://www.tiktok.com/auth/authorize/",
},
Tumblr: {
scope: "email",
scope: "basic",
endpoint: "https://www.tumblr.com/oauth2/authorize",
},
Twitch: {

View File

@@ -1,31 +1,31 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {createButton} from "react-social-login-buttons";
function Icon({width = 24, height = 24, color}) {
return <svg xmlns="http://www.w3.org/2000/svg" height="48" width="32" viewBox="-18.15 -35.9725 157.3 215.835"><path fill="#faab07" d="M60.503 142.237c-12.533 0-24.038-4.195-31.445-10.46-3.762 1.124-8.574 2.932-11.61 5.175-2.6 1.918-2.275 3.874-1.807 4.663 2.056 3.47 35.273 2.216 44.862 1.136zm0 0c12.535 0 24.039-4.195 31.447-10.46 3.76 1.124 8.573 2.932 11.61 5.175 2.598 1.918 2.274 3.874 1.805 4.663-2.056 3.47-35.272 2.216-44.862 1.136zm0 0" /><path d="M60.576 67.119c20.698-.14 37.286-4.147 42.907-5.683 1.34-.367 2.056-1.024 2.056-1.024.005-.189.085-3.37.085-5.01C105.624 27.768 92.58.001 60.5 0 28.42.001 15.375 27.769 15.375 55.401c0 1.642.08 4.822.086 5.01 0 0 .583.615 1.65.913 5.19 1.444 22.09 5.65 43.312 5.795zm56.245 23.02c-1.283-4.129-3.034-8.944-4.808-13.568 0 0-1.02-.126-1.537.023-15.913 4.623-35.202 7.57-49.9 7.392h-.153c-14.616.175-33.774-2.737-49.634-7.315-.606-.175-1.802-.1-1.802-.1-1.774 4.624-3.525 9.44-4.808 13.568-6.119 19.69-4.136 27.838-2.627 28.02 3.239.392 12.606-14.821 12.606-14.821 0 15.459 13.957 39.195 45.918 39.413h.848c31.96-.218 45.917-23.954 45.917-39.413 0 0 9.368 15.213 12.607 14.822 1.508-.183 3.491-8.332-2.627-28.021" /><path fill="#fff" d="M49.085 40.824c-4.352.197-8.07-4.76-8.304-11.063-.236-6.305 3.098-11.576 7.45-11.773 4.347-.195 8.064 4.76 8.3 11.065.238 6.306-3.097 11.577-7.446 11.771m31.133-11.063c-.233 6.302-3.951 11.26-8.303 11.063-4.35-.195-7.684-5.465-7.446-11.77.236-6.305 3.952-11.26 8.3-11.066 4.352.197 7.686 5.468 7.449 11.773" /><path fill="#faab07" d="M87.952 49.725C86.79 47.15 75.077 44.28 60.578 44.28h-.156c-14.5 0-26.212 2.87-27.375 5.446a.863.863 0 00-.085.367.88.88 0 00.16.496c.98 1.427 13.985 8.487 27.3 8.487h.156c13.314 0 26.319-7.058 27.299-8.487a.873.873 0 00.16-.498.856.856 0 00-.085-.365" /><path d="M54.434 29.854c.199 2.49-1.167 4.702-3.046 4.943-1.883.242-3.568-1.58-3.768-4.07-.197-2.492 1.167-4.704 3.043-4.944 1.886-.244 3.574 1.58 3.771 4.07m11.956.833c.385-.689 3.004-4.312 8.427-2.993 1.425.347 2.084.857 2.223 1.057.205.296.262.718.053 1.286-.412 1.126-1.263 1.095-1.734.875-.305-.142-4.082-2.66-7.562 1.097-.24.257-.668.346-1.073.04-.407-.308-.574-.93-.334-1.362" /><path fill="#fff" d="M60.576 83.08h-.153c-9.996.12-22.116-1.204-33.854-3.518-1.004 5.818-1.61 13.132-1.09 21.853 1.316 22.043 14.407 35.9 34.614 36.1h.82c20.208-.2 33.298-14.057 34.616-36.1.52-8.723-.087-16.035-1.092-21.854-11.739 2.315-23.862 3.64-33.86 3.518" /><path fill="#eb1923" d="M32.102 81.235v21.693s9.937 2.004 19.893.616V83.535c-6.307-.357-13.109-1.152-19.893-2.3" /><path fill="#eb1923" d="M105.539 60.412s-19.33 6.102-44.963 6.275h-.153c-25.591-.172-44.896-6.255-44.962-6.275L8.987 76.57c16.193 4.882 36.261 8.028 51.436 7.845h.153c15.175.183 35.242-2.963 51.437-7.845zm0 0" /></svg>;
}
const config = {
text: "Sign in with QQ",
icon: Icon,
iconFormat: name => `fa fa-${name}`,
style: {background: "rgb(94,188,249)"},
activeStyle: {background: "rgb(76,143,208)"},
};
const QqLoginButton = createButton(config);
export default QqLoginButton;
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {createButton} from "react-social-login-buttons";
function Icon({width = 24, height = 24, color}) {
return <svg xmlns="http://www.w3.org/2000/svg" height="48" width="32" viewBox="-18.15 -35.9725 157.3 215.835"><path fill="#faab07" d="M60.503 142.237c-12.533 0-24.038-4.195-31.445-10.46-3.762 1.124-8.574 2.932-11.61 5.175-2.6 1.918-2.275 3.874-1.807 4.663 2.056 3.47 35.273 2.216 44.862 1.136zm0 0c12.535 0 24.039-4.195 31.447-10.46 3.76 1.124 8.573 2.932 11.61 5.175 2.598 1.918 2.274 3.874 1.805 4.663-2.056 3.47-35.272 2.216-44.862 1.136zm0 0" /><path d="M60.576 67.119c20.698-.14 37.286-4.147 42.907-5.683 1.34-.367 2.056-1.024 2.056-1.024.005-.189.085-3.37.085-5.01C105.624 27.768 92.58.001 60.5 0 28.42.001 15.375 27.769 15.375 55.401c0 1.642.08 4.822.086 5.01 0 0 .583.615 1.65.913 5.19 1.444 22.09 5.65 43.312 5.795zm56.245 23.02c-1.283-4.129-3.034-8.944-4.808-13.568 0 0-1.02-.126-1.537.023-15.913 4.623-35.202 7.57-49.9 7.392h-.153c-14.616.175-33.774-2.737-49.634-7.315-.606-.175-1.802-.1-1.802-.1-1.774 4.624-3.525 9.44-4.808 13.568-6.119 19.69-4.136 27.838-2.627 28.02 3.239.392 12.606-14.821 12.606-14.821 0 15.459 13.957 39.195 45.918 39.413h.848c31.96-.218 45.917-23.954 45.917-39.413 0 0 9.368 15.213 12.607 14.822 1.508-.183 3.491-8.332-2.627-28.021" /><path fill="#fff" d="M49.085 40.824c-4.352.197-8.07-4.76-8.304-11.063-.236-6.305 3.098-11.576 7.45-11.773 4.347-.195 8.064 4.76 8.3 11.065.238 6.306-3.097 11.577-7.446 11.771m31.133-11.063c-.233 6.302-3.951 11.26-8.303 11.063-4.35-.195-7.684-5.465-7.446-11.77.236-6.305 3.952-11.26 8.3-11.066 4.352.197 7.686 5.468 7.449 11.773" /><path fill="#faab07" d="M87.952 49.725C86.79 47.15 75.077 44.28 60.578 44.28h-.156c-14.5 0-26.212 2.87-27.375 5.446a.863.863 0 00-.085.367.88.88 0 00.16.496c.98 1.427 13.985 8.487 27.3 8.487h.156c13.314 0 26.319-7.058 27.299-8.487a.873.873 0 00.16-.498.856.856 0 00-.085-.365" /><path d="M54.434 29.854c.199 2.49-1.167 4.702-3.046 4.943-1.883.242-3.568-1.58-3.768-4.07-.197-2.492 1.167-4.704 3.043-4.944 1.886-.244 3.574 1.58 3.771 4.07m11.956.833c.385-.689 3.004-4.312 8.427-2.993 1.425.347 2.084.857 2.223 1.057.205.296.262.718.053 1.286-.412 1.126-1.263 1.095-1.734.875-.305-.142-4.082-2.66-7.562 1.097-.24.257-.668.346-1.073.04-.407-.308-.574-.93-.334-1.362" /><path fill="#fff" d="M60.576 83.08h-.153c-9.996.12-22.116-1.204-33.854-3.518-1.004 5.818-1.61 13.132-1.09 21.853 1.316 22.043 14.407 35.9 34.614 36.1h.82c20.208-.2 33.298-14.057 34.616-36.1.52-8.723-.087-16.035-1.092-21.854-11.739 2.315-23.862 3.64-33.86 3.518" /><path fill="#eb1923" d="M32.102 81.235v21.693s9.937 2.004 19.893.616V83.535c-6.307-.357-13.109-1.152-19.893-2.3" /><path fill="#eb1923" d="M105.539 60.412s-19.33 6.102-44.963 6.275h-.153c-25.591-.172-44.896-6.255-44.962-6.275L8.987 76.57c16.193 4.882 36.261 8.028 51.436 7.845h.153c15.175.183 35.242-2.963 51.437-7.845zm0 0" /></svg>;
}
const config = {
text: "Sign in with QQ",
icon: Icon,
iconFormat: name => `fa fa-${name}`,
style: {background: "rgb(94,188,249)"},
activeStyle: {background: "rgb(76,143,208)"},
};
const QqLoginButton = createButton(config);
export default QqLoginButton;

View File

@@ -1,85 +1,85 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import * as Setting from "../Setting";
export function getResources(owner, user, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-resources?owner=${owner}&user=${user}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function getResource(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-resource?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function updateResource(owner, name, resource) {
const newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/update-resource?id=${owner}/${encodeURIComponent(name)}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newResource),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function addResource(resource) {
const newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/add-resource`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newResource),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function deleteResource(resource, provider = "") {
const newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/delete-resource?provider=${provider}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newResource),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function uploadResource(owner, user, tag, parent, fullFilePath, file, provider = "") {
const application = "app-built-in";
const formData = new FormData();
formData.append("file", file);
return fetch(`${Setting.ServerUrl}/api/upload-resource?owner=${owner}&user=${user}&application=${application}&tag=${tag}&parent=${parent}&fullFilePath=${encodeURIComponent(fullFilePath)}&provider=${provider}`, {
body: formData,
method: "POST",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import * as Setting from "../Setting";
export function getResources(owner, user, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-resources?owner=${owner}&user=${user}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function getResource(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-resource?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function updateResource(owner, name, resource) {
const newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/update-resource?id=${owner}/${encodeURIComponent(name)}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newResource),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function addResource(resource) {
const newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/add-resource`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newResource),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function deleteResource(resource, provider = "") {
const newResource = Setting.deepCopy(resource);
return fetch(`${Setting.ServerUrl}/api/delete-resource?provider=${provider}`, {
method: "POST",
credentials: "include",
body: JSON.stringify(newResource),
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function uploadResource(owner, user, tag, parent, fullFilePath, file, provider = "") {
const application = "app-built-in";
const formData = new FormData();
formData.append("file", file);
return fetch(`${Setting.ServerUrl}/api/upload-resource?owner=${owner}&user=${user}&application=${application}&tag=${tag}&parent=${parent}&fullFilePath=${encodeURIComponent(fullFilePath)}&provider=${provider}`, {
body: formData,
method: "POST",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}

View File

@@ -1,229 +1,229 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {Button, Col, Row} from "antd";
import i18next from "i18next";
import * as UserBackend from "../backend/UserBackend";
import * as Setting from "../Setting";
import * as Provider from "../auth/Provider";
import * as AuthBackend from "../auth/AuthBackend";
import {goToWeb3Url} from "../auth/ProviderButton";
import AccountAvatar from "../account/AccountAvatar";
import {WechatOfficialAccountModal} from "../auth/Util";
class OAuthWidget extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
addressOptions: [],
affiliationOptions: [],
};
}
UNSAFE_componentWillMount() {
this.getAddressOptions(this.props.application);
this.getAffiliationOptions(this.props.application, this.props.user);
}
getAddressOptions(application) {
if (application.affiliationUrl === "") {
return;
}
const addressUrl = application.affiliationUrl.split("|")[0];
UserBackend.getAddressOptions(addressUrl)
.then((addressOptions) => {
this.setState({
addressOptions: addressOptions,
});
});
}
getAffiliationOptions(application, user) {
if (application.affiliationUrl === "") {
return;
}
const affiliationUrl = application.affiliationUrl.split("|")[1];
const code = user.address[user.address.length - 1];
UserBackend.getAffiliationOptions(affiliationUrl, code)
.then((affiliationOptions) => {
this.setState({
affiliationOptions: affiliationOptions,
});
});
}
updateUserField(key, value) {
this.props.onUpdateUserField(key, value);
}
unlinked() {
this.props.onUnlinked();
}
getProviderLink(user, provider) {
if (provider.type === "GitHub") {
return `https://github.com/${this.getUserProperty(user, provider.type, "username")}`;
} else if (provider.type === "Google") {
return "https://mail.google.com";
} else {
return "";
}
}
getUserProperty(user, providerType, propertyName) {
const key = `oauth_${providerType}_${propertyName}`;
if (user.properties === null) {return "";}
return user.properties[key];
}
unlinkUser(providerType, linkedValue) {
const body = {
providerType: providerType,
// should add the unlink user's info, cause the user may not be logged in, but a admin want to unlink the user.
user: this.props.user,
};
if (providerType === "MetaMask" || providerType === "Web3Onboard") {
import("../auth/Web3Auth")
.then(module => {
const delWeb3AuthToken = module.delWeb3AuthToken;
delWeb3AuthToken(linkedValue);
AuthBackend.unlink(body)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Unlinked successfully");
this.unlinked();
} else {
Setting.showMessage("error", `Failed to unlink: ${res.msg}`);
}
});
});
return;
}
AuthBackend.unlink(body)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Unlinked successfully");
this.unlinked();
} else {
Setting.showMessage("error", `Failed to unlink: ${res.msg}`);
}
});
}
renderIdp(user, application, providerItem) {
const provider = providerItem.provider;
const linkedValue = user[provider.type.toLowerCase()];
const profileUrl = this.getProviderLink(user, provider);
const id = this.getUserProperty(user, provider.type, "id");
const username = this.getUserProperty(user, provider.type, "username");
const displayName = this.getUserProperty(user, provider.type, "displayName");
const email = this.getUserProperty(user, provider.type, "email");
let avatarUrl = this.getUserProperty(user, provider.type, "avatarUrl");
// the account user
const account = this.props.account;
if (avatarUrl === "" || avatarUrl === undefined) {
avatarUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAQAAACROWYpAAAAHElEQVR42mNkoAAwjmoe1TyqeVTzqOZRzcNZMwB18wAfEFQkPQAAAABJRU5ErkJggg==";
}
let name = (username === undefined) ? displayName : `${displayName} (${username})`;
if (name === undefined) {
if (id !== undefined) {
name = id;
} else if (email !== undefined) {
name = email;
} else {
name = linkedValue;
}
}
let linkButtonWidth = "110px";
if (Setting.getLanguage() === "id") {
linkButtonWidth = "160px";
}
return (
<Row key={provider.name} style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={this.props.labelSpan}>
{
Setting.getProviderLogo(provider)
}
<span style={{marginLeft: "5px"}}>
{
`${provider.type}:`
}
</span>
</Col>
<Col span={24 - this.props.labelSpan} >
<AccountAvatar style={{marginRight: "10px"}} size={30} src={avatarUrl} alt={name} referrerPolicy="no-referrer" />
<span style={{
width: this.props.labelSpan === 3 ? "300px" : "200px",
display: (Setting.isMobile()) ? "inline" : "inline-block",
overflow: "hidden",
textOverflow: "ellipsis",
}} title={name}>
{
linkedValue === "" ? (
`(${i18next.t("general:empty")})`
) : (
profileUrl === "" ? name : (
<a target="_blank" rel="noreferrer" href={profileUrl}>
{
name
}
</a>
)
)
}
</span>
{
linkedValue === "" ? (
provider.category === "Web3" ? (
<Button style={{marginLeft: "20px", width: linkButtonWidth}} type="primary" disabled={user.id !== account.id} onClick={() => goToWeb3Url(application, provider, "link")}>{i18next.t("user:Link")}</Button>
) : (
provider.type === "WeChat" && provider.clientId2 !== "" && provider.clientSecret2 !== "" && provider.disableSsl === true && !navigator.userAgent.includes("MicroMessenger") ? (
<a key={provider.displayName}>
<Button style={{marginLeft: "20px", width: linkButtonWidth}} type="primary" disabled={user.id !== account.id} onClick={
() => {
WechatOfficialAccountModal(application, provider, "link");
}
}>{i18next.t("user:Link")}</Button>
</a>
) : (
<a key={provider.displayName} href={user.id !== account.id ? null : Provider.getAuthUrl(application, provider, "link")}>
<Button style={{marginLeft: "20px", width: linkButtonWidth}} type="primary" disabled={user.id !== account.id}>{i18next.t("user:Link")}</Button>
</a>
)
)
) : (
<Button disabled={!providerItem.canUnlink && !Setting.isAdminUser(account)} style={{marginLeft: "20px", width: linkButtonWidth}} onClick={() => this.unlinkUser(provider.type, linkedValue)}>{i18next.t("user:Unlink")}</Button>
)
}
</Col>
</Row>
);
}
render() {
return this.renderIdp(this.props.user, this.props.application, this.props.providerItem);
}
}
export default OAuthWidget;
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import {Button, Col, Row} from "antd";
import i18next from "i18next";
import * as UserBackend from "../backend/UserBackend";
import * as Setting from "../Setting";
import * as Provider from "../auth/Provider";
import * as AuthBackend from "../auth/AuthBackend";
import {goToWeb3Url} from "../auth/ProviderButton";
import AccountAvatar from "../account/AccountAvatar";
import {WechatOfficialAccountModal} from "../auth/Util";
class OAuthWidget extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
addressOptions: [],
affiliationOptions: [],
};
}
UNSAFE_componentWillMount() {
this.getAddressOptions(this.props.application);
this.getAffiliationOptions(this.props.application, this.props.user);
}
getAddressOptions(application) {
if (application.affiliationUrl === "") {
return;
}
const addressUrl = application.affiliationUrl.split("|")[0];
UserBackend.getAddressOptions(addressUrl)
.then((addressOptions) => {
this.setState({
addressOptions: addressOptions,
});
});
}
getAffiliationOptions(application, user) {
if (application.affiliationUrl === "") {
return;
}
const affiliationUrl = application.affiliationUrl.split("|")[1];
const code = user.address[user.address.length - 1];
UserBackend.getAffiliationOptions(affiliationUrl, code)
.then((affiliationOptions) => {
this.setState({
affiliationOptions: affiliationOptions,
});
});
}
updateUserField(key, value) {
this.props.onUpdateUserField(key, value);
}
unlinked() {
this.props.onUnlinked();
}
getProviderLink(user, provider) {
if (provider.type === "GitHub") {
return `https://github.com/${this.getUserProperty(user, provider.type, "username")}`;
} else if (provider.type === "Google") {
return "https://mail.google.com";
} else {
return "";
}
}
getUserProperty(user, providerType, propertyName) {
const key = `oauth_${providerType}_${propertyName}`;
if (user.properties === null) {return "";}
return user.properties[key];
}
unlinkUser(providerType, linkedValue) {
const body = {
providerType: providerType,
// should add the unlink user's info, cause the user may not be logged in, but a admin want to unlink the user.
user: this.props.user,
};
if (providerType === "MetaMask" || providerType === "Web3Onboard") {
import("../auth/Web3Auth")
.then(module => {
const delWeb3AuthToken = module.delWeb3AuthToken;
delWeb3AuthToken(linkedValue);
AuthBackend.unlink(body)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Unlinked successfully");
this.unlinked();
} else {
Setting.showMessage("error", `Failed to unlink: ${res.msg}`);
}
});
});
return;
}
AuthBackend.unlink(body)
.then((res) => {
if (res.status === "ok") {
Setting.showMessage("success", "Unlinked successfully");
this.unlinked();
} else {
Setting.showMessage("error", `Failed to unlink: ${res.msg}`);
}
});
}
renderIdp(user, application, providerItem) {
const provider = providerItem.provider;
const linkedValue = user[provider.type.toLowerCase()];
const profileUrl = this.getProviderLink(user, provider);
const id = this.getUserProperty(user, provider.type, "id");
const username = this.getUserProperty(user, provider.type, "username");
const displayName = this.getUserProperty(user, provider.type, "displayName");
const email = this.getUserProperty(user, provider.type, "email");
let avatarUrl = this.getUserProperty(user, provider.type, "avatarUrl");
// the account user
const account = this.props.account;
if (avatarUrl === "" || avatarUrl === undefined) {
avatarUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAQAAACROWYpAAAAHElEQVR42mNkoAAwjmoe1TyqeVTzqOZRzcNZMwB18wAfEFQkPQAAAABJRU5ErkJggg==";
}
let name = (username === undefined) ? displayName : `${displayName} (${username})`;
if (name === undefined) {
if (id !== undefined) {
name = id;
} else if (email !== undefined) {
name = email;
} else {
name = linkedValue;
}
}
let linkButtonWidth = "110px";
if (Setting.getLanguage() === "id") {
linkButtonWidth = "160px";
}
return (
<Row key={provider.name} style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={this.props.labelSpan}>
{
Setting.getProviderLogo(provider)
}
<span style={{marginLeft: "5px"}}>
{
`${provider.type}:`
}
</span>
</Col>
<Col span={24 - this.props.labelSpan} >
<AccountAvatar style={{marginRight: "10px"}} size={30} src={avatarUrl} alt={name} referrerPolicy="no-referrer" />
<span style={{
width: this.props.labelSpan === 3 ? "300px" : "200px",
display: (Setting.isMobile()) ? "inline" : "inline-block",
overflow: "hidden",
textOverflow: "ellipsis",
}} title={name}>
{
linkedValue === "" ? (
`(${i18next.t("general:empty")})`
) : (
profileUrl === "" ? name : (
<a target="_blank" rel="noreferrer" href={profileUrl}>
{
name
}
</a>
)
)
}
</span>
{
linkedValue === "" ? (
provider.category === "Web3" ? (
<Button style={{marginLeft: "20px", width: linkButtonWidth}} type="primary" disabled={user.id !== account.id} onClick={() => goToWeb3Url(application, provider, "link")}>{i18next.t("user:Link")}</Button>
) : (
provider.type === "WeChat" && provider.clientId2 !== "" && provider.clientSecret2 !== "" && provider.disableSsl === true && !navigator.userAgent.includes("MicroMessenger") ? (
<a key={provider.displayName}>
<Button style={{marginLeft: "20px", width: linkButtonWidth}} type="primary" disabled={user.id !== account.id} onClick={
() => {
WechatOfficialAccountModal(application, provider, "link");
}
}>{i18next.t("user:Link")}</Button>
</a>
) : (
<a key={provider.displayName} href={user.id !== account.id ? null : Provider.getAuthUrl(application, provider, "link")}>
<Button style={{marginLeft: "20px", width: linkButtonWidth}} type="primary" disabled={user.id !== account.id}>{i18next.t("user:Link")}</Button>
</a>
)
)
) : (
<Button disabled={!providerItem.canUnlink && !Setting.isAdminUser(account)} style={{marginLeft: "20px", width: linkButtonWidth}} onClick={() => this.unlinkUser(provider.type, linkedValue)}>{i18next.t("user:Unlink")}</Button>
)
}
</Col>
</Row>
);
}
render() {
return this.renderIdp(this.props.user, this.props.application, this.props.providerItem);
}
}
export default OAuthWidget;

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Přizpůsobit hlavičku vstupní stránky vaší aplikace",
"Incremental": "Inkrementální",
"Input": "Vstup",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Kód pozvánky",
"Left": "Vlevo",
"Logged in successfully": "Úspěšně přihlášen",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Nadřazená skupina - Tooltip",
"Physical": "Fyzická",
"Show all": "Zobrazit vše",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtuální",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Prodáno",
"Sold - Tooltip": "Prodávané množství",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Štítek produktu",
"Test buy page..": "Testovací stránka nákupu..",
"There is no payment channel for this product.": "Pro tento produkt neexistuje žádný platební kanál.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Název hostitele",
"IdP": "IdP",
"IdP certificate": "Certifikát IdP",
"Intelligent Validation": "Inteligentní validace",
"Internal": "Interní",
"Issuer URL": "URL vydavatele",
"Issuer URL - Tooltip": "URL vydavatele",
@@ -946,7 +949,6 @@
"Silent": "Tiché",
"Site key": "Klíč stránky",
"Site key - Tooltip": "Nápověda ke klíči stránky",
"Sliding Validation": "Posuvné ověření",
"Sub type": "Podtyp",
"Sub type - Tooltip": "Nápověda k podtypu",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Links",
"Logged in successfully": "Erfolgreich eingeloggt",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Verkauft",
"Sold - Tooltip": "Menge verkauft",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag des Produkts",
"Test buy page..": "Testkaufseite.",
"There is no payment channel for this product.": "Es gibt keinen Zahlungskanal für dieses Produkt.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name des Hosts",
"IdP": "IdP",
"IdP certificate": "IdP-Zertifikat",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer-URL",
"Issuer URL - Tooltip": "Emittenten-URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site-Key",
"Site key - Tooltip": "Seitenschlüssel",
"Sliding Validation": "Sliding Validation",
"Sub type": "Untertyp",
"Sub type - Tooltip": "Unterart",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Izquierda",
"Logged in successfully": "Acceso satisfactorio",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Vendido",
"Sold - Tooltip": "Cantidad vendida",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Etiqueta de producto",
"Test buy page..": "Página de compra de prueba.",
"There is no payment channel for this product.": "No hay canal de pago para este producto.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Nombre del anfitrión",
"IdP": "IdP = Proveedor de Identidad",
"IdP certificate": "Certificado de proveedor de identidad (IdP)",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL del emisor",
"Issuer URL - Tooltip": "URL del emisor",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Clave del sitio",
"Site key - Tooltip": "Clave del sitio",
"Sliding Validation": "Sliding Validation",
"Sub type": "Subtipo",
"Sub type - Tooltip": "Subtipo",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "کد head صفحه ورود برنامه خود را سفارشی کنید",
"Incremental": "افزایشی",
"Input": "ورودی",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "کد دعوت",
"Left": "چپ",
"Logged in successfully": "با موفقیت وارد شدید",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "گروه والد - راهنمای ابزار",
"Physical": "فیزیکی",
"Show all": "نمایش همه",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "مجازی",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "فروخته شده",
"Sold - Tooltip": "تعداد فروخته شده",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "برچسب محصول",
"Test buy page..": "صفحه تست خرید..",
"There is no payment channel for this product.": "برای این محصول کانال پرداختی وجود ندارد.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "نام میزبان",
"IdP": "IdP",
"IdP certificate": "گواهی IdP",
"Intelligent Validation": "اعتبارسنجی هوشمند",
"Internal": "داخلی",
"Issuer URL": "آدرس صادرکننده",
"Issuer URL - Tooltip": "آدرس صادرکننده",
@@ -946,7 +949,6 @@
"Silent": "بی‌صدا",
"Site key": "کلید سایت",
"Site key - Tooltip": "کلید سایت",
"Sliding Validation": "اعتبارسنجی کشویی",
"Sub type": "زیرنوع",
"Sub type - Tooltip": "زیرنوع",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incrémentale",
"Input": "Saisie",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Code d'invitation",
"Left": "Gauche",
"Logged in successfully": "Connexion réussie",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Groupe parent - Infobulle",
"Physical": "Physique",
"Show all": "Tout afficher",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtuel",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Vendu",
"Sold - Tooltip": "Quantité vendue",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Étiquette de produit",
"Test buy page..": "Page d'achat de test.",
"There is no payment channel for this product.": "Il n'y a aucun canal de paiement pour ce produit.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Nom d'hôte",
"IdP": "IdP (Identité Fournisseur)",
"IdP certificate": "Certificat IdP",
"Intelligent Validation": "Validation intelligente",
"Internal": "Interne",
"Issuer URL": "URL de l'émetteur",
"Issuer URL - Tooltip": "URL de l'émetteur",
@@ -946,7 +949,6 @@
"Silent": "Silencieux",
"Site key": "Clé de site",
"Site key - Tooltip": "Clé de site",
"Sliding Validation": "Validation glissante",
"Sub type": "Sous-type",
"Sub type - Tooltip": "Sous-type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Kiri",
"Logged in successfully": "Berhasil masuk",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Terjual",
"Sold - Tooltip": "Jumlah terjual",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag produk",
"Test buy page..": "Halaman pembelian uji coba.",
"There is no payment channel for this product.": "Tidak ada saluran pembayaran untuk produk ini.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Nama tuan rumah",
"IdP": "IdP",
"IdP certificate": "Sertifikat IdP",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL penerbit",
"Issuer URL - Tooltip": "URL Penerbit",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Kunci situs",
"Site key - Tooltip": "Kunci situs atau kunci halaman web",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub jenis",
"Sub type - Tooltip": "Sub jenis",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "左",
"Logged in successfully": "正常にログインしました",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "売れました",
"Sold - Tooltip": "販売数量",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "製品のタグ",
"Test buy page..": "テスト購入ページ。",
"There is no payment channel for this product.": "この製品には支払いチャネルがありません。",
@@ -860,7 +864,6 @@
"Host - Tooltip": "ホストの名前",
"IdP": "IdP",
"IdP certificate": "IdP証明書",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "発行者のURL",
"Issuer URL - Tooltip": "発行者URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "サイトキー",
"Site key - Tooltip": "サイトキー",
"Sliding Validation": "Sliding Validation",
"Sub type": "サブタイプ",
"Sub type - Tooltip": "サブタイプ",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "왼쪽",
"Logged in successfully": "성공적으로 로그인했습니다",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "팔렸습니다",
"Sold - Tooltip": "판매량",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "제품 태그",
"Test buy page..": "시험 구매 페이지.",
"There is no payment channel for this product.": "이 제품에 대한 결제 채널이 없습니다.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "호스트의 이름",
"IdP": "IdP",
"IdP certificate": "IdP 인증서",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "발행자 URL",
"Issuer URL - Tooltip": "발급자 URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "사이트 키",
"Site key - Tooltip": "사이트 키",
"Sliding Validation": "Sliding Validation",
"Sub type": "하위 유형",
"Sub type - Tooltip": "서브 타입",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Código de convite",
"Left": "Esquerda",
"Logged in successfully": "Login realizado com sucesso",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Vendido",
"Sold - Tooltip": "Quantidade vendida",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag do produto",
"Test buy page..": "Página de teste de compra...",
"There is no payment channel for this product.": "Não há canal de pagamento disponível para este produto.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Nome do host",
"IdP": "IdP",
"IdP certificate": "Certificado IdP",
"Intelligent Validation": "Validação inteligente",
"Internal": "Interno",
"Issuer URL": "URL do Emissor",
"Issuer URL - Tooltip": "URL do Emissor",
@@ -946,7 +949,6 @@
"Silent": "Silencioso",
"Site key": "Chave do site",
"Site key - Tooltip": "Chave do site",
"Sliding Validation": "Validação deslizante",
"Sub type": "Subtipo",
"Sub type - Tooltip": "Subtipo",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Последовательный",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Код приглашения",
"Left": "Левый",
"Logged in successfully": "Успешный вход в систему",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Продано",
"Sold - Tooltip": "Количество проданных",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Метка продукта",
"Test buy page..": "Страница для тестовой покупки.",
"There is no payment channel for this product.": "Для этого продукта нет канала оплаты.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Имя хоста",
"IdP": "ИдП",
"IdP certificate": "Сертификат IdP",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "URL выпускающего органа",
"Issuer URL - Tooltip": "URL эмитента",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Ключ сайта",
"Site key - Tooltip": "Ключ сайта",
"Sliding Validation": "Sliding Validation",
"Sub type": "Подтип",
"Sub type - Tooltip": "Подтип",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Vlastný HTML kód pre hlavičku vašej vstupnej stránky aplikácie",
"Incremental": "Postupný",
"Input": "Vstup",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Kód pozvania",
"Left": "Vľavo",
"Logged in successfully": "Úspešne prihlásený",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Nadradená skupina - Nápoveda",
"Physical": "Fyzická",
"Show all": "Zobraziť všetko",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtuálna",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Predané",
"Sold - Tooltip": "Množstvo predaných kusov",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Štítok produktu",
"Test buy page..": "Testovať stránku nákupu..",
"There is no payment channel for this product.": "Pre tento produkt neexistuje platobný kanál.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Názov hostiteľa",
"IdP": "IdP",
"IdP certificate": "Certifikát IdP",
"Intelligent Validation": "Inteligentné overenie",
"Internal": "Interný",
"Issuer URL": "URL vydavateľa",
"Issuer URL - Tooltip": "URL vydavateľa",
@@ -946,7 +949,6 @@
"Silent": "Tichý",
"Site key": "Kľúč stránky",
"Site key - Tooltip": "Kľúč stránky",
"Sliding Validation": "Posuvné overenie",
"Sub type": "Podtyp",
"Sub type - Tooltip": "Podtyp",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Left",
"Logged in successfully": "Logged in successfully",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Incremental",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Davet Kodu",
"Left": "Sol",
"Logged in successfully": "Başarıyla giriş yapıldı",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Sold",
"Sold - Tooltip": "Quantity sold",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Tag of product",
"Test buy page..": "Test buy page..",
"There is no payment channel for this product.": "There is no payment channel for this product.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Name of host",
"IdP": "IdP",
"IdP certificate": "IdP certificate",
"Intelligent Validation": "Intelligent Validation",
"Internal": "Internal",
"Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL",
@@ -946,7 +949,6 @@
"Silent": "Silent",
"Site key": "Site key",
"Site key - Tooltip": "Site key",
"Sliding Validation": "Sliding Validation",
"Sub type": "Sub type",
"Sub type - Tooltip": "Sub type",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Налаштуйте тег head на сторінці входу до програми",
"Incremental": "Інкрементний",
"Input": "Введення",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Код запрошення",
"Left": "Ліворуч",
"Logged in successfully": "Успішно ввійшли",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Батьківська група - підказка",
"Physical": "фізичний",
"Show all": "Покажи все",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Віртуальний",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Продано",
"Sold - Tooltip": "Продана кількість",
"Stripe": "смужка",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Тег товару",
"Test buy page..": "Сторінка тестової покупки..",
"There is no payment channel for this product.": "Для цього продукту немає платіжного каналу.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Ім'я хоста",
"IdP": "IDP",
"IdP certificate": "сертифікат IdP",
"Intelligent Validation": "Інтелектуальна перевірка",
"Internal": "внутрішній",
"Issuer URL": "URL-адреса емітента",
"Issuer URL - Tooltip": "URL-адреса емітента",
@@ -946,7 +949,6 @@
"Silent": "Мовчазний",
"Site key": "Ключ сайту",
"Site key - Tooltip": "Ключ сайту",
"Sliding Validation": "Ковзна перевірка",
"Sub type": "Підтип",
"Sub type - Tooltip": "Підтип",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "Custom the head tag of your application entry page",
"Incremental": "Tăng",
"Input": "Input",
"Invalid characters in application name": "Invalid characters in application name",
"Invitation code": "Invitation code",
"Left": "Trái",
"Logged in successfully": "Đăng nhập thành công",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "Parent group - Tooltip",
"Physical": "Physical",
"Show all": "Show all",
"Upload (.xlsx)": "Upload (.xlsx)",
"Virtual": "Virtual",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
},
@@ -778,6 +780,8 @@
"Sold": "Đã bán",
"Sold - Tooltip": "Số lượng bán ra",
"Stripe": "Stripe",
"Success URL": "Success URL",
"Success URL - Tooltip": "URL to return to after purchase",
"Tag - Tooltip": "Nhãn sản phẩm",
"Test buy page..": "Trang mua thử.",
"There is no payment channel for this product.": "Không có kênh thanh toán cho sản phẩm này.",
@@ -860,7 +864,6 @@
"Host - Tooltip": "Tên của người chủ chỗ ở",
"IdP": "IdP",
"IdP certificate": "Chứng chỉ IdP",
"Intelligent Validation": "Xác nhận thông minh",
"Internal": "Nội bộ",
"Issuer URL": "Địa chỉ URL của người phát hành",
"Issuer URL - Tooltip": "Địa chỉ URL của nhà phát hành",
@@ -946,7 +949,6 @@
"Silent": "Im lặng",
"Site key": "Khóa trang web",
"Site key - Tooltip": "Khóa trang web",
"Sliding Validation": "Xác nhận trượt ngang",
"Sub type": "Loại phụ",
"Sub type - Tooltip": "Loại phụ",
"Subject": "Subject",

View File

@@ -76,6 +76,7 @@
"Header HTML - Tooltip": "自定义应用页面的head标签",
"Incremental": "递增",
"Input": "输入",
"Invalid characters in application name": "应用名称内有非法字符",
"Invitation code": "邀请码",
"Left": "居左",
"Logged in successfully": "登录成功",
@@ -454,6 +455,7 @@
"Parent group - Tooltip": "上级组",
"Physical": "实体组",
"Show all": "显示全部",
"Upload (.xlsx)": "上传(.xlsx)",
"Virtual": "虚拟组",
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "您需要先删除所有子组。您可以在 [组织] -\u003e [群组] 页面左侧的群组树中查看子组"
},
@@ -778,6 +780,8 @@
"Sold": "售出",
"Sold - Tooltip": "已售出的数量",
"Stripe": "Stripe",
"Success URL": "成功URL",
"Success URL - Tooltip": "支付后跳转的URL",
"Tag - Tooltip": "商品类别",
"Test buy page..": "测试购买页面..",
"There is no payment channel for this product.": "该商品没有付款方式。",
@@ -860,7 +864,6 @@
"Host - Tooltip": "主机名",
"IdP": "身份提供商",
"IdP certificate": "IdP公钥证书",
"Intelligent Validation": "智能验证",
"Internal": "内部",
"Issuer URL": "Issuer链接",
"Issuer URL - Tooltip": "Issuer链接URL",
@@ -946,7 +949,6 @@
"Silent": "静默",
"Site key": "Site key",
"Site key - Tooltip": "站点密钥",
"Sliding Validation": "滑块验证",
"Sub type": "子类型",
"Sub type - Tooltip": "子类型",
"Subject": "主题",

View File

@@ -100,7 +100,7 @@ class LdapTable extends React.Component {
sorter: (a, b) => a.serverName.localeCompare(b.serverName),
render: (text, record, index) => {
return (
<Link to={`/ldaps/${record.id}`}>
<Link to={`/ldap/${record.owner}/${record.id}`}>
{text}
</Link>
);