Compare commits

...

469 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
d6ab3a18ea Address code review feedback: fix X-Forwarded-For logic and add error logging
Co-authored-by: mserico <140243407+mserico@users.noreply.github.com>
2026-02-15 18:36:35 +00:00
copilot-swe-agent[bot]
b7fa3a6194 Format code with gofmt
Co-authored-by: mserico <140243407+mserico@users.noreply.github.com>
2026-02-15 18:34:09 +00:00
copilot-swe-agent[bot]
ac1307e576 Add comprehensive tests for reverse proxy functionality
Co-authored-by: mserico <140243407+mserico@users.noreply.github.com>
2026-02-15 18:32:57 +00:00
copilot-swe-agent[bot]
7f2c238eba Implement basic reverse proxy functionality
Co-authored-by: mserico <140243407+mserico@users.noreply.github.com>
2026-02-15 18:31:03 +00:00
copilot-swe-agent[bot]
2cf83d3b0c Initial plan 2026-02-15 18:24:23 +00:00
Yang Luo
3b8e7c9da2 fix: extend application with reverse proxy fields (#5113) 2026-02-16 02:23:47 +08:00
Yang Luo
4d5de767b0 fix: sync frontend i18n strings 2026-02-16 02:01:48 +08:00
Yang Luo
54bf8eae5c fix: improve category column UI in app list page 2026-02-16 01:46:06 +08:00
IsAurora6
1731b74fa0 fix: fix issue that dummy payments failed when there were too many items in the order (#5108) 2026-02-15 22:35:59 +08:00
Yang Luo
6e1e5dd569 feat: add scope-to-tool permission checking for Casdoor MCP server (#5104) 2026-02-15 22:31:35 +08:00
Yang Luo
b183359daf fix: rename order state PaymentFailed to Failed and improve UI (#5107) 2026-02-15 21:52:24 +08:00
Yang Luo
3cb9df3723 feat: [mcp-5] add Application.Category and Application.Type fields for agent applications (MCP, A2A) (#5102) 2026-02-15 21:28:00 +08:00
Yang Luo
9d1e5c10d0 feat: [mcp-4] implement RFC 8707 Resource Indicators for OAuth 2.0 (#5098) 2026-02-15 18:03:22 +08:00
Yang Luo
ef84c4b0b4 feat: [mcp-3] implement OAuth 2.0 Dynamic Client Registration (RFC 7591) (#5097) 2026-02-15 17:25:44 +08:00
Yang Luo
5a108bd921 fix: [mcp-2] add OAuth 2.0 Authorization Server Metadata endpoints (RFC 8414) (#5094) 2026-02-15 17:00:40 +08:00
Yang Luo
ac671ec1ee fix: rename to wellknown_oidc_discovery.go 2026-02-15 16:42:00 +08:00
Yang Luo
7814caf2ab feat: implement RFC 9728 OAuth 2.0 Protected Resource Metadata for MCP server discovery (#5092) 2026-02-15 16:40:48 +08:00
Yang Luo
f966f4a0f9 feat: fix Dummy payment provider returning zero price in NotifyResult (#5090) 2026-02-15 02:31:56 +08:00
Yang Luo
a4b1a068a8 feat: fix Azure SQL DB panic by migrating to the official go-mssqldb fork (#5082) 2026-02-15 01:52:06 +08:00
Yang Luo
362797678d feat: fix nil pointer panic in update-user API for non-existent account items (#5084) 2026-02-15 01:44:26 +08:00
Yang Luo
7879e1bf09 fix: fix Dummy payment provider to simulate external callback flow (#5080) 2026-02-15 00:18:09 +08:00
IsAurora6
c246f102c9 feat: fix issue that User.Cart cannot be updated without org account items (#5076) 2026-02-14 22:32:58 +08:00
IsAurora6
37d1c4910c feat: Fixed an error when clicking the “delete” button on the cart list page. (#5075) 2026-02-13 20:49:08 +08:00
Yang Luo
3bcde7cb7c feat: add Cart and payment fields to organization account items (#5070) 2026-02-13 10:40:37 +08:00
Yang Luo
6a90d21941 fix: add CreatedTime field to cart items and sort by timestamp (#5066) 2026-02-13 10:36:20 +08:00
Yang Luo
80b4c0b1a7 feat: remove special handling for Dummy payment provider (#5068) 2026-02-13 10:06:14 +08:00
Yang Luo
eb5a422026 feat: replace DisableSsl boolean with SslMode enum for Email providers (#5063) 2026-02-13 02:15:20 +08:00
DacongDA
f7bd70e0a3 feat: improve tab height UI in application edit page (#5055) 2026-02-12 21:57:57 +08:00
Copilot
5e7dbe4b56 feat: fix CAPTCHA rule enforcement in verification code flow (#5009) 2026-02-12 21:22:47 +08:00
Yang Luo
bd1fca2f32 feat: Add LDAP group/OU hierarchy syncing with automatic user membership (#5052) 2026-02-12 17:11:20 +08:00
IsAurora6
3d4cc42f1f feat: mark cart items as invalid when product is removed, renamed, or currency is changed. (#5050) 2026-02-12 00:46:54 +08:00
Yang Luo
1836cab44d feat: fix icons for 5 payment providers 2026-02-11 01:42:37 +08:00
Yang Luo
75b18635f7 feat: fix issue that Webhook records for set-password API were missing user context (#5008) 2026-02-11 01:32:11 +08:00
Yang Luo
47cd44c7ce feat: support "snsapi_privateinfo" scope in WeCom OAuth provider to support fetching Emails (#5034) 2026-02-11 01:21:29 +08:00
Yang Luo
090ca97dcd feat: bind provider IDs in WeCom/DingTalk/Lark syncers (#5033) 2026-02-11 01:04:26 +08:00
Yang Luo
bed01b31f1 feat: add AWS IAM syncer (#5043) 2026-02-11 01:00:41 +08:00
Yang Luo
c8f8f88d85 feat: add "Existing Field" category for token attributes table in application edit page (#5041) 2026-02-11 00:58:50 +08:00
IsAurora6
7acb303995 feat: Fixed cart anomalies when updating product information. (#5039) 2026-02-10 20:58:18 +08:00
IsAurora6
2607f8d3e5 feat: fix DingTalk syncer to fetch nested departments recursively (#5036) 2026-02-10 18:11:03 +08:00
IsAurora6
481db33e58 feat: Optimize the display of rechargeable product content on the ProductStorePage.js. (#5028) 2026-02-09 20:28:18 +08:00
DacongDA
f556c7e11f feat: add PaginateSelect widget to fix non-pagination fetch API issue (#5023) 2026-02-09 20:07:41 +08:00
IsAurora6
f590992f28 feat: update i18n translations (#5021) 2026-02-09 00:05:08 +08:00
Yang Luo
80f9db0fa2 feat: move captcha provider validation from frontend filter to backend check (#5019) 2026-02-08 02:16:47 +08:00
Yang Luo
0748661d2a feat: store OAuth tokens per provider instead of single originalToken field (#5016) 2026-02-08 01:22:24 +08:00
Yang Luo
83552ed143 feat: fix renderRightDropdown() scrollbar UI bug 2026-02-08 00:45:46 +08:00
Yang Luo
8cb8541f96 feat: add Plan.IsExclusive field for single subscription enforcement (#5004) 2026-02-07 01:23:22 +08:00
Yang Luo
5b646a726c fix: fix format issue in DuplicateInfo 2026-02-07 00:51:11 +08:00
Yang Luo
19b9586670 fix: fix broken links for role/plan/user/payment columns (#4999) 2026-02-07 00:46:36 +08:00
Yang Luo
73f8d19c5f fix: de-duplicate i18n translation keys in frontend and backend (#4997) 2026-02-07 00:35:46 +08:00
Yang Luo
04da531df3 fix: sync all i18n strings 2026-02-07 00:18:07 +08:00
Yang Luo
d97558051d fix: add duplicate key detection tests for i18n JSON files (#4994) 2026-02-07 00:17:53 +08:00
Yang Luo
ac55355290 fix: deduplicate the i18n strings 2026-02-06 21:42:10 +08:00
Yang Luo
a2da380be4 feat: add organization sync to DingTalk syncer (#4989) 2026-02-06 20:39:31 +08:00
IsAurora6
ecf8039c5d feat: Add cart icon to ProductStore/ProductBuy and quantity controls to ProductStore/ProductBuy/CartList. (#4984) 2026-02-05 23:07:22 +08:00
Yang Luo
0a6948034c feat: add OAuth 2.0 Token Exchange (RFC 8693) support (#4981) 2026-02-05 19:12:39 +08:00
Yang Luo
442f8fb19e feat: fix DeleteSession to handle missing sessions gracefully (#4979) 2026-02-05 15:41:15 +08:00
Yang Luo
b771add9e3 feat: auto-redirect OAuth signup to callback URL (#4941) 2026-02-05 15:18:33 +08:00
Yang Luo
df8e9fceea feat: disable /forget API when "Forgot Password?" signin item is hidden (#4977) 2026-02-04 23:04:00 +08:00
Yang Luo
d674f0c33d feat: update Swagger docs 2026-02-03 21:34:38 +08:00
buzaslan129
1e1b5273d9 feat: expose get-all-* Casbin endpoints in Swagger (#4952) 2026-02-03 21:32:50 +08:00
IsAurora6
cf5e88915c feat: The order.products display is divided into two parts. Remove the "startTime" and "endTime", and add an updateTime field. (#4968) 2026-02-03 21:12:27 +08:00
Yang Luo
c8973e6c9e feat: add Cloud PNVS SMS provider (#4964) 2026-02-03 02:00:08 +08:00
Yang Luo
87ea451561 feat: support group sync in Google Workspace syncer (#4962) 2026-02-03 01:58:28 +08:00
Yang Luo
8f32779b42 feat: fix invitation code group assignment for OAuth provider signup (#4961) 2026-02-03 01:23:36 +08:00
Yang Luo
aba471b4e8 feat: install lsof in ALLINONE Docker image (#4958) 2026-02-02 23:51:49 +08:00
DacongDA
72b70c3b03 feat: use sqlite DB instead of mariadb for all-in-one Docker image (#4949) 2026-02-02 00:13:14 +08:00
DacongDA
a1c56894c7 feat: add tabs to user edit page (#4945) 2026-02-01 14:01:28 +08:00
Yang Luo
a9ae9394c7 feat: add Linux machine login via LDAP with POSIX attributes (#4944) 2026-01-31 22:37:29 +08:00
Yang Luo
5f0fa5f23e feat: fix properties field xlsx import issue in user list page (#4943) 2026-01-31 01:49:36 +08:00
Yang Luo
f99aa047a9 feat: add Org.AccountItems.Tab field to have tabs in user edit page (#4892) 2026-01-30 21:56:35 +08:00
Yang Luo
1d22b7ebd0 feat: prevent duplicate webhook events from redundant payment notifications (#4936) 2026-01-30 21:56:09 +08:00
IsAurora6
d147053329 feat: Optimize the display of the products column on the order and payment, adjust the color of the “Add to Cart” button. (#4933) 2026-01-30 14:03:15 +08:00
IsAurora6
0f8cd92be4 feat: resolve returnUrl redirection failure of UserEditPage (#4931) 2026-01-29 09:37:47 +08:00
DacongDA
7ea6f1296d feat: fix i18n/generate.go bug in handling "\" (#4930) 2026-01-28 23:35:23 +08:00
Yang Luo
db8c649f5e feat: include payment status in notify-payment webhook payload (#4929) 2026-01-28 19:59:10 +08:00
DacongDA
a06d003589 feat: make codeChallenge dynamic for custom OAuth provider (#4924) 2026-01-28 17:56:28 +08:00
Jacob
33298e44d4 feat(ldap-sync): support syncing phone country code and formatting mobile number (#4919) 2026-01-28 14:09:52 +08:00
IsAurora6
f4d86f8d92 feat: fix incorrect clearing of the returnUrl path parameter in redirects (#4920) 2026-01-28 10:51:44 +08:00
Yang Luo
af4337a1ae feat: add multi-address support to user edit page (#4916) 2026-01-27 21:46:41 +08:00
IsAurora6
81e650df65 feat: Optimize the display of the order price column and improve parameter passing in the OrderPay view mode. (#4912) 2026-01-27 12:17:15 +08:00
Yang Luo
fcea1e4c07 feat: add SCIM 2.0 syncer (#4909) 2026-01-27 01:47:50 +08:00
Yang Luo
639a8a47b1 feat: add Okta syncer (#4908) 2026-01-27 01:19:39 +08:00
Yang Luo
43f61d4426 feat: add Lark syncer (#4897) 2026-01-27 01:00:19 +08:00
IsAurora6
e90cdb8a74 feat: add default payment providers on startup, improve checkProduct() logic (#4895) 2026-01-27 00:23:09 +08:00
DacongDA
bfe8955250 feat: remove bottom save button and extra scrollbar in application edit page (#4890) 2026-01-25 11:03:52 +08:00
DacongDA
36b9c4602a feat: add tab menu for application edit page (#4889) 2026-01-24 18:05:17 +08:00
IsAurora6
18117833e1 feat: Optimize button logic of product buy/store page,non-Created orders display "Detail" Button, and add "clear cart" Button (#4887) 2026-01-24 12:17:44 +08:00
Yang Luo
78dde97b64 feat: add PKCE support for Custom OAuth providers (#4880) 2026-01-23 21:29:57 +08:00
Yang Luo
3a06c66057 feat: fix Azure AD syncer OAuth2 token request - send parameters in body (#4878) 2026-01-22 23:01:38 +08:00
Yang Luo
aa59901400 feat: change Application.TermsOfUse length to 200 chars 2026-01-21 17:24:06 +08:00
IsAurora6
8e03b2d97c feat: Enable subscription-based products to be added to the cart and purchased, and optimize the cart page. (#4868) 2026-01-21 17:18:11 +08:00
MarshallHuang
d1da9499e8 fix: update OIDC discovery to use consistent authorization endpoint (#4872) 2026-01-21 16:54:51 +08:00
Yang Luo
2e7673c015 feat: use unionid in DingTalk syncer for consistency with OAuth provider (#4870) 2026-01-21 00:07:31 +08:00
DacongDA
2d1ace427e feat: support GetVersionInfo() API in released binary (#4860) 2026-01-20 18:05:11 +08:00
IsAurora6
039c12afa3 feat: add the shopping cart page (#4855) 2026-01-19 12:12:15 +08:00
slavb18
4236160fa7 feat: add User.OriginalRefreshToken field (#4721) 2026-01-19 12:08:18 +08:00
Yang Luo
071b5ddec0 feat: fix error for "/.well-known/:application/openid-configuration" API (#4866) 2026-01-19 03:06:33 +08:00
Gucheng Wang
f46b92d225 feat: reduce i18n languages (#4862) 2026-01-18 18:28:13 +08:00
Yang Luo
cc7eb4664c feat: support comma-separated user tags in application tag validation (#4856) 2026-01-17 01:26:12 +08:00
Yang Luo
1567723e2b feat: fix null issue for GrantTypes and RedirectUris in application 2026-01-17 01:18:57 +08:00
IsAurora6
074253f45e feat: Optimize PlaceOrder-related methods and pages to support the creation of multi-item orders. (#4847) 2026-01-16 16:52:02 +08:00
Yang Luo
23c86e9018 feat: add application.EnableSamlAssertionSignature to allow disabling SAML assertion signatures (#4850) 2026-01-16 14:30:48 +08:00
DacongDA
f088827a50 feat: redirect user to last login org's login page while cookie expired (#4844) 2026-01-15 18:17:12 +08:00
IsAurora6
663815fefe feat: The frontend supports payment logic for multi-item orders. (#4843) 2026-01-15 18:16:28 +08:00
DacongDA
0d003d347e fix: improve error handling in the syncer (#4845) 2026-01-15 15:02:24 +08:00
IsAurora6
7d495ca5f2 feat: The backend supports payment logic for multi-item orders. (#4842) 2026-01-14 21:57:09 +08:00
Jiachen Ren
f89495b35c fix: use unionid instead of job_number as user name in the OAuth provider (#4841) 2026-01-14 20:02:35 +08:00
IsAurora6
4a3aefc5f5 feat: improve filter logic in order, payment, subscription get APIs (#4839) 2026-01-14 12:08:29 +08:00
Yang Luo
15646b23ff feat: support ES/ECDSA signing method in ParseStandardJwtToken() (#4837) 2026-01-14 00:47:31 +08:00
gufeiyan1215
4b663a437f feat: add RRSA (RAM roles) support for the OSS storage provider (#4831) 2026-01-13 23:01:04 +08:00
DacongDA
9fb90fbb95 feat: support user impersonation (#4817) 2026-01-13 20:47:35 +08:00
Yang Luo
65eeaef8a7 feat: fix payment currency display to use product currency instead of user balance currency (#4822) 2026-01-13 20:47:31 +08:00
IsAurora6
ecf8e2eb32 feat: add supported currency validation for payment providers (#4818) 2026-01-13 20:47:28 +08:00
soliujing
e49e678d16 feat: improve build performance, separate build dependency to allow docker cache (#4815) 2026-01-13 20:47:24 +08:00
DacongDA
623ee23285 feat: in some case, saml replay state will include special character (#4814) 2026-01-13 20:47:09 +08:00
soliujing
0901a1d5a0 feat: handle default organization in get-orders API (#4790) 2026-01-13 20:46:50 +08:00
Yang Luo
58ff2fe69c feat: include access tokens in session-level (logoutAll=false) sso-logout notifications for Single Logout (SLO) (#4804) 2026-01-13 20:46:27 +08:00
IsAurora6
737f44a059 feat: optimize authentication handling in MCP (#4801) 2026-01-09 21:27:21 +08:00
soliujing
32cef8e828 feat: add permissions for get-order and get-orders APIs (#4788) 2026-01-09 17:33:29 +08:00
Yang Luo
9e854abc77 feat: don't auto-login for single SAML provider (#4795) 2026-01-09 17:03:16 +08:00
Yang Luo
9b3343d3db feat: fix multiple webhooks don't work bug (#4798) 2026-01-08 23:41:40 +08:00
Yang Luo
5b71725c94 feat: add OIDC-compliant email_verified claim to all JWT token formats (#4797) 2026-01-08 21:12:34 +08:00
IsAurora6
59b6854ccc feat: Optimize the notifications/initialized request and authentication failure handling in MCP. (#4781) 2026-01-08 17:42:36 +08:00
Yang Luo
0daf67c52c feat: fix UTF-8 encoding error in Active Directory syncer (#4783) 2026-01-08 01:50:47 +08:00
Yang Luo
4b612269ea feat: check whether refresh token is expired after SSO logout (#4771) 2026-01-07 19:42:35 +08:00
0xkrypton
f438d39720 feat: fix Telegram OAuth login error: "failed to verify Telegram auth data: data verification failed." (#4776) 2026-01-07 19:41:43 +08:00
Eng Zer Jun
f8df200dbf feat: update github.com/shirou/gopsutil to v4 (#4773) 2026-01-07 00:51:37 +08:00
IsAurora6
cb1b3b767e feat: improve "/api/mcp" check with demo mode (#4772) 2026-01-06 14:48:24 +08:00
IsAurora6
3bec49f16c feat: enhance MCP Permissions and Response Workflow, fix bugs (#4767) 2026-01-05 22:54:12 +08:00
Yang Luo
e28344f0e7 feat: add DingTalk syncer (#4766) 2026-01-05 21:43:57 +08:00
Yang Luo
93fefed6e8 feat: add Casdoor MCP server at "/api/mcp" for application management (#4752) 2026-01-05 21:38:34 +08:00
Yang Luo
ea9abb2f29 feat: fix bugs in ticket pages 2026-01-02 23:17:30 +08:00
Yang Luo
337a8c357b feat: fix error in order APIs 2026-01-02 22:04:51 +08:00
IsAurora6
d8cebfbf04 feat: Fixed the logic for updating order and transaction statuses in payment notifications. (#4749) 2026-01-02 19:30:23 +08:00
Yang Luo
91d5039155 feat: add all API endpoints to webhook Events dropdown (#4748) 2026-01-01 22:39:18 +08:00
DacongDA
5996ee8695 feat: add ID verification to init data template and organization UI (#4744) 2026-01-01 15:16:51 +08:00
Yang Luo
8c9331932b feat: initialize default values for fields like signupItems when adding applications via SDK (#4733) 2025-12-29 20:29:02 +08:00
DacongDA
db594e2096 feat: use org name as TOTP issuer (#4731) 2025-12-29 13:49:01 +08:00
Yang Luo
b46b79ee44 feat: improve error handling of hasGravatar() 2025-12-28 22:36:47 +08:00
Yang Luo
b9dbbca716 chore: improve README 2025-12-28 19:37:51 +08:00
Yang Luo
313cf6d480 fix: add missing ID Verification category to OtherProviderInfo (#4727) 2025-12-27 18:48:11 +08:00
DacongDA
0548597d04 feat: update dependencies (aws-sdk-go, go-git, goth and go-jose) to latest (#4729) 2025-12-27 18:17:18 +08:00
DacongDA
eb8e26748f feat: replace notify with notify2 for notification provider (#4728) 2025-12-27 10:47:36 +08:00
Yang Luo
516a23ab1b feat: fix CAPTCHA modal appearing when provider Rule is set to None (#4725) 2025-12-27 09:46:33 +08:00
DacongDA
9887d80e55 feat: upgrade beego to v2 (#4720) 2025-12-26 12:46:13 +08:00
slavb18
13dd4337a6 feat: Add phone number to CustomUserInfo (#4718) 2025-12-25 09:29:58 +08:00
Yang Luo
36c69a6da1 feat: add Telegram to OAuth provider options in web UI (#4719) 2025-12-25 09:29:36 +08:00
Yang Luo
3f4a60096a feat: add 28 missing User fields to syncer UI dropdown (#4713) 2025-12-24 20:56:11 +08:00
Yang Luo
b6240fa356 feat: improve GetFilteredUsers() 2025-12-24 20:31:09 +08:00
Yang Luo
d61f06b053 feat: add WebauthnCredentials and 27 other User fields to syncer (#4705) 2025-12-24 01:52:52 +08:00
IsAurora6
6fe785b6a4 feat: fix null address causing TypeError in management UI (#4706) 2025-12-24 01:31:47 +08:00
DacongDA
cccddea67e feat: fix unauthorized error when using app API to login (#4702) 2025-12-23 20:29:46 +08:00
IsAurora6
83b8c5477a feat: fix Transaction State field type from pp.PaymentState to string (#4699) 2025-12-21 01:31:54 +08:00
IsAurora6
ac0e069f71 feat: add Adyen payment provider (#4667) 2025-12-21 01:25:17 +08:00
DacongDA
4b25e56048 feat: Make session and cookie timeout configurable per application (#4698) 2025-12-21 01:04:38 +08:00
DacongDA
39740e3d6c feat: add support to delete single session and report err while deleting current session (#4694) 2025-12-18 21:15:57 +08:00
IsAurora6
87c5bf3855 fix: fixed balance and dummy payment errors (#4692) 2025-12-14 22:52:13 +08:00
IsAurora6
c4a28acbd8 feat: fix bug in i18n applyToOtherLanguage() (#4691) 2025-12-14 19:24:01 +08:00
IsAurora6
ee26b896f6 fix: show recharge options UI in product store page (#4682) 2025-12-13 15:46:26 +08:00
Yang Luo
4a8cb9535e feat: enforce failed signin limit for LDAP login (#4686) 2025-12-13 00:30:05 +08:00
Yang Luo
387a22d5f8 feat: add ticket list/edit pages (#4651) 2025-12-12 23:16:47 +08:00
Yang Luo
36cadded1c feat: add missing grant types to OIDC discovery endpoint (#4677) 2025-12-12 23:12:13 +08:00
DacongDA
7d130392d9 feat: add session-level single sign-out with authentication and configurable scope (#4678) 2025-12-12 23:08:01 +08:00
IsAurora6
f82c90b901 feat: Optimise the order confirmation page prompts and fix the issue where the transaction.application field was incorrectly populated as organisation. (#4681) 2025-12-12 21:31:22 +08:00
Yang Luo
1a08d6514e fix: improve IsRedirectUriValid() (#4672) 2025-12-11 22:18:56 +08:00
Yang Luo
4d5bf09b36 feat: fix signup application bug in /sso-logout API 2025-12-11 22:10:24 +08:00
Yang Luo
f050deada7 feat: add GoReleaser workflow for multi-platform binary releases (#4665) 2025-12-10 12:10:23 +08:00
Yang Luo
dee94666e0 fix: disable isValidRealName() check in backend 2025-12-10 12:00:23 +08:00
Yang Luo
b84b7d787b fix: fix isSelf() identity check for users without ID field in account items of user edit page (#4669) 2025-12-10 11:40:05 +08:00
Yang Luo
d425183137 feat: update Swagger docs 2025-12-10 01:55:08 +08:00
Yang Luo
ff7fcd277c feat: fix SAML authentication failure when username attribute is unmapped (#4663) 2025-12-10 01:50:03 +08:00
Yang Luo
ed5c0b2713 feat: remove "Please sign out first" check from signup and login APIs (#4659) 2025-12-09 21:16:54 +08:00
Yang Luo
eb60e43192 feat: use bcrypt password type by default for all organizations (#4654) 2025-12-08 22:11:19 +08:00
Yang Luo
d0170532e6 fix: improve Swagger annotations for session and token APIs (#4652) 2025-12-08 22:04:53 +08:00
Yang Luo
7ddb87cdf8 fix: Fix JWT-Custom token format: always include nonce/scope, add signinMethod and provider to dropdown (#4649) 2025-12-08 17:55:31 +08:00
Yang Luo
fac45f5ac7 feat: add Alibaba Cloud ID verification provider (#4645) 2025-12-08 17:48:52 +08:00
Yang Luo
266d361244 feat: fix "only the last session is displayed" bug by respecting application.EnableExclusiveSignin when adding sessions (#4643) 2025-12-08 17:14:11 +08:00
DacongDA
b454ab1931 feat: fix generated link has no org info bug while using shared application (#4647) 2025-12-08 16:35:17 +08:00
Yang Luo
ff39b6f186 feat: add Jumio ID Verification provider (#4641) 2025-12-08 00:39:34 +08:00
DacongDA
0597dbbe20 feat: always return array if item contains roles, groups or permissions in JWT (#4640) 2025-12-08 00:11:39 +08:00
Yang Luo
49c417c70e fix: add excel import support for groups, permissions, and roles (#4585) 2025-12-07 22:24:12 +08:00
IsAurora6
8b30e12915 feat: improve inventory logic: check stock before order and update stock/sales after payment. (#4633) 2025-12-07 19:38:41 +08:00
Jacob
2e18c65429 feat: add Application.DisableSamlAttributes field and fix C14N namespace issue (#4634) 2025-12-06 21:45:02 +08:00
IsAurora6
27c98bb056 feat: improve payment flow with order navigation and remove returnUrl field (#4632) 2025-12-06 17:57:59 +08:00
DacongDA
4400b66862 feat: fix silentSignin not working bug (#4629) 2025-12-06 11:10:10 +08:00
IsAurora6
e7e7d18ee7 fix: add permission control and view mode for product/order/payment/plan/pricing/subscription pages. (#4628) 2025-12-04 23:08:41 +08:00
IsAurora6
66d1e28300 feat: Add payment column to order list and refine product store card layout. (#4625) 2025-12-04 18:18:10 +08:00
IsAurora6
53782a6706 feat: support recharge products with preset amounts and disable custom amount option. (#4619) 2025-12-03 13:50:33 +08:00
Yang Luo
30bb0ce92f feat: fix signupItem.regex validation not working in signup page frontend (#4614) 2025-12-03 08:56:45 +08:00
Yang Luo
29f7dda858 feat: fix 403 error on /api/acs endpoint for SAML IdP responses (#4620) 2025-12-02 21:19:00 +08:00
Yang Luo
68b82ed524 fix: accept all file types in resources list page's upload button 2025-11-30 20:42:54 +08:00
Yang Luo
c4ce88198f feat: improve password popover positioning on signup page 2025-11-30 18:10:19 +08:00
Yang Luo
a11fa23add fix: fix i18n for "Please input your {field}!" validation message in signup page (#4610) 2025-11-30 17:47:25 +08:00
Yang Luo
add6ba32db fix: improve application edit page's Providers dropdown with search, icons, and display names (#4608) 2025-11-30 17:13:06 +08:00
Yang Luo
37379dee13 fix: fix get-groups API call in ApplicationEditPage to use correct owner parameter (#4606) 2025-11-30 16:23:28 +08:00
Yang Luo
2066670b76 feat: add Lemon Squeezy payment provider (#4604) 2025-11-30 13:40:48 +08:00
Yang Luo
e751148be2 feat: add FastSpring payment provider (#4601) 2025-11-30 12:02:18 +08:00
Yang Luo
c541d0bcdd feat: add Paddle payment provider (#4598) 2025-11-30 11:31:16 +08:00
Yang Luo
f0db95d006 feat: add Polar payment provider (#4595) 2025-11-30 10:45:11 +08:00
IsAurora6
e4db367eaa feat: Remove BuyProduct endpoint and legacy purchase logic. (#4591) 2025-11-28 23:51:22 +08:00
IsAurora6
9df81e3ffc feat: feat: add OrderPayPage.js, fix subscription redirect & refine list time format. (#4586) 2025-11-27 20:49:49 +08:00
IsAurora6
048d6acc83 feat: Implement the complete process of product purchase, order placement, and payment. (#4588) 2025-11-27 20:49:34 +08:00
Yang Luo
e440199977 feat: regenerate the Swagger docs 2025-11-25 22:24:32 +08:00
IsAurora6
cb4e559d51 feat: Added PlaceOrder, CancelOrder, and PayOrder methods, and added corresponding buttons to the frontend. (#4583) 2025-11-25 22:22:46 +08:00
zjumathcode
4d1d0b95d6 feat: drop legacy // +build comment (#4582) 2025-11-25 20:21:09 +08:00
Yang Luo
9cc1133a96 feat: upgrade gomail to v2.2.0 2025-11-25 01:03:45 +08:00
Yang Luo
897c28e8ad fix: fix SQL query in Keycloak syncer (#4578) 2025-11-24 23:40:30 +08:00
Yang Luo
9d37a7e38e fix: fix memory leaks in database syncer from unclosed connections (#4574) 2025-11-24 23:38:50 +08:00
Yang Luo
ea597296b4 fix: allow normal users to view their own transactions (#4572) 2025-11-24 01:47:10 +08:00
Yang Luo
427ddd215e feat: add Telegram OAuth provider (#4570) 2025-11-24 01:04:36 +08:00
Yang Luo
24de79b100 Improve getTransactionTableColumns UI 2025-11-23 22:07:33 +08:00
DacongDA
9ab9c7c8e0 fix: show error better for user upload (#4568) 2025-11-23 21:52:44 +08:00
Yang Luo
0728a9716b feat: deduplicate code between TransactionTable and TransactionListPage (#4567) 2025-11-23 21:47:58 +08:00
Yang Luo
471570f24a Improve AddTransaction API return value 2025-11-23 21:02:06 +08:00
Yang Luo
2fa520844b fix: fix product store page to pass owner parameter to API (#4565) 2025-11-23 20:48:15 +08:00
Yang Luo
2306acb416 fix: improve balanceCredit for org and user 2025-11-23 19:51:39 +08:00
Yang Luo
d3f3f76290 fix: add dry run mode to add-transaction API (#4563) 2025-11-23 17:36:51 +08:00
DacongDA
fe93128495 feat: improve user upload UX (#4542) 2025-11-23 16:05:46 +08:00
seth-shi
7fd890ff14 fix: ticket error handling in HandleOfficialAccountEvent() (#4557) 2025-11-23 14:58:23 +08:00
Yang Luo
83b56d7ceb feat: add product store page (#4544) 2025-11-23 14:54:35 +08:00
Yang Luo
503e5a75d2 feat: add User.OriginalToken field to expose OAuth provider access tokens (#4559) 2025-11-23 14:54:02 +08:00
seth-shi
5a607b4991 fix: close file handle in GetUploadXlsxPath to prevent resource leak (#4558) 2025-11-23 14:37:06 +08:00
Yang Luo
ca2dc2825d feat: add SSO logout notifications to user's signup application (#4547) 2025-11-23 00:47:29 +08:00
Yang Luo
446d0b9047 Improve TransactionTable UI 2025-11-23 00:45:47 +08:00
Yang Luo
ee708dbf48 feat: add Organization.OrgBalanceCredit and User.BalanceCredit fields for credit limit enforcement (#4552) 2025-11-23 00:37:44 +08:00
Yang Luo
221ca28488 fix: flatten top navbar to single level when ≤7 items (#4550) 2025-11-23 00:34:17 +08:00
Yang Luo
e93d3f6c13 Improve transaction list page UI 2025-11-22 23:35:04 +08:00
Yang Luo
e285396d4e fix: fix recharge transaction default values (#4546) 2025-11-22 23:27:29 +08:00
Yang Luo
10320bb49f Improve TransactionTable UI 2025-11-22 21:39:56 +08:00
seth-shi
4d27ebd82a feat: Use email as username when organization setting is enabled during login (#4539) 2025-11-22 20:58:27 +08:00
Yang Luo
6d5e6dab0a Fix account table missing item 2025-11-22 20:56:45 +08:00
Yang Luo
e600ea7efd feat: add i18n support for table column widgets (#4541) 2025-11-22 16:39:44 +08:00
Yang Luo
8002613398 feat: Add exchange rate conversion for balance calculations (#4534) 2025-11-21 22:13:26 +08:00
IsAurora6
a48b1d0c73 feat: Add recharge functionality with editable fields to transaction list page. (#4536) 2025-11-21 22:11:38 +08:00
Yang Luo
d8b5ecba36 feat: add transaction's subtype field and fix product recharge (#4531) 2025-11-21 19:27:07 +08:00
IsAurora6
e3a8a464d5 feat: Add balanceCurrency field to Organization and User models. (#4525) 2025-11-21 14:42:54 +08:00
IsAurora6
a575ba02d6 feat: Fixed a bug in addTransaction and optimized the transactionEdit page. (#4523) 2025-11-21 09:35:12 +08:00
IsAurora6
a9fcfceb8f feat: Add currency icons wherever currency appears, and optimize the display columns in the transaction table. (#4516) 2025-11-20 22:33:00 +08:00
ledigang
712482ffb9 refactor: omit unnecessary reassignment (#4509) 2025-11-20 18:47:03 +08:00
Yang Luo
84e2c760d9 feat: lazy-load Face ID models only when modal opens (#4508) 2025-11-20 18:46:31 +08:00
IsAurora6
4ab85d6781 feat: Distinguish and allow users to configure adminNavItems and userNavItems. (#4503) 2025-11-20 11:05:30 +08:00
Yang Luo
2ede56ac46 fix: refactor out Setting.CurrencyOptions (#4502) 2025-11-19 21:51:28 +08:00
Yang Luo
6a819a9a20 feat: persist hash column when updating users (#4500) 2025-11-19 21:50:32 +08:00
IsAurora6
ddaeac46e8 fix: optimize UpdateUserBalance and fix precision loss for orgBalance/userBalance. (#4499) 2025-11-19 21:13:32 +08:00
IsAurora6
f9d061d905 feat: return transaction IDs in API and disable links for anonymous user in transaction list (#4498) 2025-11-19 17:40:30 +08:00
Yang Luo
5e550e4364 feat: fix bug in createTable() 2025-11-19 17:33:51 +08:00
Yang Luo
146d54d6f6 feat: add Order pages (#4492) 2025-11-19 14:05:52 +08:00
IsAurora6
1df15a2706 fix: Transaction category & type links not navigating. (#4496) 2025-11-19 11:41:36 +08:00
Yang Luo
f7d73bbfdd Improve transaction fields 2025-11-19 09:14:49 +08:00
Yang Luo
a8b7217348 fix: add needSshfields() 2025-11-19 08:37:13 +08:00
Yang Luo
40a3b19cee feat: add Active Directory syncer support (#4495) 2025-11-19 08:30:01 +08:00
Yang Luo
98b45399a7 feat: add Google Workspace syncer (#4494) 2025-11-19 07:37:11 +08:00
Yang Luo
90edb7ab6b feat: refactor syncers into interface (#4490) 2025-11-19 01:28:37 +08:00
marun
e21b995eca feat: update payment providers when organization changes in PlanEditPage (#4462) 2025-11-19 00:14:01 +08:00
Yang Luo
81221f07f0 fix: improve isAllowedInDemoMode() for add-transaction API 2025-11-18 23:55:43 +08:00
Yang Luo
5fc2cdf637 feat: fix bug in GetEnforcer() API 2025-11-18 23:31:53 +08:00
Yang Luo
5e852e0121 feat: improve user edit page UI 2025-11-18 23:31:17 +08:00
Yang Luo
513ac6ffe9 fix: improve user edit page's transaction table UI 2025-11-18 23:31:16 +08:00
Yang Luo
821ba5673d Improve "Generate" button i18n 2025-11-18 23:31:16 +08:00
IsAurora6
d3ee73e48c feat: Add a URL field to the Transaction structure and optimize the display of the Transaction List. (#4487) 2025-11-18 21:45:57 +08:00
Yang Luo
1d719e3759 feat: fix OAuth-registered users to keep empty passwords unhashed (#4482) 2025-11-17 23:12:53 +08:00
Yang Luo
b3355a9fa6 fix: fix undefined owner in syncer edit page getCerts API call (#4471) 2025-11-17 22:51:12 +08:00
Yang Luo
ccc88cdafb feat: populate updated_time for all user creation paths (#4472) 2025-11-17 22:07:47 +08:00
Yang Luo
abf328bbe5 feat: allow setting email_verified in UpdateUser() API 2025-11-17 22:04:33 +08:00
DacongDA
5530253d38 feat: use correct org owner for UpdateOrganizationBalance (#4478) 2025-11-17 18:17:02 +08:00
Yang Luo
4cef6c5f3f feat: fix duplicate key error when re-importing users from different organization (#4473) 2025-11-17 02:13:35 +08:00
aozima
7e6929b900 feat: LDAP server adds more attributes: mail, mobile, sn, giveName (#4468) 2025-11-16 19:13:12 +08:00
aozima
46ae1a9580 fix: improve error handling for DingTalkIdProvider.GetUserInfo() (#4469) 2025-11-16 17:42:55 +08:00
Yang Luo
37e22f3e2c feat: support user custom password salt when organization salt is empty (#4465) 2025-11-15 02:35:15 +08:00
Yang Luo
68cde65d84 feat: fix bug about adding new permission in setEnforcerModel() 2025-11-12 20:39:44 +08:00
Yang Luo
1c7f5fdfe4 fix: fix transaction API to enforce user-level access control (#4447) 2025-11-12 20:31:14 +08:00
Yang Luo
1a5be46325 feat: add i18n support for password complexity error messages (#4458) 2025-11-12 19:40:21 +08:00
Yang Luo
f7bafb28d6 feat: support application's ExpireInHours and RefreshExpireInHours in float64 (#4442) 2025-11-12 17:01:56 +08:00
Yang Luo
6f815aefdf feat: update gopay to v1.5.115 to fix the payment URL (#4449) 2025-11-12 16:40:37 +08:00
DacongDA
eb49f29529 feat: fix e2e test backend start to fail caused by wrong GetModel param (#4454) 2025-11-12 15:44:20 +08:00
Yang Luo
5ad4e6aac0 feat: upgrade to Go 1.23 2025-11-11 22:43:38 +08:00
DacongDA
3c28a2202d feat: fix bug about "Failed to subscribe for new paid users" (#4450) 2025-11-11 22:37:14 +08:00
Yang Luo
0a9a9117e5 feat: allow org admins to access verification list and store organization in Owner field (#4441) 2025-11-11 01:12:16 +08:00
Yang Luo
f3ee1f83fe feat: fix bug about Permission.Model 2025-11-11 00:22:18 +08:00
Yang Luo
171af2901c feat: fix SAML signature verification failure with C14N10 canonicalization (#4439) 2025-11-10 20:50:57 +08:00
Yang Luo
2ded293e10 feat: fix namespace declaration issue in SAML C14N10 schema 2025-11-10 13:53:42 +08:00
Yang Luo
a1c6d6c6cf feat: fix bug in permission's model and adapter fields 2025-11-09 23:51:14 +08:00
Yang Luo
bf42176708 fix: add .editorconfig to web folder 2025-11-09 23:40:30 +08:00
Yang Luo
23a45c1d33 fix: remove wrong comments in lark.go 2025-11-07 23:02:48 +08:00
Yang Luo
6894ca407e fix: fix SAML assertion signing: add xmlns:xsi and xmlns:xs to assertion element (#4417) 2025-11-07 22:46:47 +08:00
Yang Luo
d288ecf6ed feat: support for WeChat Mobile (in-app browser) OAuth login (#4420) 2025-11-07 22:43:53 +08:00
Yang Luo
0a04174ec8 feat: add guest user authentication with automatic upgrade flow (#4421) 2025-11-07 22:05:22 +08:00
Yang Luo
3feb723abf feat: fix Lark OAuth login failure when user_id is empty (#4418) 2025-11-07 20:01:26 +08:00
Yang Luo
ff8b8fb631 feat: fix SAML Response schema validation by declaring xmlns:xs and xmlns:xsi at root (#4415) 2025-11-07 12:55:09 +08:00
Yang Luo
df38c0dd62 feat: fix null pointer panic in controllers package 2025-11-06 21:28:51 +08:00
Yang Luo
93e87e009e feat: add password obfuscation support to set-password API (#4410) 2025-11-06 20:06:11 +08:00
Copilot
f0a4ccbc3c feat: add CLI "export" arg to support exporting data to file (#4408) 2025-11-04 22:54:27 +08:00
Copilot
f17c8622f7 feat: fix authz filter's "Unauthorized operation" bug in /api/sso-logout API (#4404) 2025-11-04 20:23:58 +08:00
Copilot
09698b0714 feat: rename /api/logout-all to /api/sso-logout (#4401) 2025-11-04 14:43:43 +08:00
Copilot
1d913677a0 fix: add Transactions to account items of org edit page (#4399) 2025-11-04 14:19:24 +08:00
DacongDA
f3b00fb431 fix: support SSO logout: logout from all applications (#4390) 2025-11-04 14:14:33 +08:00
Copilot
c95a427635 feat: remove unused get-user-transactions API, use get-transactions API instead in user account page (#4395) 2025-11-04 12:22:57 +08:00
Copilot
778be62bae fix: add missing WeCom notification provider to dropdown (#4394) 2025-11-04 10:57:28 +08:00
hamidreza abedi
5574c6ad0d fix: refresh captcha on send code, prevent refreshing on signin (#4376) 2025-11-04 10:37:07 +08:00
Copilot
36db852a32 feat: fix JWT-Custom format including unselected fields with empty values (#4392) 2025-11-04 10:35:19 +08:00
Copilot
8ee8767882 feat: replace GetOwnerAndNameFromId with GetOwnerAndNameFromIdWithError everywhere (#4383) 2025-11-03 11:38:54 +08:00
Mohammed Tayeh
af5a9c805d feat: normalize email to lowercase to prevent duplicate accounts (#4380) 2025-11-02 21:39:18 +08:00
Copilot
f8e5fedf8b feat: add balance for user and org transactions (#4368) 2025-11-01 14:26:39 +08:00
Copilot
962a4970f4 feat: consolidate i18n "Failed to get" strings and wrap hardcoded error messages (#4374) 2025-11-01 10:51:10 +08:00
Copilot
d239b3f0cb fix: add flag icons to currency fields in product pages (#4370) 2025-11-01 08:57:51 +08:00
Copilot
0df467ce5e feat: add WeCom notification provider (#4367) 2025-11-01 01:11:51 +08:00
Copilot
3d5356a1f0 feat: add push notification as MFA method (#4364) 2025-11-01 00:19:18 +08:00
DacongDA
1824762e00 feat: fix missing dest parameter for signup with invitation code (#4363) 2025-10-31 20:46:37 +08:00
DacongDA
a533212d8a feat: fix bug that captcha will show twice if using inline captcha (#4358) 2025-10-30 23:13:59 +08:00
Copilot
53e1813dc8 feat: fix OTP countdown timer UI to respect application's codeResendTimeout config (#4357) 2025-10-30 22:16:55 +08:00
Copilot
ba95c7ffb0 feat: add cleanOldMEIFolders() for casbin-python-cli (#4353) 2025-10-30 17:44:48 +08:00
Copilot
10105de418 fix: add missing i18n wrappers to backend error messages and translate all strings (#4349) 2025-10-29 23:59:19 +08:00
anhuv
9582163bdd feat: upgrade some Go dependencies (#4350) 2025-10-29 23:53:01 +08:00
Copilot
cc7408e976 feat: improve Prometheus metric API handlers (#4346) 2025-10-29 20:46:52 +08:00
Copilot
d67d714105 feat: fix Custom HTTP Email provider: correct From address field binding and add missing To address field (#4341) 2025-10-29 11:10:28 +08:00
Copilot
0aab27f154 feat: add Azure AD syncer (#4335) 2025-10-28 00:55:52 +08:00
Copilot
212090325b feat: add WeCom syncer (#4329) 2025-10-27 23:30:57 +08:00
DacongDA
b24e43c736 feat: Add RADIUS MFA support for external authentication servers (#4333) 2025-10-27 22:51:26 +08:00
Copilot
1728bf01ac feat: translate untranslated backend i18n strings (#4322) 2025-10-27 10:29:43 +08:00
Attack825
86a7a87c57 feat: translate all untranslated i18n strings (#4313) 2025-10-27 09:30:50 +08:00
Copilot
61c8e08eb0 feat: fix duplicate CI workflow runs on pull requests (#4319) 2025-10-27 01:01:03 +08:00
Copilot
caccd75edb feat: add EnableProxy field for Email and SMS providers (#4317) 2025-10-26 21:37:54 +08:00
Copilot
7b2666d23e feat: add in-memory cache for run-casbin-command API (#4314) 2025-10-25 23:46:02 +08:00
Copilot
b7b6d2377a feat: add username matching in Login() API for automatic Wecom OAuth login association (#4308) 2025-10-25 01:50:24 +08:00
Copilot
d43ee2d48f feat: enable post-registration subscription upgrades for all user types, not only paid users (#4309) 2025-10-25 01:48:23 +08:00
Copilot
242c75d9dc feat: add CodeResendTimeout to Application edit page (#4264) 2025-10-25 01:13:17 +08:00
Copilot
6571ad88a2 feat: prevent re-registration via third-party login for soft-deleted users (#4306) 2025-10-25 01:09:08 +08:00
DacongDA
bb33c8ea31 feat: add support for exclusive login (#4301) 2025-10-23 22:00:09 +08:00
Copilot
48f5531332 feat: apply Casbin rules to users signing up via external providers with signup groups (#4253) 2025-10-22 14:53:57 +08:00
Copilot
3e5114e42d feat: can map claims from external Identity Providers (Okta, Azure AD, etc.) to additional user properties (#4296) 2025-10-22 01:45:34 +08:00
Yang Luo
03082db9f2 fix: update all i18n data 2025-10-22 00:35:16 +08:00
Attack825
a2363e55e7 feat: add missing "eft" in GetBuiltInModel()'s Casbin model (#4277) 2025-10-22 00:05:29 +08:00
Copilot
dde4e41e24 feat: add application-specific OIDC discovery endpoints (#4294) 2025-10-21 23:40:23 +08:00
Copilot
c3eea4d895 feat: enable applications to define custom title and favicon (#4291) 2025-10-21 01:27:53 +08:00
Copilot
4ff28cacbe feat: fix /api/logout API to support POST requests with form parameters (#4282) 2025-10-20 14:16:14 +08:00
Copilot
e8ed9ca9e3 feat: add support for custom HTTP headers, body mapping, and content types in Custom HTTP SMS provider (#4270) 2025-10-20 14:07:48 +08:00
Copilot
8f8b7e5215 feat: support "new-user" webhooks for LDAP and syncer (#4285) 2025-10-19 22:38:41 +08:00
Copilot
099e6437a9 feat: fix nil pointer dereference in Login handler when provider is nil (#4278) 2025-10-18 00:13:12 +08:00
DacongDA
fdbb0d52da feat: fix QRCode param error in payUrl and successUrl (#4276) 2025-10-17 23:18:02 +08:00
Copilot
9c89705a19 feat: fix SAML audience duplication and empty values in response generation (#4268) 2025-10-15 19:25:49 +08:00
DacongDA
18451a874e feat: add 9 more custom fields for custom oauth (#4265) 2025-10-14 22:26:41 +08:00
Copilot
99dae68c53 feat: add LDAP country attribute mapping to user region field (#4257) 2025-10-14 22:11:02 +08:00
Copilot
7e2c2bfc64 feat: Add RegisterType and RegisterSource fields to User struct (#4252) 2025-10-14 20:56:38 +08:00
Copilot
4ae6675198 feat: fix SAML assertion signing failure with C14N10 exclusive canonicalization (#4260) 2025-10-14 18:48:29 +08:00
Copilot
8c37533b92 feat: support SAML assertion signing at all times (#4237) 2025-10-14 00:25:26 +08:00
DacongDA
3e77bd30a0 feat: support "Casdoor API" resource type in permission edit page (#4251) 2025-10-13 23:51:14 +08:00
Copilot
55257d6190 feat: support user.Id parameter in /update-user API (#4249) 2025-10-13 23:10:17 +08:00
Attack825
b9046bec01 feat: support Form.Tag and remove unique formType checks (#4002) 2025-10-09 22:15:08 +08:00
Kevin D'souza
40d4e3a1a9 feat: accept if the SAML certificate is of type PEM as well (#4232) 2025-10-08 22:57:53 +08:00
Attack825
60bfc8891a fix: fix label's i18n in form edit page (#4226) 2025-10-05 23:18:52 +08:00
Attack825
126879533b feat: add Form.Label and change form.Width to string (#4225) 2025-10-05 21:03:36 +08:00
DacongDA
469b6036fd feat: fix JSON parse error with ObjectWithOrg in authz_filter.go's getObject() (#4224) 2025-10-04 23:36:15 +08:00
DacongDA
6c750867b0 feat: support different SAML hash algorithms: "SHA1", "SHA256", "SHA512" for SAML signature in application edit page (#4221) 2025-10-02 11:58:34 +08:00
Austin Riendeau
625b3e2c63 feat: fix missing subject in Sendgrid Email provider (#4220) 2025-10-02 11:45:31 +08:00
DacongDA
28dff8083a feat: fix bug that notify-payment webhook was not triggered (#4219) 2025-10-02 11:44:01 +08:00
Yang Luo
02c4bddb5f feat: improve user-upload button 2025-09-30 14:01:12 +08:00
Enze Wu
df65fb3525 feat: skip old password verification for OAuth users without a password (#4211) 2025-09-29 17:43:45 +08:00
DacongDA
d3bbf954f8 feat: fix issue that couldn't auto set invitatonCode when using oAuth signup link (#4212) 2025-09-29 17:19:58 +08:00
Attack825
f3755d925c feat: improve form edit page UI and add preview (#4210) 2025-09-27 16:26:12 +08:00
Attack825
ca819e7e83 feat: add form to customize columns (#4202) 2025-09-25 22:04:43 +08:00
M3ti
d619e91d9e feat: add support for custom attribute mapping to user properties in LDAP (#4201) 2025-09-23 00:57:12 +08:00
Robin Ye
5079c37818 feat: improve compatibility for MinIO storage provider (#4196) 2025-09-21 16:02:19 +08:00
DacongDA
d5f29d716a feat: change User.Avatar's DB type to text (#4199) 2025-09-20 21:32:51 +08:00
DacongDA
00b278a00f feat: check roles in CheckLoginPermission (#4198) 2025-09-20 19:50:36 +08:00
DacongDA
d883db907b feat: improve authz_filter (#4195) 2025-09-18 23:46:00 +08:00
Attack825
8e7efe5c23 feat: add code verification label in signin items (#4187) 2025-09-18 10:41:47 +08:00
DacongDA
bf75508d95 feat: add token attribute table to provide a more flexible Jwt-custom token in application edit page (#4191) 2025-09-17 21:57:17 +08:00
Mirko Rapisarda
986b94cc90 feat: improve domain field text in provider edit page (#4181) 2025-09-16 20:57:40 +08:00
Attack825
890f528556 feat: separate getLocalPrimaryKey() and getTargetTablePrimaryKey() in DB syncer (#4180) 2025-09-15 17:45:18 +08:00
Robin Ye
b46e779235 feat: persist custom signin item label in signin items table (#4179) 2025-09-15 17:43:20 +08:00
Attack825
5c80948a06 feat: add tag filtering in app list page (#4163) 2025-09-14 15:32:13 +08:00
DacongDA
1467199159 feat: add webhook for buy-product and add resp data (#4177) 2025-09-12 23:53:59 +08:00
DacongDA
64c2b8f0c2 feat: fix issue that init will add duplicate policy and not add permission policies to adapter (#4175) 2025-09-11 21:21:07 +08:00
DacongDA
8f7ea7f0a0 feat: fix Data Missing From casbin_rule Table After Importing init_data.json (#4167) 2025-09-09 21:20:25 +08:00
DacongDA
2ab85c0c44 feat: fix bug that send code type will be "phone" when logged-in via autofill (#4164) 2025-09-08 18:13:52 +08:00
Dev Hjz
bf67be2af6 feat: add username and loginHint to redirect URL in HandleSamlRedirect of SAML IdP (#4162) 2025-09-07 14:18:35 +08:00
DacongDA
bc94735a8d feat: add the username parameter in SAML or OAuth2 (#4161) 2025-09-06 22:03:18 +08:00
DacongDA
89c6ef5aae feat: support "permissionNames" field in JWT-Custom token (#4154) 2025-09-06 00:05:47 +08:00
anhuv
21da9f5ff2 feat: remove port from client IP in getIpInfo() (#4145) 2025-09-04 08:10:42 +08:00
karatekaneen
3b11e778e7 feat(i18n): Update faulty Swedish translations (#4149) 2025-09-03 20:45:57 +08:00
Attack825
ad240a373f feat: fix non-standard CAS bug (#4146) 2025-09-03 20:20:08 +08:00
amaankm
01000f7022 feat: update parameter descriptions in Session API (#4140) 2025-09-02 16:31:06 +08:00
Cleidson Oliveira
f93aeb5350 feat: improve pt i18n strings (#4143) 2025-09-02 15:53:51 +08:00
gongzhongqiang
8fa681f883 feat: add password change validation to ensure new password differs from current password (#4134) 2025-09-01 17:22:06 +08:00
DacongDA
3b16406442 feat: add signinMethod in JWT token (#4136) 2025-08-31 18:01:05 +08:00
Attack825
fbc16ef124 feat: change builtInMaxFields to 6 in Casbin policy length (#4130) 2025-08-29 22:39:39 +08:00
DacongDA
f26f56e88b feat: support auto signup with SAML (#4129) 2025-08-29 11:51:52 +08:00
DacongDA
9cb633c9e2 feat: use a more popular format for nameid to ensure compatibility in NewSamlResponse() (#4123) 2025-08-27 22:33:14 +08:00
DacongDA
d0d059d42f feat: fix Email and SMS check failures when enabling or verifying MFA (#4122) 2025-08-27 21:11:53 +08:00
biankasyo
c184dc7f3a feat(lark): support enterprise_email field as email fallback (#4128) 2025-08-27 20:55:32 +08:00
DacongDA
2fa0890c11 feat: fix bug that custom JWT token no longer includes properties (#4124) 2025-08-27 20:41:27 +08:00
DacongDA
a0e2be7ba8 feat: support inserting user's field to SAML attribute (#4105) 2025-08-22 11:27:21 +08:00
IsAurora6
09b389b1f7 feat: add a loading animation in DashboardPage (#4117) 2025-08-22 00:11:08 +08:00
DacongDA
a23033758f feat: Add "Send Invitation Email" action to User Invitation flow (#4113) 2025-08-21 18:53:43 +08:00
Attack825
f7bc822087 feat: refresh inline captcha on login failure (#4108) 2025-08-21 10:29:56 +08:00
kevin kwok
e533ff1ee1 feat: add support for casbin-dotnet-cli auto-download (#4110) 2025-08-20 18:38:00 +08:00
Attack825
9f187f690e feat: add copy button in ApplicationListPage (#4097) 2025-08-19 16:18:28 +08:00
Jerry
fe5aa1f214 feat: Add Phantom web3 onboard wallet support (#4100) 2025-08-19 13:31:35 +08:00
DacongDA
eda742a848 feat: support e164 phone number in GetUserByPhone() (#4099) 2025-08-19 02:19:15 +08:00
Attack825
83df077a02 feat: add Application.Order for sorting in Apps page (#4085) 2025-08-18 08:34:32 +08:00
DacongDA
ad6080e763 feat: fix issue that signing up via provider in shared application will sign up to built-in app (#4093) 2025-08-17 22:32:47 +08:00
DacongDA
c179324de4 feat: fix bug that SelfLoginButton will re-render when username field updates (#4091) 2025-08-17 19:50:34 +08:00
DacongDA
645716e485 feat: add country code to validate phone number when Code method's rule is Phone only (#4089) 2025-08-17 16:56:25 +08:00
IsAurora6
955e73ddd1 feat: fix the asynchronous issue in handleOrganizationChange in BaseListPage (#4090) 2025-08-17 14:59:49 +08:00
Robin Ye
2493ae9cfe feat: fix issue that a user can belong to two physical groups at the same time (#4084) 2025-08-15 23:42:09 +08:00
Attack825
b5c80513fb feat: change username too when "username as email" switch is enabled in ResetEmailOrPhone API (#4081) 2025-08-14 21:03:45 +08:00
Attack825
0653353be1 feat: update social_osonsms.svg URL (#4082) 2025-08-14 20:35:39 +08:00
Robin Ye
d6778fb4e6 feat: improve inline captcha UI by increasing spacing (#4079) 2025-08-14 16:15:34 +08:00
DacongDA
fee7773839 feat: add First name and Last name to account items (#4077) 2025-08-14 08:41:18 +08:00
Robin Ye
d47ac6b957 feat: add support for Azerbaijani language (az) (#4073) 2025-08-14 00:13:01 +08:00
Robin Ye
857824df19 feat: sync i18n texts (#4075) 2025-08-13 23:10:58 +08:00
Attack825
1e98d1e11b feat: fix MinIO provider logo URL (#4076) 2025-08-13 22:20:50 +08:00
Yang Luo
48ba88de2d feat: improve error handling in AutoSigninFilter 2025-08-13 15:27:52 +08:00
Yang Luo
a3a142db39 feat: fix error message in VerificationForm.CheckParameter() 2025-08-12 10:13:00 +08:00
hamidreza abedi
3bb7cc6b81 feat: increase LDAP's "basedn" field to 500 chars (#4062) 2025-08-11 16:46:15 +08:00
Robin Ye
1fb3249bfd fix: improve "Copy signup page URL" button UI in invitation edit page (#4038) 2025-08-10 23:03:13 +08:00
DacongDA
ff8f61a84c feat: fix missing search params bug in switchLoginOrganization() (#4058) 2025-08-10 22:11:06 +08:00
DacongDA
a118879dc0 feat: allow user to select organization in login page when using shared app (#4053) 2025-08-10 20:40:30 +08:00
DacongDA
386b673446 feat: support scanning code to login in the login page (#4052) 2025-08-10 00:09:43 +08:00
DacongDA
6abd46fe81 feat: fix issue that signing up with shared application will create user in wrong org (#4051) 2025-08-09 22:25:01 +08:00
IsAurora6
49d734d249 feat: standardize Resource APIs by handling path prefix internally and returning clean paths (#4047) 2025-08-08 23:31:22 +08:00
iderr
f5b4cd7fab feat: Fix GetFilteredPoliciesMulti when filtering only by ptype (#4039) 2025-08-05 22:51:40 +08:00
iderr
76f322861a feat: Refactor GetFilteredPolicies to support multiple filters via POST (#4037) 2025-08-04 19:51:25 +08:00
Seele.Clover
124c28f1e1 feat: allow Custom OAuth provider to not fill in email and avatarUrl in configuring user_mapping (#4035) 2025-08-04 12:26:12 +08:00
DacongDA
e0d9cc7ed1 feat: improve error handling on signInWithWebAuthn (#4033) 2025-08-03 01:26:18 +08:00
Seele.Clover
75c1ae4366 feat: support nested fields for configuring user_mapping in the Custom OAuth provider (#4032) 2025-08-03 00:33:52 +08:00
DacongDA
d537377b31 feat: show placeholder QR code with loading instead of "Loading" text in QR code login page (#4031) 2025-08-02 15:58:49 +08:00
raiki02
462ecce43b feat: check args in Enforce and BatchEnforce APIs (#4029) 2025-08-02 13:39:05 +08:00
raiki02
a84664b55d feat: remove toLower conversion in getPolicies() (#4030) 2025-08-02 13:38:49 +08:00
Justin Judd
941c56e69e feat(jwt): Enable using User Properties as custom claims (#3571) 2025-08-02 10:34:11 +08:00
DacongDA
a28b871a46 feat: add useGroupPathInToken boolean field in app.conf (#4026) 2025-08-02 01:40:26 +08:00
Robin Ye
387f5d58f7 feat: prevent two captcha providers are added to one single application (#4025) 2025-08-01 22:50:12 +08:00
Xiao Mao
7d846b2060 feat: implement root DSE handling and schema query in LDAP server (#4020) 2025-07-31 01:23:25 +08:00
raiki02
c1c2dcab38 feat: can disable signin within application and organization (#4012) 2025-07-30 21:07:35 +08:00
Robin Ye
f9264f700b feat: add get-filtered-policies API, improve Swagger docs (#4006) 2025-07-29 23:51:01 +08:00
Xiao Mao
f3af2a26aa feat: add posixAccount and posixGroup filter logic for more versatile usage in LDAP (#4014) 2025-07-29 21:49:39 +08:00
DacongDA
0ac69bde53 feat: fix objectClass filter will return empty response (#4011) 2025-07-28 23:39:04 +08:00
Yang Luo
70c99f0e59 feat: fix "Key text" multi-line input box for Apple OAuth provider 2025-07-28 17:49:36 +08:00
kevin kwok
8d1fdc3a08 feat: add support for casbin-python-cli auto-download (#4004) 2025-07-27 14:00:00 +08:00
DacongDA
30c15b8135 feat: fix the error effect of form post response type (#4003) 2025-07-26 23:26:37 +08:00
Kevin D'souza
2d6de216b8 feat: move to a more robust way of checking if element in slice (#4001) 2025-07-26 11:57:45 +08:00
IsAurora6
ac39722687 feat: fix issue that resource provider.PathPrefix is not used in GetDirectResources() API (#4000) 2025-07-25 22:06:08 +08:00
Attack825
26a9ec8ee6 feat: translate all i18n strings (#3992) 2025-07-25 21:22:25 +08:00
DacongDA
fea6317430 feat: add back support for non-discoverable credential WebAuthn login and display WebAuthn ID again (#3998) 2025-07-25 18:34:37 +08:00
DacongDA
5f702ca418 feat: make enableErrorMask work for corner cases by moving checks from controller to Translate() (#3996) 2025-07-25 00:39:01 +08:00
Robin Ye
0495d17a07 feat: support OAuth 2.0 form_post response mode (#3973) 2025-07-24 15:17:45 +08:00
Yang Luo
c6a2d59aa4 feat: update i18n strings 2025-07-24 15:15:19 +08:00
DacongDA
d867afdd70 feat: can set default value for "Auto sign in" in application edit page (#3987) 2025-07-22 22:57:01 +08:00
Attack825
a92430e8fd feat: fix auto sign-in flow on result page (#3983) 2025-07-22 20:19:45 +08:00
Yang Luo
447cb70553 feat: change some fields of organization and user to mediumtext 2025-07-21 23:43:17 +08:00
Yang Luo
e05fbec739 feat: keep backward compatibility in GetHashedPassword() 2025-07-21 19:32:59 +08:00
DacongDA
65ab36f073 feat: fix bug that GetHashedPassword() reports error (#3982) 2025-07-21 14:41:09 +08:00
M Zahid Rausyanfikri
d027e07383 feat: fix bug that needUpdatePassword is not respected (#3979) 2025-07-21 10:17:24 +08:00
DacongDA
d3c718b577 feat: fix bug that language cannot be switched to user selected language (#3980) 2025-07-21 10:16:07 +08:00
DacongDA
ea68e6c2dc feat: support inline-captcha in login page (#3970) 2025-07-19 01:12:07 +08:00
raiki02
7aa0b2e63f feat: change the method "login" to correct param "signup" (#3971) 2025-07-19 00:49:00 +08:00
raiki02
a39b121280 feat: support WeChat login directly in login page (#3957) 2025-07-18 01:29:31 +08:00
DacongDA
feef4cc242 feat: set ResponseModesSupported to standard OIDC: "query", "fragment" (#3968) 2025-07-17 10:20:37 +08:00
Attack825
1b5ef53655 feat: fix tour bug about orgIsTourVisible settings (#3965) 2025-07-16 18:00:44 +08:00
Attack825
18d639cca2 feat: fix tour button (#3961) 2025-07-16 12:02:14 +08:00
DacongDA
3ac5aad648 feat: fix validate text error caused by password length check (#3964) 2025-07-16 10:10:13 +08:00
Robin Ye
2a53241128 feat: support 15 more currencies (#3963) 2025-07-16 01:07:25 +08:00
DacongDA
835273576b feat: add Lark OAuth provider (#3956) 2025-07-13 19:51:45 +08:00
raiki02
7fdc264ff6 feat: check if MFA is verified when required (#3954) 2025-07-12 15:20:44 +08:00
DacongDA
a120734bb1 feat: support links in email to reset password (#3939) 2025-07-12 00:18:56 +08:00
Vickko
edd0b30e08 feat: Supports smooth migration of password hash (#3940) 2025-07-11 19:57:55 +08:00
Attack825
2da597b26f feat: add support for per-account MFA validity period in org setting to reduce repeated prompts (#3917) 2025-07-11 00:24:33 +08:00
DacongDA
ef14c84edc feat: show the popover on the top when window's width too small and close popover when password options is empty (#3952) 2025-07-10 19:56:05 +08:00
Yang Luo
cb5c7667b5 feat: change Subscription's StartTime and EndTime to string 2025-07-10 14:11:40 +08:00
461 changed files with 47668 additions and 33550 deletions

View File

@@ -1,6 +1,10 @@
name: Build
on: [ push, pull_request ]
on:
push:
branches:
- master
pull_request:
jobs:
@@ -20,7 +24,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
go-version: '1.23'
cache-dependency-path: ./go.mod
- name: Tests
run: |
@@ -40,6 +44,12 @@ jobs:
cache-dependency-path: ./web/yarn.lock
- run: yarn install && CI=false yarn run build
working-directory: ./web
- name: Upload build artifacts
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
uses: actions/upload-artifact@v4
with:
name: frontend-build-${{ github.run_id }}
path: ./web/build
backend:
name: Back-end
@@ -49,7 +59,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
go-version: '1.23'
cache-dependency-path: ./go.mod
- run: go version
- name: Build
@@ -65,7 +75,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
go-version: '1.23'
cache: false
# gen a dummy config file
@@ -94,11 +104,28 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.16.5'
go-version: '1.23'
cache-dependency-path: ./go.mod
- name: start backend
run: nohup go run ./main.go &
run: nohup go run ./main.go > /tmp/backend.log 2>&1 &
working-directory: ./
- name: Wait for backend to be ready
run: |
echo "Waiting for backend server to start on port 8000..."
for i in {1..60}; do
if curl -s http://localhost:8000 > /dev/null 2>&1; then
echo "Backend is ready!"
break
fi
if [ $i -eq 60 ]; then
echo "Backend failed to start within 60 seconds"
echo "Backend logs:"
cat /tmp/backend.log || echo "No backend logs available"
exit 1
fi
echo "Waiting... ($i/60)"
sleep 1
done
- uses: actions/setup-node@v3
with:
node-version: 20
@@ -125,39 +152,95 @@ jobs:
name: cypress-videos
path: ./web/cypress/videos
release-and-push:
name: Release And Push
tag-release:
name: Create Tag
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
needs: [ frontend, backend, linter, e2e ]
outputs:
new-release-published: ${{ steps.semantic.outputs.new_release_published }}
new-release-version: ${{ steps.semantic.outputs.new_release_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create Tag with Semantic Release
id: semantic
uses: cycjimmy/semantic-release-action@v4
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
github-release:
name: GitHub Release
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && needs.tag-release.outputs.new-release-published == 'true'
needs: [ tag-release ]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Free disk space
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: true
swap-storage: true
- name: Download frontend build artifacts
uses: actions/download-artifact@v4
with:
name: frontend-build-${{ github.run_id }}
path: ./web/build
- name: Prepare Go caches
run: |
echo "GOMODCACHE=$RUNNER_TEMP/gomod" >> $GITHUB_ENV
echo "GOCACHE=$RUNNER_TEMP/gocache" >> $GITHUB_ENV
go clean -cache -modcache -testcache -fuzzcache
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: '~> v2'
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
docker-release:
name: Docker Release
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && needs.tag-release.outputs.new-release-published == 'true'
needs: [ tag-release ]
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: -1
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: Fetch Previous version
id: get-previous-tag
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
- name: Release
run: yarn global add semantic-release@17.4.4 && semantic-release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fetch Current version
id: get-current-tag
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
- name: Decide Should_Push Or Not
id: should_push
run: |
old_version=${{steps.get-previous-tag.outputs.tag}}
new_version=${{steps.get-current-tag.outputs.tag }}
new_version=${{ needs.tag-release.outputs.new-release-version }}
old_array=(${old_version//\./ })
new_array=(${new_version//\./ })
@@ -196,7 +279,7 @@ jobs:
target: STANDARD
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
tags: casbin/casdoor:${{ needs.tag-release.outputs.new-release-version }},casbin/casdoor:latest
- name: Push All In One Version to Docker Hub
uses: docker/build-push-action@v3
@@ -206,7 +289,7 @@ jobs:
target: ALLINONE
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest
tags: casbin/casdoor-all-in-one:${{ needs.tag-release.outputs.new-release-version }},casbin/casdoor-all-in-one:latest
- uses: actions/checkout@v3
if: steps.should_push.outputs.push=='true'
@@ -219,8 +302,8 @@ jobs:
if: steps.should_push.outputs.push=='true'
run: |
# Set the appVersion and version of the chart to the current tag
sed -i "s/appVersion: .*/appVersion: ${{steps.get-current-tag.outputs.tag }}/g" ./charts/casdoor/Chart.yaml
sed -i "s/version: .*/version: ${{steps.get-current-tag.outputs.tag }}/g" ./charts/casdoor/Chart.yaml
sed -i "s/appVersion: .*/appVersion: ${{ needs.tag-release.outputs.new-release-version }}/g" ./charts/casdoor/Chart.yaml
sed -i "s/version: .*/version: ${{ needs.tag-release.outputs.new-release-version }}/g" ./charts/casdoor/Chart.yaml
REGISTRY=oci://registry-1.docker.io/casbin
cd charts/casdoor
@@ -234,6 +317,6 @@ jobs:
git config --global user.name "casbin-bot"
git config --global user.email "bot@casbin.org"
git add Chart.yaml index.yaml
git commit -m "chore(helm): bump helm charts appVersion to ${{steps.get-current-tag.outputs.tag }}"
git tag ${{steps.get-current-tag.outputs.tag }}
git commit -m "chore(helm): bump helm charts appVersion to ${{ needs.tag-release.outputs.new-release-version }}"
git tag ${{ needs.tag-release.outputs.new-release-version }}
git push origin HEAD:master --follow-tags

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
*.so
*.dylib
*.swp
server_*
# Test binary, built with `go test -c`
*.test

55
.goreleaser.yaml Normal file
View File

@@ -0,0 +1,55 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 2
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
#- go generate ./...
- go test -v -run TestGetVersionInfo ./util/system_test.go ./util/system.go ./util/variable.go
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
archives:
- format: tar.gz
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
format: zip
files:
- src: 'web/build'
dst: './web/build'
- src: 'conf/app.conf'
dst: './conf/app.conf'
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"

View File

@@ -1,14 +1,26 @@
FROM --platform=$BUILDPLATFORM node:18.19.0 AS FRONT
WORKDIR /web
# Copy only dependency files first for better caching
COPY ./web/package.json ./web/yarn.lock ./
RUN yarn install --frozen-lockfile --network-timeout 1000000
# Copy source files and build
COPY ./web .
RUN yarn install --frozen-lockfile --network-timeout 1000000 && NODE_OPTIONS="--max-old-space-size=4096" yarn run build
RUN NODE_OPTIONS="--max-old-space-size=4096" yarn run build
FROM --platform=$BUILDPLATFORM golang:1.21.13 AS BACK
FROM --platform=$BUILDPLATFORM golang:1.23.12 AS BACK
WORKDIR /go/src/casdoor
# Copy only go.mod and go.sum first for dependency caching
COPY go.mod go.sum ./
RUN go mod download
# Copy source files
COPY . .
RUN go test -v -run TestGetVersionInfo ./util/system_test.go ./util/system.go ./util/variable.go
RUN ./build.sh
RUN go test -v -run TestGetVersionInfo ./util/system_test.go ./util/system.go > version_info.txt
FROM alpine:latest AS STANDARD
LABEL MAINTAINER="https://casdoor.org/"
@@ -34,35 +46,25 @@ WORKDIR /
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server_${BUILDX_ARCH} ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt
COPY --from=FRONT --chown=$USER:$USER /web/build ./web/build
ENTRYPOINT ["/server"]
FROM debian:latest AS db
RUN apt update \
&& apt install -y \
mariadb-server \
mariadb-client \
&& rm -rf /var/lib/apt/lists/*
FROM db AS ALLINONE
FROM debian:latest AS ALLINONE
LABEL MAINTAINER="https://casdoor.org/"
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN apt update
RUN apt install -y ca-certificates && update-ca-certificates
RUN apt install -y ca-certificates lsof && update-ca-certificates
WORKDIR /
COPY --from=BACK /go/src/casdoor/server_${BUILDX_ARCH} ./server
COPY --from=BACK /go/src/casdoor/swagger ./swagger
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=BACK /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt
COPY --from=FRONT /web/build ./web/build
ENTRYPOINT ["/bin/bash"]

View File

@@ -42,20 +42,6 @@
</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)

View File

@@ -46,6 +46,8 @@ p, *, *, POST, /api/login, *, *
p, *, *, GET, /api/get-app-login, *, *
p, *, *, POST, /api/logout, *, *
p, *, *, GET, /api/logout, *, *
p, *, *, POST, /api/sso-logout, *, *
p, *, *, GET, /api/sso-logout, *, *
p, *, *, POST, /api/callback, *, *
p, *, *, POST, /api/device-auth, *, *
p, *, *, GET, /api/get-account, *, *
@@ -57,18 +59,25 @@ p, *, *, GET, /api/get-qrcode, *, *
p, *, *, GET, /api/get-webhook-event, *, *
p, *, *, GET, /api/get-captcha-status, *, *
p, *, *, *, /api/login/oauth, *, *
p, *, *, POST, /api/oauth/register, *, *
p, *, *, GET, /api/get-application, *, *
p, *, *, GET, /api/get-organization-applications, *, *
p, *, *, GET, /api/get-user, *, *
p, *, *, GET, /api/get-user-application, *, *
p, *, *, POST, /api/upload-users, *, *
p, *, *, GET, /api/get-resources, *, *
p, *, *, GET, /api/get-records, *, *
p, *, *, GET, /api/get-product, *, *
p, *, *, POST, /api/buy-product, *, *
p, *, *, GET, /api/get-order, *, *
p, *, *, GET, /api/get-orders, *, *
p, *, *, GET, /api/get-user-orders, *, *
p, *, *, GET, /api/get-payment, *, *
p, *, *, POST, /api/update-payment, *, *
p, *, *, POST, /api/invoice-payment, *, *
p, *, *, POST, /api/notify-payment, *, *
p, *, *, POST, /api/place-order, *, *
p, *, *, POST, /api/cancel-order, *, *
p, *, *, POST, /api/pay-order, *, *
p, *, *, POST, /api/unlink, *, *
p, *, *, POST, /api/set-password, *, *
p, *, *, POST, /api/send-verification-code, *, *
@@ -80,6 +89,9 @@ p, *, *, POST, /api/upload-resource, *, *
p, *, *, GET, /.well-known/openid-configuration, *, *
p, *, *, GET, /.well-known/webfinger, *, *
p, *, *, *, /.well-known/jwks, *, *
p, *, *, GET, /.well-known/:application/openid-configuration, *, *
p, *, *, GET, /.well-known/:application/webfinger, *, *
p, *, *, *, /.well-known/:application/jwks, *, *
p, *, *, GET, /api/get-saml-login, *, *
p, *, *, POST, /api/acs, *, *
p, *, *, GET, /api/saml/metadata, *, *
@@ -94,6 +106,8 @@ p, *, *, *, /api/metrics, *, *
p, *, *, GET, /api/get-pricing, *, *
p, *, *, GET, /api/get-plan, *, *
p, *, *, GET, /api/get-subscription, *, *
p, *, *, GET, /api/get-transactions, *, *
p, *, *, GET, /api/get-transaction, *, *
p, *, *, GET, /api/get-provider, *, *
p, *, *, GET, /api/get-organization-names, *, *
p, *, *, GET, /api/get-all-objects, *, *
@@ -122,7 +136,15 @@ p, *, *, GET, /api/faceid-signin-begin, *, *
}
}
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
func IsAllowed(subOwner string, subName string, method string, urlPath string, objOwner string, objName string, extraInfo map[string]interface{}) bool {
if urlPath == "/api/mcp" {
if detailPath, ok := extraInfo["detailPathUrl"].(string); ok {
if detailPath == "initialize" || detailPath == "notifications/initialized" || detailPath == "ping" || detailPath == "tools/list" {
return true
}
}
}
if conf.IsDemoMode() {
if !isAllowedInDemoMode(subOwner, subName, method, urlPath, objOwner, objName) {
return false
@@ -143,6 +165,10 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
return false
}
if user.IsGlobalAdmin() {
return true
}
if user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) {
return true
}
@@ -153,12 +179,19 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
panic(err)
}
if !res {
res, err = object.CheckApiPermission(util.GetId(subOwner, subName), objOwner, urlPath, method)
if err != nil {
panic(err)
}
}
return res
}
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if method == "POST" {
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/verify-code" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") || urlPath == "/api/webhook" || urlPath == "/api/get-qrcode" || urlPath == "/api/refresh-engines" {
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/sso-logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/verify-code" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") || urlPath == "/api/webhook" || urlPath == "/api/get-qrcode" || urlPath == "/api/refresh-engines" {
return true
} else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information
@@ -166,7 +199,7 @@ func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath
return true
}
return false
} else if urlPath == "/api/upload-resource" {
} else if urlPath == "/api/upload-resource" || urlPath == "/api/add-transaction" {
if subOwner == "app" && subName == "app-casibase" {
return true
}

View File

@@ -30,6 +30,8 @@ ldapsServerPort = 636
radiusServerPort = 1812
radiusDefaultOrganization = "built-in"
radiusSecret = "secret"
proxyHttpPort =
proxyHttpsPort =
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
logConfig = {"adapter":"file", "filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
initDataNewOnly = false

View File

@@ -21,7 +21,7 @@ import (
"strconv"
"strings"
"github.com/beego/beego"
"github.com/beego/beego/v2/server/web"
)
func init() {
@@ -29,7 +29,7 @@ func init() {
presetConfigItems := []string{"httpport", "appname"}
for _, key := range presetConfigItems {
if value, ok := os.LookupEnv(key); ok {
err := beego.AppConfig.Set(key, value)
err := web.AppConfig.Set(key, value)
if err != nil {
panic(err)
}
@@ -42,12 +42,13 @@ func GetConfigString(key string) string {
return value
}
res := beego.AppConfig.String(key)
res, _ := web.AppConfig.String(key)
if res == "" {
if key == "staticBaseUrl" {
res = "https://cdn.casbin.org"
} else if key == "logConfig" {
res = fmt.Sprintf("{\"filename\": \"logs/%s.log\", \"maxdays\":99999, \"perm\":\"0770\"}", beego.AppConfig.String("appname"))
appname, _ := web.AppConfig.String("appname")
res = fmt.Sprintf("{\"filename\": \"logs/%s.log\", \"maxdays\":99999, \"perm\":\"0770\"}", appname)
}
}

View File

@@ -17,7 +17,7 @@ package conf
import (
"encoding/json"
"github.com/beego/beego"
"github.com/beego/beego/v2/server/web"
)
type Quota struct {
@@ -34,7 +34,7 @@ func init() {
}
func initQuota() {
res := beego.AppConfig.String("quota")
res, _ := web.AppConfig.String("quota")
if res != "" {
err := json.Unmarshal([]byte(res), quota)
if err != nil {

View File

@@ -18,7 +18,7 @@ import (
"os"
"testing"
"github.com/beego/beego"
"github.com/beego/beego/v2/server/web"
"github.com/stretchr/testify/assert"
)
@@ -38,7 +38,7 @@ func TestGetConfString(t *testing.T) {
os.Setenv("appname", "casbin")
os.Setenv("key", "value")
err := beego.LoadAppConfig("ini", "app.conf")
err := web.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
@@ -62,7 +62,7 @@ func TestGetConfInt(t *testing.T) {
// do some set up job
os.Setenv("httpport", "8001")
err := beego.LoadAppConfig("ini", "app.conf")
err := web.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
@@ -83,7 +83,7 @@ func TestGetConfBool(t *testing.T) {
{"Should be return false", "copyrequestbody", true},
}
err := beego.LoadAppConfig("ini", "app.conf")
err := web.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
t.Run(scenery.description, func(t *testing.T) {
@@ -102,7 +102,7 @@ func TestGetConfigQuota(t *testing.T) {
{"default", &Quota{-1, -1, -1, -1}},
}
err := beego.LoadAppConfig("ini", "app.conf")
err := web.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
quota := GetConfigQuota()
@@ -118,7 +118,7 @@ func TestGetConfigLogs(t *testing.T) {
{"Default log config", `{"adapter":"file", "filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}`},
}
err := beego.LoadAppConfig("ini", "app.conf")
err := web.LoadAppConfig("ini", "app.conf")
assert.Nil(t, err)
for _, scenery := range scenarios {
quota := GetConfigString("logConfig")

View File

@@ -15,6 +15,7 @@
package controllers
import (
"context"
"encoding/json"
"fmt"
"net/http"
@@ -80,11 +81,6 @@ type LaravelResponse struct {
// @Success 200 {object} controllers.Response The Response object
// @router /signup [post]
func (c *ApiController) Signup() {
if c.GetSessionUsername() != "" {
c.ResponseError(c.T("account:Please sign out first"), c.GetSessionUsername())
return
}
var authForm form.AuthForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &authForm)
if err != nil {
@@ -197,7 +193,7 @@ func (c *ApiController) Signup() {
userType := "normal-user"
if authForm.Plan != "" && authForm.Pricing != "" {
err = object.CheckPricingAndPlan(authForm.Organization, authForm.Pricing, authForm.Plan)
err = object.CheckPricingAndPlan(authForm.Organization, authForm.Pricing, authForm.Plan, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@@ -218,7 +214,7 @@ func (c *ApiController) Signup() {
Tag: authForm.Tag,
Education: authForm.Education,
Avatar: organization.DefaultAvatar,
Email: authForm.Email,
Email: strings.ToLower(authForm.Email),
Phone: authForm.Phone,
CountryCode: authForm.CountryCode,
Address: []string{},
@@ -235,6 +231,8 @@ func (c *ApiController) Signup() {
Invitation: invitationName,
InvitationCode: authForm.InvitationCode,
EmailVerified: userEmailVerified,
RegisterType: "Application Signup",
RegisterSource: fmt.Sprintf("%s/%s", authForm.Organization, application.Name),
}
if len(organization.Tags) > 0 {
@@ -286,9 +284,10 @@ func (c *ApiController) Signup() {
}
}
if application.HasPromptPage() && user.Type == "normal-user" {
// The prompt page needs the user to be signed in
if user.Type == "normal-user" {
c.SetSessionUsername(user.GetId())
} else if user.Type == "paid-user" {
c.SetSession("paidUsername", user.GetId())
}
if authForm.Email != "" {
@@ -313,6 +312,29 @@ func (c *ApiController) Signup() {
userId := user.GetId()
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
// Check if this is an OAuth flow and automatically generate code
clientId := c.Ctx.Input.Query("clientId")
responseType := c.Ctx.Input.Query("responseType")
redirectUri := c.Ctx.Input.Query("redirectUri")
scope := c.Ctx.Input.Query("scope")
state := c.Ctx.Input.Query("state")
nonce := c.Ctx.Input.Query("nonce")
codeChallenge := c.Ctx.Input.Query("code_challenge")
// If OAuth parameters are present, generate OAuth code and return it
if clientId != "" && responseType == ResponseTypeCode {
code, err := object.GetOAuthCode(userId, clientId, "", "password", responseType, redirectUri, scope, state, nonce, codeChallenge, "", c.Ctx.Request.Host, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
resp := codeToResponse(code)
c.Data["json"] = resp
c.ServeJSON()
return
}
c.ResponseOk(userId)
}
@@ -327,9 +349,9 @@ func (c *ApiController) Signup() {
// @router /logout [post]
func (c *ApiController) Logout() {
// https://openid.net/specs/openid-connect-rpinitiated-1_0-final.html
accessToken := c.Input().Get("id_token_hint")
redirectUri := c.Input().Get("post_logout_redirect_uri")
state := c.Input().Get("state")
accessToken := c.GetString("id_token_hint")
redirectUri := c.GetString("post_logout_redirect_uri")
state := c.GetString("state")
user := c.GetSessionUsername()
@@ -342,8 +364,12 @@ func (c *ApiController) Logout() {
c.ClearUserSession()
c.ClearTokenSession()
owner, username := util.GetOwnerAndNameFromId(user)
_, err := object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
if err != nil {
c.ResponseError(err.Error())
return
}
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID(context.Background()))
if err != nil {
c.ResponseError(err.Error())
return
@@ -390,9 +416,13 @@ func (c *ApiController) Logout() {
c.ClearUserSession()
c.ClearTokenSession()
// TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
owner, username := util.GetOwnerAndNameFromId(user)
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
if err != nil {
c.ResponseError(err.Error())
return
}
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID(context.Background()))
if err != nil {
c.ResponseError(err.Error())
return
@@ -422,6 +452,108 @@ func (c *ApiController) Logout() {
}
}
// SsoLogout
// @Title SsoLogout
// @Tag Login API
// @Description logout the current user from all applications or current session only
// @Param logoutAll query string false "Whether to logout from all sessions. Accepted values: 'true', '1', or empty (default: true). Any other value means false."
// @Success 200 {object} controllers.Response The Response object
// @router /sso-logout [get,post]
func (c *ApiController) SsoLogout() {
user := c.GetSessionUsername()
if user == "" {
c.ResponseOk()
return
}
// Check if user wants to logout from all sessions or just current session
// Default is true for backward compatibility
logoutAll := c.Ctx.Input.Query("logoutAll")
logoutAllSessions := logoutAll == "" || logoutAll == "true" || logoutAll == "1"
c.ClearUserSession()
c.ClearTokenSession()
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
if err != nil {
c.ResponseError(err.Error())
return
}
currentSessionId := c.Ctx.Input.CruSession.SessionID(context.Background())
_, err = object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), currentSessionId)
if err != nil {
c.ResponseError(err.Error())
return
}
var tokens []*object.Token
var sessionIds []string
// Get tokens for notification (needed for both session-level and full logout)
// This enables subsystems to identify and invalidate corresponding access tokens
// Note: Tokens must be retrieved BEFORE expiration to include their hashes in the notification
tokens, err = object.GetTokensByUser(owner, username)
if err != nil {
c.ResponseError(err.Error())
return
}
if logoutAllSessions {
// Logout from all sessions: expire all tokens and delete all sessions
_, err = object.ExpireTokenByUser(owner, username)
if err != nil {
c.ResponseError(err.Error())
return
}
sessions, err := object.GetUserSessions(owner, username)
if err != nil {
c.ResponseError(err.Error())
return
}
for _, session := range sessions {
sessionIds = append(sessionIds, session.SessionId...)
}
object.DeleteBeegoSession(sessionIds)
_, err = object.DeleteAllUserSessions(owner, username)
if err != nil {
c.ResponseError(err.Error())
return
}
util.LogInfo(c.Ctx, "API: [%s] logged out from all applications", user)
} else {
// Logout from current session only
sessionIds = []string{currentSessionId}
// Only delete the current session's Beego session
object.DeleteBeegoSession(sessionIds)
util.LogInfo(c.Ctx, "API: [%s] logged out from current session", user)
}
// Send SSO logout notifications to all notification providers in the user's signup application
// Now includes session-level information for targeted logout
userObj, err := object.GetUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
if userObj != nil {
err = object.SendSsoLogoutNotifications(userObj, sessionIds, tokens)
if err != nil {
c.ResponseError(err.Error())
return
}
}
c.ResponseOk()
}
// GetAccount
// @Title GetAccount
// @Tag Account API
@@ -435,7 +567,7 @@ func (c *ApiController) GetAccount() {
return
}
managedAccounts := c.Input().Get("managedAccounts")
managedAccounts := c.Ctx.Input.Query("managedAccounts")
if managedAccounts == "1" {
user, err = object.ExtendManagedAccountsWithUser(user)
if err != nil {
@@ -553,9 +685,54 @@ func (c *ApiController) GetUserinfo2() {
// @router /get-captcha [get]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) GetCaptcha() {
applicationId := c.Input().Get("applicationId")
isCurrentProvider := c.Input().Get("isCurrentProvider")
applicationId := c.Ctx.Input.Query("applicationId")
isCurrentProvider := c.Ctx.Input.Query("isCurrentProvider")
// When isCurrentProvider == "true", the frontend passes a provider ID instead of an application ID.
// In that case, skip application lookup and rule evaluation, and just return the provider config.
shouldSkipCaptcha := false
if isCurrentProvider != "true" {
application, err := object.GetApplication(applicationId)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), applicationId))
return
}
// Check the CAPTCHA rule to determine if CAPTCHA should be shown
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
// For Internet-Only rule, we can determine on the backend if CAPTCHA should be shown
// For other rules (Dynamic, Always), we need to return the CAPTCHA config
for _, providerItem := range application.Providers {
if providerItem.Provider == nil || providerItem.Provider.Category != "Captcha" {
continue
}
// For "None" rule, skip CAPTCHA
if providerItem.Rule == "None" || providerItem.Rule == "" {
shouldSkipCaptcha = true
} else if providerItem.Rule == "Internet-Only" {
// For Internet-Only rule, check if the client is from intranet
if !util.IsInternetIp(clientIp) {
// Client is from intranet, skip CAPTCHA
shouldSkipCaptcha = true
}
}
break // Only check the first CAPTCHA provider
}
if shouldSkipCaptcha {
c.ResponseOk(Captcha{Type: "none"})
return
}
}
captchaProvider, err := object.GetCaptchaProviderByApplication(applicationId, isCurrentProvider, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Adapter The Response object
// @router /get-adapters [get]
func (c *ApiController) GetAdapters() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
adapters, err := object.GetAdapters(owner)
@@ -54,7 +54,7 @@ func (c *ApiController) GetAdapters() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
adapters, err := object.GetPaginationAdapters(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,7 +73,7 @@ func (c *ApiController) GetAdapters() {
// @Success 200 {object} object.Adapter The Response object
// @router /get-adapter [get]
func (c *ApiController) GetAdapter() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
adapter, err := object.GetAdapter(id)
if err != nil {
@@ -93,7 +93,7 @@ func (c *ApiController) GetAdapter() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-adapter [post]
func (c *ApiController) UpdateAdapter() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var adapter object.Adapter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &adapter)

View File

@@ -18,7 +18,7 @@ import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -32,14 +32,14 @@ import (
// @router /get-applications [get]
func (c *ApiController) GetApplications() {
userId := c.GetSessionUsername()
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
organization := c.Ctx.Input.Query("organization")
var err error
if limit == "" || page == "" {
var applications []*object.Application
@@ -61,7 +61,7 @@ func (c *ApiController) GetApplications() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
application, err := object.GetPaginationApplications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -82,7 +82,7 @@ func (c *ApiController) GetApplications() {
// @router /get-application [get]
func (c *ApiController) GetApplication() {
userId := c.GetSessionUsername()
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
application, err := object.GetApplication(id)
if err != nil {
@@ -90,7 +90,7 @@ func (c *ApiController) GetApplication() {
return
}
if c.Input().Get("withKey") != "" && application != nil && application.Cert != "" {
if c.Ctx.Input.Query("withKey") != "" && application != nil && application.Cert != "" {
cert, err := object.GetCert(util.GetId(application.Owner, application.Cert))
if err != nil {
c.ResponseError(err.Error())
@@ -125,7 +125,7 @@ func (c *ApiController) GetApplication() {
// @router /get-user-application [get]
func (c *ApiController) GetUserApplication() {
userId := c.GetSessionUsername()
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
user, err := object.GetUser(id)
if err != nil {
@@ -159,14 +159,14 @@ func (c *ApiController) GetUserApplication() {
// @router /get-organization-applications [get]
func (c *ApiController) GetOrganizationApplications() {
userId := c.GetSessionUsername()
organization := c.Input().Get("organization")
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Ctx.Input.Query("organization")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if organization == "" {
c.ResponseError(c.T("general:Missing parameter") + ": organization")
@@ -196,7 +196,7 @@ func (c *ApiController) GetOrganizationApplications() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
applications, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -223,7 +223,7 @@ func (c *ApiController) GetOrganizationApplications() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-application [post]
func (c *ApiController) UpdateApplication() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var application object.Application
err := json.Unmarshal(c.Ctx.Input.RequestBody, &application)
@@ -237,7 +237,7 @@ func (c *ApiController) UpdateApplication() {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application, c.IsGlobalAdmin(), c.GetAcceptLanguage()))
c.ServeJSON()
}

View File

@@ -15,6 +15,7 @@
package controllers
import (
"context"
"encoding/base64"
"encoding/json"
"encoding/xml"
@@ -27,6 +28,7 @@ import (
"strings"
"time"
"github.com/beego/beego/v2/server/web"
"github.com/casdoor/casdoor/captcha"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/form"
@@ -61,6 +63,11 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
return
}
if user.IsDeleted {
c.ResponseError(c.T("check:The user has been deleted and cannot be used to sign in, please contact the administrator"))
return
}
userId := user.GetId()
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
@@ -70,6 +77,16 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
return
}
if application.DisableSignin {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s has disabled users to signin"), application.Name))
return
}
if application.OrganizationObj != nil && application.OrganizationObj.DisableSignin {
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s has disabled users to signin"), application.Organization))
return
}
allowed, err := object.CheckLoginPermission(userId, application)
if err != nil {
c.ResponseError(err.Error(), nil)
@@ -83,7 +100,8 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
// check user's tag
if !user.IsGlobalAdmin() && !user.IsAdmin && len(application.Tags) > 0 {
// only users with the tag that is listed in the application tags can login
if !util.InSlice(application.Tags, user.Tag) {
// supports comma-separated tags in user.Tag (e.g., "default-policy,project-admin")
if !util.HasTagInSlice(application.Tags, user.Tag) {
c.ResponseError(fmt.Sprintf(c.T("auth:User's tag: %s is not listed in the application's tags"), user.Tag))
return
}
@@ -121,6 +139,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
c.ResponseError(fmt.Sprintf(c.T("auth:paid-user %s does not have active or pending subscription and the application: %s does not have default pricing"), user.Name, application.Name))
return
} else {
c.SetSession("paidUsername", user.GetId())
// let the paid-user select plan
c.ResponseOk("SelectPlan", pricing)
return
@@ -134,20 +153,21 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
resp = &Response{Status: "ok", Msg: "", Data: userId, Data3: user.NeedUpdatePassword}
} else if form.Type == ResponseTypeCode {
clientId := c.Input().Get("clientId")
responseType := c.Input().Get("responseType")
redirectUri := c.Input().Get("redirectUri")
scope := c.Input().Get("scope")
state := c.Input().Get("state")
nonce := c.Input().Get("nonce")
challengeMethod := c.Input().Get("code_challenge_method")
codeChallenge := c.Input().Get("code_challenge")
clientId := c.Ctx.Input.Query("clientId")
responseType := c.Ctx.Input.Query("responseType")
redirectUri := c.Ctx.Input.Query("redirectUri")
scope := c.Ctx.Input.Query("scope")
state := c.Ctx.Input.Query("state")
nonce := c.Ctx.Input.Query("nonce")
challengeMethod := c.Ctx.Input.Query("code_challenge_method")
codeChallenge := c.Ctx.Input.Query("code_challenge")
resource := c.Ctx.Input.Query("resource")
if challengeMethod != "S256" && challengeMethod != "null" && challengeMethod != "" {
c.ResponseError(c.T("auth:Challenge method should be S256"))
return
}
code, err := object.GetOAuthCode(userId, clientId, form.Provider, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
code, err := object.GetOAuthCode(userId, clientId, form.Provider, form.SigninMethod, responseType, redirectUri, scope, state, nonce, codeChallenge, resource, c.Ctx.Request.Host, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error(), nil)
return
@@ -163,8 +183,8 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
if !object.IsGrantTypeValid(form.Type, application.GrantTypes) {
resp = &Response{Status: "error", Msg: fmt.Sprintf("error: grant_type: %s is not supported in this application", form.Type), Data: ""}
} else {
scope := c.Input().Get("scope")
nonce := c.Input().Get("nonce")
scope := c.Ctx.Input.Query("scope")
nonce := c.Ctx.Input.Query("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token)
@@ -210,7 +230,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}
} else if form.Type == ResponseTypeCas {
// not oauth but CAS SSO protocol
service := c.Input().Get("service")
service := c.Ctx.Input.Query("service")
resp = wrapErrorResponse(nil)
if service != "" {
st, err := object.GenerateCasToken(userId, service)
@@ -229,9 +249,36 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
resp = wrapErrorResponse(fmt.Errorf("unknown response type: %s", form.Type))
}
// if user did not check auto signin
if resp.Status == "ok" && !form.AutoSignin {
c.setExpireForSession()
// For all successful logins, set the session expiration; if auto signin is not checked, cap it at 24 hours.
if resp.Status == "ok" {
expireInHours := application.CookieExpireInHours
if expireInHours == 0 {
expireInHours = 720
}
if !form.AutoSignin && expireInHours > 24 {
expireInHours = 24
}
c.setExpireForSession(expireInHours)
}
if application.EnableExclusiveSignin {
sessions, err := object.GetUserAppSessions(user.Owner, user.Name, application.Name)
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
for _, session := range sessions {
for _, sid := range session.SessionId {
err := web.GlobalSessions.GetProvider().SessionDestroy(context.Background(), sid)
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
}
}
}
if resp.Status == "ok" {
@@ -239,7 +286,9 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
Owner: user.Owner,
Name: user.Name,
Application: application.Name,
SessionId: []string{c.Ctx.Input.CruSession.SessionID()},
SessionId: []string{c.Ctx.Input.CruSession.SessionID(context.Background())},
ExclusiveSignin: application.EnableExclusiveSignin,
})
if err != nil {
c.ResponseError(err.Error(), nil)
@@ -262,14 +311,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
// @Success 200 {object} controllers.Response The Response object
// @router /get-app-login [get]
func (c *ApiController) GetApplicationLogin() {
clientId := c.Input().Get("clientId")
responseType := c.Input().Get("responseType")
redirectUri := c.Input().Get("redirectUri")
scope := c.Input().Get("scope")
state := c.Input().Get("state")
id := c.Input().Get("id")
loginType := c.Input().Get("type")
userCode := c.Input().Get("userCode")
clientId := c.Ctx.Input.Query("clientId")
responseType := c.Ctx.Input.Query("responseType")
redirectUri := c.Ctx.Input.Query("redirectUri")
scope := c.Ctx.Input.Query("scope")
state := c.Ctx.Input.Query("state")
id := c.Ctx.Input.Query("id")
loginType := c.Ctx.Input.Query("type")
userCode := c.Ctx.Input.Query("userCode")
var application *object.Application
var msg string
@@ -355,25 +404,32 @@ func isProxyProviderType(providerType string) bool {
func checkMfaEnable(c *ApiController, user *object.User, organization *object.Organization, verificationType string) bool {
if object.IsNeedPromptMfa(organization, user) {
// The prompt page needs the user to be srigned in
// The prompt page needs the user to be signed in
c.SetSessionUsername(user.GetId())
c.ResponseOk(object.RequiredMfa)
return true
}
if user.IsMfaEnabled() {
currentTime := util.String2Time(util.GetCurrentTime())
mfaRememberDeadline := util.String2Time(user.MfaRememberDeadline)
if user.MfaRememberDeadline != "" && mfaRememberDeadline.After(currentTime) {
return false
}
c.setMfaUserSession(user.GetId())
mfaList := object.GetAllMfaProps(user, true)
mfaAllowList := []*object.MfaProps{}
mfaRememberInHours := organization.MfaRememberInHours
for _, prop := range mfaList {
if prop.MfaType == verificationType || !prop.Enabled {
continue
}
prop.MfaRememberInHours = mfaRememberInHours
mfaAllowList = append(mfaAllowList, prop)
}
if len(mfaAllowList) >= 1 {
c.SetSession("verificationCodeType", verificationType)
c.Ctx.Input.CruSession.SessionRelease(c.Ctx.ResponseWriter)
c.Ctx.Input.CruSession.SessionRelease(context.Background(), c.Ctx.ResponseWriter)
c.ResponseOk(object.NextMfa, mfaAllowList)
return true
}
@@ -410,13 +466,6 @@ func (c *ApiController) Login() {
verificationType := ""
if authForm.Username != "" {
if authForm.Type == ResponseTypeLogin {
if c.GetSessionUsername() != "" {
c.ResponseError(c.T("account:Please sign out first"), c.GetSessionUsername())
return
}
}
var user *object.User
if authForm.SigninMethod == "Face ID" {
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
@@ -671,6 +720,7 @@ func (c *ApiController) Login() {
}
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), authForm.Provider))
return
}
providerItem := application.GetProviderItem(provider.Name)
@@ -679,6 +729,7 @@ func (c *ApiController) Login() {
return
}
userInfo := &idp.UserInfo{}
var token *oauth2.Token
if provider.Category == "SAML" {
// SAML
userInfo, err = object.ParseSamlResponse(authForm.SamlResponse, provider, c.Ctx.Request.Host)
@@ -689,6 +740,7 @@ func (c *ApiController) Login() {
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
// OAuth
idpInfo := object.FromProviderToIdpInfo(c.Ctx, provider)
idpInfo.CodeVerifier = authForm.CodeVerifier
var idProvider idp.IdProvider
idProvider, err = idp.GetIdProvider(idpInfo, authForm.RedirectUri)
if err != nil {
@@ -702,13 +754,13 @@ func (c *ApiController) Login() {
setHttpClient(idProvider, provider.Type)
if authForm.State != conf.GetConfigString("authState") && authForm.State != application.Name {
stateApplicationName := strings.Split(authForm.State, "-org-")[0]
if authForm.State != conf.GetConfigString("authState") && stateApplicationName != application.Name {
c.ResponseError(fmt.Sprintf(c.T("auth:State expected: %s, but got: %s"), conf.GetConfigString("authState"), authForm.State))
return
}
// https://github.com/golang/oauth2/issues/123#issuecomment-103715338
var token *oauth2.Token
token, err = idProvider.GetToken(authForm.Code)
if err != nil {
c.ResponseError(err.Error())
@@ -758,7 +810,7 @@ func (c *ApiController) Login() {
if user != nil && !user.IsDeleted {
// Sign in via OAuth (want to sign up but already have account)
// sync info from 3rd-party if possible
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo, token, provider.UserMapping)
if err != nil {
c.ResponseError(err.Error())
return
@@ -771,7 +823,7 @@ func (c *ApiController) Login() {
resp = c.HandleLoggedIn(application, user, &authForm)
c.Ctx.Input.SetParam("recordUserId", user.GetId())
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
} else if provider.Category == "OAuth" || provider.Category == "Web3" || provider.Category == "SAML" {
// Sign up via OAuth
if application.EnableLinkWithEmail {
if userInfo.Email != "" {
@@ -793,21 +845,44 @@ func (c *ApiController) Login() {
}
}
if user == nil || user.IsDeleted {
// Try to find existing user by username (case-insensitive)
// This allows OAuth providers (e.g., Wecom) to automatically associate with
// existing users when usernames match, particularly useful for enterprise
// scenarios where signup is disabled and users already exist in Casdoor
if user == nil && userInfo.Username != "" {
user, err = object.GetUserByFields(application.Organization, userInfo.Username)
if err != nil {
c.ResponseError(err.Error())
return
}
}
if user == nil {
if !application.EnableSignUp {
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support"), provider.Type, userInfo.Username, userInfo.DisplayName))
return
}
if !providerItem.CanSignUp {
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
return
}
if application.IsSignupItemRequired("Invitation code") {
c.ResponseError(c.T("check:Invitation code cannot be blank"))
// Check and validate invitation code
invitation, msg := object.CheckInvitationCode(application, organization, &authForm, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
return
}
invitationName := ""
if invitation != nil {
invitationName = invitation.Name
}
// Handle UseEmailAsUsername for OAuth and Web3
if organization.UseEmailAsUsername && userInfo.Email != "" {
userInfo.Username = userInfo.Email
}
// Handle username conflicts
var tmpUser *object.User
@@ -869,6 +944,17 @@ func (c *ApiController) Login() {
IsDeleted: false,
SignupApplication: application.Name,
Properties: properties,
Invitation: invitationName,
InvitationCode: authForm.InvitationCode,
RegisterType: "Application Signup",
RegisterSource: fmt.Sprintf("%s/%s", application.Organization, application.Name),
}
// Set group from invitation code if available, otherwise use provider's signup group
if invitation != nil && invitation.SignupGroup != "" {
user.Groups = []string{invitation.SignupGroup}
} else if providerItem.SignupGroup != "" {
user.Groups = []string{providerItem.SignupGroup}
}
var affected bool
@@ -883,9 +969,10 @@ func (c *ApiController) Login() {
return
}
if providerItem.SignupGroup != "" {
user.Groups = []string{providerItem.SignupGroup}
_, err = object.UpdateUser(user.GetId(), user, []string{"groups"}, false)
// Increment invitation usage count
if invitation != nil {
invitation.UsedCount += 1
_, err = object.UpdateInvitation(invitation.GetId(), invitation, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@@ -894,7 +981,7 @@ func (c *ApiController) Login() {
}
// sync info from 3rd-party if possible
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo, token, provider.UserMapping)
if err != nil {
c.ResponseError(err.Error())
return
@@ -942,7 +1029,7 @@ func (c *ApiController) Login() {
}
// sync info from 3rd-party if possible
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo, token, provider.UserMapping)
if err != nil {
c.ResponseError(err.Error())
return
@@ -973,6 +1060,28 @@ func (c *ApiController) Login() {
return
}
var application *object.Application
if authForm.ClientId == "" {
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
} else {
application, err = object.GetApplicationByClientId(authForm.ClientId)
}
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
var organization *object.Organization
organization, err = object.GetOrganization(util.GetId("admin", application.Organization))
if err != nil {
c.ResponseError(c.T(err.Error()))
}
if authForm.Passcode != "" {
if authForm.MfaType == c.GetSession("verificationCodeType") {
c.ResponseError("Invalid multi-factor authentication type")
@@ -999,6 +1108,17 @@ func (c *ApiController) Login() {
}
}
if authForm.EnableMfaRemember {
mfaRememberInSeconds := organization.MfaRememberInHours * 3600
currentTime := util.String2Time(util.GetCurrentTime())
duration := time.Duration(mfaRememberInSeconds) * time.Second
user.MfaRememberDeadline = util.Time2String(currentTime.Add(duration))
_, err = object.UpdateUser(user.GetId(), user, []string{"mfa_remember_deadline"}, user.IsAdmin)
if err != nil {
c.ResponseError(err.Error())
return
}
}
c.SetSession("verificationCodeType", "")
} else if authForm.RecoveryCode != "" {
err = object.MfaRecover(user, authForm.RecoveryCode)
@@ -1011,22 +1131,6 @@ func (c *ApiController) Login() {
return
}
var application *object.Application
if authForm.ClientId == "" {
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
} else {
application, err = object.GetApplicationByClientId(authForm.ClientId)
}
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
resp = c.HandleLoggedIn(application, user, &authForm)
c.setMfaUserSession("")
@@ -1077,8 +1181,8 @@ func (c *ApiController) Login() {
}
func (c *ApiController) GetSamlLogin() {
providerId := c.Input().Get("id")
relayState := c.Input().Get("relayState")
providerId := c.Ctx.Input.Query("id")
relayState := c.Ctx.Input.Query("relayState")
authURL, method, err := object.GenerateSamlRequest(providerId, relayState, c.Ctx.Request.Host, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
@@ -1088,8 +1192,8 @@ func (c *ApiController) GetSamlLogin() {
}
func (c *ApiController) HandleSamlLogin() {
relayState := c.Input().Get("RelayState")
samlResponse := c.Input().Get("SAMLResponse")
relayState := c.Ctx.Input.Query("RelayState")
samlResponse := c.Ctx.Input.Query("SAMLResponse")
decode, err := base64.StdEncoding.DecodeString(relayState)
if err != nil {
c.ResponseError(err.Error())
@@ -1121,9 +1225,9 @@ func (c *ApiController) HandleOfficialAccountEvent() {
c.ResponseError(err.Error())
return
}
signature := c.Input().Get("signature")
timestamp := c.Input().Get("timestamp")
nonce := c.Input().Get("nonce")
signature := c.Ctx.Input.Query("signature")
timestamp := c.Ctx.Input.Query("timestamp")
nonce := c.Ctx.Input.Query("nonce")
var data struct {
MsgType string `xml:"MsgType"`
Event string `xml:"Event"`
@@ -1141,7 +1245,7 @@ func (c *ApiController) HandleOfficialAccountEvent() {
return
}
if data.Ticket == "" {
c.ResponseError(err.Error())
c.ResponseError("empty ticket")
return
}
@@ -1151,10 +1255,11 @@ func (c *ApiController) HandleOfficialAccountEvent() {
c.ResponseError(err.Error())
return
}
if data.Ticket == "" {
c.ResponseError("empty ticket")
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), providerId))
return
}
if !idp.VerifyWechatSignature(provider.Content, nonce, timestamp, signature) {
c.ResponseError("invalid signature")
return
@@ -1180,7 +1285,7 @@ func (c *ApiController) HandleOfficialAccountEvent() {
// @Param ticket query string true "The eventId of QRCode"
// @Success 200 {object} controllers.Response The Response object
func (c *ApiController) GetWebhookEventType() {
ticket := c.Input().Get("ticket")
ticket := c.Ctx.Input.Query("ticket")
idp.Lock.RLock()
_, ok := idp.WechatCacheMap[ticket]
@@ -1200,12 +1305,17 @@ func (c *ApiController) GetWebhookEventType() {
// @Param id query string true "The id ( owner/name ) of provider"
// @Success 200 {object} controllers.Response The Response object
func (c *ApiController) GetQRCode() {
providerId := c.Input().Get("id")
providerId := c.Ctx.Input.Query("id")
provider, err := object.GetProvider(providerId)
if err != nil {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), providerId))
return
}
code, ticket, err := idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2, providerId)
if err != nil {
c.ResponseError(err.Error())
@@ -1223,9 +1333,9 @@ func (c *ApiController) GetQRCode() {
// @Success 200 {object} controllers.Response The Response object
// @router /get-captcha-status [get]
func (c *ApiController) GetCaptchaStatus() {
organization := c.Input().Get("organization")
userId := c.Input().Get("userId")
applicationName := c.Input().Get("application")
organization := c.Ctx.Input.Query("organization")
userId := c.Ctx.Input.Query("userId")
applicationName := c.Ctx.Input.Query("application")
application, err := object.GetApplication(fmt.Sprintf("admin/%s", applicationName))
if err != nil {
@@ -1268,8 +1378,8 @@ func (c *ApiController) Callback() {
// @router /device-auth [post]
// @Success 200 {object} object.DeviceAuthResponse The Response object
func (c *ApiController) DeviceAuth() {
clientId := c.Input().Get("client_id")
scope := c.Input().Get("scope")
clientId := c.Ctx.Input.Query("client_id")
scope := c.Ctx.Input.Query("scope")
application, err := object.GetApplicationByClientId(clientId)
if err != nil {
c.Data["json"] = object.TokenError{

View File

@@ -15,11 +15,12 @@
package controllers
import (
"context"
"strings"
"time"
"github.com/beego/beego"
"github.com/beego/beego/logs"
"github.com/beego/beego/v2/core/logs"
"github.com/beego/beego/v2/server/web"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -27,7 +28,7 @@ import (
// ApiController
// controller for handlers under /api uri
type ApiController struct {
beego.Controller
web.Controller
}
// RootController
@@ -104,6 +105,13 @@ func (c *ApiController) getCurrentUser() *object.User {
// GetSessionUsername ...
func (c *ApiController) GetSessionUsername() string {
// prefer username stored in Beego context by ApiFilter
if ctxUser := c.Ctx.Input.GetData("currentUserId"); ctxUser != nil {
if username, ok := ctxUser.(string); ok {
return username
}
}
// check if user session expired
sessionData := c.GetSessionData()
@@ -122,6 +130,26 @@ func (c *ApiController) GetSessionUsername() string {
return user.(string)
}
// GetPaidUsername ...
func (c *ApiController) GetPaidUsername() string {
// check if user session expired
sessionData := c.GetSessionData()
if sessionData != nil &&
sessionData.ExpireTime != 0 &&
sessionData.ExpireTime < time.Now().Unix() {
c.ClearUserSession()
return ""
}
user := c.GetSession("paidUsername")
if user == nil {
return ""
}
return user.(string)
}
func (c *ApiController) GetSessionToken() string {
accessToken := c.GetSession("accessToken")
if accessToken == nil {
@@ -148,6 +176,7 @@ func (c *ApiController) GetSessionApplication() *object.Application {
func (c *ApiController) ClearUserSession() {
c.SetSessionUsername("")
c.SetSessionData(nil)
_ = c.SessionRegenerateID()
}
func (c *ApiController) ClearTokenSession() {
@@ -216,16 +245,19 @@ func (c *ApiController) setMfaUserSession(userId string) {
}
func (c *ApiController) getMfaUserSession() string {
userId := c.Ctx.Input.CruSession.Get(object.MfaSessionUserId)
userId := c.Ctx.Input.CruSession.Get(context.Background(), object.MfaSessionUserId)
if userId == nil {
return ""
}
return userId.(string)
}
func (c *ApiController) setExpireForSession() {
func (c *ApiController) setExpireForSession(cookieExpireInHours int64) {
timestamp := time.Now().Unix()
timestamp += 3600 * 24
if cookieExpireInHours == 0 {
cookieExpireInHours = 720
}
timestamp += 3600 * cookieExpireInHours
c.SetSessionData(&SessionData{
ExpireTime: timestamp,
})

View File

@@ -41,8 +41,8 @@ func queryUnescape(service string) string {
}
func (c *RootController) CasValidate() {
ticket := c.Input().Get("ticket")
service := c.Input().Get("service")
ticket := c.Ctx.Input.Query("ticket")
service := c.Ctx.Input.Query("service")
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
if service == "" || ticket == "" {
c.Ctx.Output.Body([]byte("no\n"))
@@ -60,8 +60,8 @@ func (c *RootController) CasValidate() {
}
func (c *RootController) CasServiceValidate() {
ticket := c.Input().Get("ticket")
format := c.Input().Get("format")
ticket := c.Ctx.Input.Query("ticket")
format := c.Ctx.Input.Query("format")
if !strings.HasPrefix(ticket, "ST") {
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
}
@@ -75,8 +75,8 @@ func (c *RootController) CasProxyValidate() {
}
func (c *RootController) CasP3ServiceValidate() {
ticket := c.Input().Get("ticket")
format := c.Input().Get("format")
ticket := c.Ctx.Input.Query("ticket")
format := c.Ctx.Input.Query("format")
if !strings.HasPrefix(ticket, "ST") {
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
}
@@ -84,10 +84,10 @@ func (c *RootController) CasP3ServiceValidate() {
}
func (c *RootController) CasP3ProxyValidate() {
ticket := c.Input().Get("ticket")
format := c.Input().Get("format")
service := c.Input().Get("service")
pgtUrl := c.Input().Get("pgtUrl")
ticket := c.Ctx.Input.Query("ticket")
format := c.Ctx.Input.Query("format")
service := c.Ctx.Input.Query("service")
pgtUrl := c.Ctx.Input.Query("pgtUrl")
serviceResponse := object.CasServiceResponse{
Xmlns: "http://www.yale.edu/tp/cas",
@@ -161,9 +161,9 @@ func (c *RootController) CasP3ProxyValidate() {
}
func (c *RootController) CasProxy() {
pgt := c.Input().Get("pgt")
targetService := c.Input().Get("targetService")
format := c.Input().Get("format")
pgt := c.Ctx.Input.Query("pgt")
targetService := c.Ctx.Input.Query("targetService")
format := c.Ctx.Input.Query("format")
if pgt == "" || targetService == "" {
c.sendCasProxyResponseErr(InvalidRequest, "pgt and targetService must exist", format)
return
@@ -200,7 +200,7 @@ func (c *RootController) CasProxy() {
func (c *RootController) SamlValidate() {
c.Ctx.Output.Header("Content-Type", "text/xml; charset=utf-8")
target := c.Input().Get("TARGET")
target := c.Ctx.Input.Query("TARGET")
body := c.Ctx.Input.RequestBody
envelopRequest := struct {
XMLName xml.Name `xml:"Envelope"`

View File

@@ -34,11 +34,23 @@ import (
// @Success 200 {object} controllers.Response The Response object
// @router /enforce [post]
func (c *ApiController) Enforce() {
permissionId := c.Input().Get("permissionId")
modelId := c.Input().Get("modelId")
resourceId := c.Input().Get("resourceId")
enforcerId := c.Input().Get("enforcerId")
owner := c.Input().Get("owner")
permissionId := c.Ctx.Input.Query("permissionId")
modelId := c.Ctx.Input.Query("modelId")
resourceId := c.Ctx.Input.Query("resourceId")
enforcerId := c.Ctx.Input.Query("enforcerId")
owner := c.Ctx.Input.Query("owner")
params := []string{permissionId, modelId, resourceId, enforcerId, owner}
nonEmpty := 0
for _, param := range params {
if param != "" {
nonEmpty++
}
}
if nonEmpty > 1 {
c.ResponseError("Only one of the parameters (permissionId, modelId, resourceId, enforcerId, owner) should be provided")
return
}
if len(c.Ctx.Input.RequestBody) == 0 {
c.ResponseError("The request body should not be empty")
@@ -107,7 +119,11 @@ func (c *ApiController) Enforce() {
permissions := []*object.Permission{}
if modelId != "" {
owner, modelName := util.GetOwnerAndNameFromId(modelId)
owner, modelName, err := util.GetOwnerAndNameFromIdWithError(modelId)
if err != nil {
c.ResponseError(err.Error())
return
}
permissions, err = object.GetPermissionsByModel(owner, modelName)
if err != nil {
c.ResponseError(err.Error())
@@ -164,10 +180,22 @@ func (c *ApiController) Enforce() {
// @Success 200 {object} controllers.Response The Response object
// @router /batch-enforce [post]
func (c *ApiController) BatchEnforce() {
permissionId := c.Input().Get("permissionId")
modelId := c.Input().Get("modelId")
enforcerId := c.Input().Get("enforcerId")
owner := c.Input().Get("owner")
permissionId := c.Ctx.Input.Query("permissionId")
modelId := c.Ctx.Input.Query("modelId")
enforcerId := c.Ctx.Input.Query("enforcerId")
owner := c.Ctx.Input.Query("owner")
params := []string{permissionId, modelId, enforcerId, owner}
nonEmpty := 0
for _, param := range params {
if param != "" {
nonEmpty++
}
}
if nonEmpty > 1 {
c.ResponseError("Only one of the parameters (permissionId, modelId, enforcerId, owner) should be provided")
return
}
var requests [][]string
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
@@ -231,7 +259,11 @@ func (c *ApiController) BatchEnforce() {
permissions := []*object.Permission{}
if modelId != "" {
owner, modelName := util.GetOwnerAndNameFromId(modelId)
owner, modelName, err := util.GetOwnerAndNameFromIdWithError(modelId)
if err != nil {
c.ResponseError(err.Error())
return
}
permissions, err = object.GetPermissionsByModel(owner, modelName)
if err != nil {
c.ResponseError(err.Error())
@@ -271,8 +303,15 @@ func (c *ApiController) BatchEnforce() {
c.ResponseOk(res, keyRes)
}
// GetAllObjects
// @Title GetAllObjects
// @Tag Enforcer API
// @Description Get all objects for a user (Casbin API)
// @Param userId query string false "user id like built-in/admin"
// @Success 200 {object} controllers.Response The Response object
// @router /get-all-objects [get]
func (c *ApiController) GetAllObjects() {
userId := c.Input().Get("userId")
userId := c.Ctx.Input.Query("userId")
if userId == "" {
userId = c.GetSessionUsername()
if userId == "" {
@@ -290,8 +329,15 @@ func (c *ApiController) GetAllObjects() {
c.ResponseOk(objects)
}
// GetAllActions
// @Title GetAllActions
// @Tag Enforcer API
// @Description Get all actions for a user (Casbin API)
// @Param userId query string false "user id like built-in/admin"
// @Success 200 {object} controllers.Response The Response object
// @router /get-all-actions [get]
func (c *ApiController) GetAllActions() {
userId := c.Input().Get("userId")
userId := c.Ctx.Input.Query("userId")
if userId == "" {
userId = c.GetSessionUsername()
if userId == "" {
@@ -309,8 +355,15 @@ func (c *ApiController) GetAllActions() {
c.ResponseOk(actions)
}
// GetAllRoles
// @Title GetAllRoles
// @Tag Enforcer API
// @Description Get all roles for a user (Casbin API)
// @Param userId query string false "user id like built-in/admin"
// @Success 200 {object} controllers.Response The Response object
// @router /get-all-roles [get]
func (c *ApiController) GetAllRoles() {
userId := c.Input().Get("userId")
userId := c.Ctx.Input.Query("userId")
if userId == "" {
userId = c.GetSessionUsername()
if userId == "" {

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"sync"
@@ -38,6 +39,46 @@ var (
cliVersionMutex sync.RWMutex
)
// cleanOldMEIFolders cleans up old _MEIXXX folders from the Casdoor temp directory
// that are older than 24 hours. These folders are created by PyInstaller when
// executing casbin-python-cli and can accumulate over time.
func cleanOldMEIFolders() {
tempDir := "temp"
cutoffTime := time.Now().Add(-24 * time.Hour)
entries, err := os.ReadDir(tempDir)
if err != nil {
// Log error but don't fail - cleanup is best-effort
// This is expected if temp directory doesn't exist yet
return
}
for _, entry := range entries {
// Check if the entry is a directory and matches the _MEI pattern
if !entry.IsDir() || !strings.HasPrefix(entry.Name(), "_MEI") {
continue
}
dirPath := filepath.Join(tempDir, entry.Name())
info, err := entry.Info()
if err != nil {
continue
}
// Check if the folder is older than 24 hours
if info.ModTime().Before(cutoffTime) {
// Try to remove the directory
err = os.RemoveAll(dirPath)
if err != nil {
// Log but continue with other folders
fmt.Printf("failed to remove old MEI folder %s: %v\n", dirPath, err)
} else {
fmt.Printf("removed old MEI folder: %s\n", dirPath)
}
}
}
}
// getCLIVersion
// @Title getCLIVersion
// @Description Get CLI version with cache mechanism
@@ -66,6 +107,9 @@ func getCLIVersion(language string) (string, error) {
}
cliVersionMutex.RUnlock()
// Clean up old _MEI folders before running the command
cleanOldMEIFolders()
cmd := exec.Command(binaryName, "--version")
output, err := cmd.CombinedOutput()
if err != nil {
@@ -125,8 +169,8 @@ func (c *ApiController) RunCasbinCommand() {
return
}
language := c.Input().Get("language")
argString := c.Input().Get("args")
language := c.Ctx.Input.Query("language")
argString := c.Ctx.Input.Query("args")
if language == "" {
language = "go"
@@ -152,6 +196,19 @@ func (c *ApiController) RunCasbinCommand() {
return
}
// Generate cache key for this command
cacheKey, err := generateCacheKey(language, args)
if err != nil {
c.ResponseError(err.Error())
return
}
// Check if result is cached
if cachedOutput, found := getCachedCommandResult(cacheKey); found {
c.ResponseOk(cachedOutput)
return
}
if len(args) > 0 && args[0] == "--version" {
version, err := getCLIVersion(language)
if err != nil {
@@ -173,6 +230,10 @@ func (c *ApiController) RunCasbinCommand() {
return
}
// Clean up old _MEI folders before running the command
// This is especially important for Python CLI which creates these folders
cleanOldMEIFolders()
command := exec.Command(binaryName, processedArgs...)
outputBytes, err := command.CombinedOutput()
if err != nil {
@@ -188,6 +249,10 @@ func (c *ApiController) RunCasbinCommand() {
output := string(outputBytes)
output = strings.TrimSuffix(output, "\n")
// Store result in cache
setCachedCommandResult(cacheKey, output)
c.ResponseOk(output)
}
@@ -197,10 +262,10 @@ func (c *ApiController) RunCasbinCommand() {
// @Param hash string The SHA-256 hash string
// @Return error Returns error if validation fails, nil if successful
func validateIdentifier(c *ApiController) error {
language := c.Input().Get("language")
args := c.Input().Get("args")
hash := c.Input().Get("m")
timestamp := c.Input().Get("t")
language := c.Ctx.Input.Query("language")
args := c.Ctx.Input.Query("args")
hash := c.Ctx.Input.Query("m")
timestamp := c.Ctx.Input.Query("t")
if hash == "" || timestamp == "" || language == "" || args == "" {
return fmt.Errorf("invalid identifier")

View File

@@ -0,0 +1,100 @@
// Copyright 2024 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 controllers
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"sync"
"time"
)
type CommandCacheEntry struct {
Output string
CachedTime time.Time
}
var (
commandCache = make(map[string]*CommandCacheEntry)
commandCacheMutex sync.RWMutex
cacheTTL = 5 * time.Minute
cleanupInProgress = false
cleanupMutex sync.Mutex
)
// generateCacheKey creates a unique cache key based on language and arguments
func generateCacheKey(language string, args []string) (string, error) {
argsJSON, err := json.Marshal(args)
if err != nil {
return "", fmt.Errorf("failed to marshal args: %v", err)
}
data := fmt.Sprintf("%s:%s", language, string(argsJSON))
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:]), nil
}
// cleanExpiredCacheEntries removes expired entries from the cache
func cleanExpiredCacheEntries() {
commandCacheMutex.Lock()
defer commandCacheMutex.Unlock()
for key, entry := range commandCache {
if time.Since(entry.CachedTime) >= cacheTTL {
delete(commandCache, key)
}
}
cleanupMutex.Lock()
cleanupInProgress = false
cleanupMutex.Unlock()
}
// getCachedCommandResult retrieves cached command result if available and not expired
func getCachedCommandResult(cacheKey string) (string, bool) {
commandCacheMutex.RLock()
defer commandCacheMutex.RUnlock()
if entry, exists := commandCache[cacheKey]; exists {
if time.Since(entry.CachedTime) < cacheTTL {
return entry.Output, true
}
}
return "", false
}
// setCachedCommandResult stores command result in cache and performs periodic cleanup
func setCachedCommandResult(cacheKey string, output string) {
commandCacheMutex.Lock()
commandCache[cacheKey] = &CommandCacheEntry{
Output: output,
CachedTime: time.Now(),
}
shouldCleanup := len(commandCache)%100 == 0
commandCacheMutex.Unlock()
// Periodically clean expired entries (every 100 cache sets)
if shouldCleanup {
cleanupMutex.Lock()
if !cleanupInProgress {
cleanupInProgress = true
cleanupMutex.Unlock()
go cleanExpiredCacheEntries()
} else {
cleanupMutex.Unlock()
}
}
}

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Cert The Response object
// @router /get-certs [get]
func (c *ApiController) GetCerts() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
certs, err := object.GetMaskedCerts(object.GetCerts(owner))
@@ -54,7 +54,7 @@ func (c *ApiController) GetCerts() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
certs, err := object.GetMaskedCerts(object.GetPaginationCerts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder))
if err != nil {
c.ResponseError(err.Error())
@@ -72,12 +72,12 @@ func (c *ApiController) GetCerts() {
// @Success 200 {array} object.Cert The Response object
// @router /get-global-certs [get]
func (c *ApiController) GetGlobalCerts() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
certs, err := object.GetMaskedCerts(object.GetGlobalCerts())
@@ -95,7 +95,7 @@ func (c *ApiController) GetGlobalCerts() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
certs, err := object.GetMaskedCerts(object.GetPaginationGlobalCerts(paginator.Offset(), limit, field, value, sortField, sortOrder))
if err != nil {
c.ResponseError(err.Error())
@@ -114,7 +114,7 @@ func (c *ApiController) GetGlobalCerts() {
// @Success 200 {object} object.Cert The Response object
// @router /get-cert [get]
func (c *ApiController) GetCert() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
cert, err := object.GetCert(id)
if err != nil {
c.ResponseError(err.Error())
@@ -133,7 +133,7 @@ func (c *ApiController) GetCert() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-cert [post]
func (c *ApiController) UpdateCert() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var cert object.Cert
err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert)

View File

@@ -15,7 +15,7 @@ import (
"strings"
"time"
"github.com/beego/beego"
"github.com/beego/beego/v2/server/web"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/util"
)
@@ -24,6 +24,8 @@ const (
javaCliRepo = "https://api.github.com/repos/jcasbin/casbin-java-cli/releases/latest"
goCliRepo = "https://api.github.com/repos/casbin/casbin-go-cli/releases/latest"
rustCliRepo = "https://api.github.com/repos/casbin-rs/casbin-rust-cli/releases/latest"
pythonCliRepo = "https://api.github.com/repos/casbin/casbin-python-cli/releases/latest"
dotnetCliRepo = "https://api.github.com/repos/casbin-net/casbin-dotnet-cli/releases/latest"
downloadFolder = "bin"
)
@@ -43,6 +45,8 @@ func getBinaryNames() map[string]string {
golang = "go"
java = "java"
rust = "rust"
python = "python"
dotnet = "dotnet"
)
arch := runtime.GOARCH
@@ -62,18 +66,24 @@ func getBinaryNames() map[string]string {
golang: fmt.Sprintf("casbin-go-cli_Windows_%s.zip", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-pc-windows-gnu", archNames.rustArch),
python: fmt.Sprintf("casbin-python-cli-windows-%s.exe", archNames.goArch),
dotnet: fmt.Sprintf("casbin-dotnet-cli-windows-%s.exe", archNames.goArch),
}
case "darwin":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Darwin_%s.tar.gz", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-apple-darwin", archNames.rustArch),
python: fmt.Sprintf("casbin-python-cli-darwin-%s", archNames.goArch),
dotnet: fmt.Sprintf("casbin-dotnet-cli-darwin-%s", archNames.goArch),
}
case "linux":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Linux_%s.tar.gz", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-unknown-linux-gnu", archNames.rustArch),
python: fmt.Sprintf("casbin-python-cli-linux-%s", archNames.goArch),
dotnet: fmt.Sprintf("casbin-dotnet-cli-linux-%s", archNames.goArch),
}
default:
return nil
@@ -98,6 +108,16 @@ func getFinalBinaryName(lang string) string {
return "casbin-rust-cli.exe"
}
return "casbin-rust-cli"
case "python":
if runtime.GOOS == "windows" {
return "casbin-python-cli.exe"
}
return "casbin-python-cli"
case "dotnet":
if runtime.GOOS == "windows" {
return "casbin-dotnet-cli.exe"
}
return "casbin-dotnet-cli"
default:
return ""
}
@@ -333,9 +353,11 @@ func downloadCLI() error {
}
repos := map[string]string{
"java": javaCliRepo,
"go": goCliRepo,
"rust": rustCliRepo,
"java": javaCliRepo,
"go": goCliRepo,
"rust": rustCliRepo,
"python": pythonCliRepo,
"dotnet": dotnetCliRepo,
}
for lang, repo := range repos {
@@ -424,13 +446,13 @@ func downloadCLI() error {
// @Success 200 {object} controllers.Response The Response object
// @router /refresh-engines [post]
func (c *ApiController) RefreshEngines() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
if !web.AppConfig.DefaultBool("isDemoMode", false) {
c.ResponseError("refresh engines is only available in demo mode")
return
}
hash := c.Input().Get("m")
timestamp := c.Input().Get("t")
hash := c.Ctx.Input.Query("m")
timestamp := c.Ctx.Input.Query("t")
if hash == "" || timestamp == "" {
c.ResponseError("invalid identifier")
@@ -476,7 +498,7 @@ func (c *ApiController) RefreshEngines() {
// @Title ScheduleCLIUpdater
// @Description Start periodic CLI update scheduler
func ScheduleCLIUpdater() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
if !web.AppConfig.DefaultBool("isDemoMode", false) {
return
}
@@ -504,7 +526,7 @@ func DownloadCLI() error {
// @Title InitCLIDownloader
// @Description Initialize CLI downloader and start update scheduler
func InitCLIDownloader() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
if !web.AppConfig.DefaultBool("isDemoMode", false) {
return
}

View File

@@ -18,7 +18,7 @@ import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
@@ -32,13 +32,13 @@ import (
// @Success 200 {array} object.Enforcer
// @router /get-enforcers [get]
func (c *ApiController) GetEnforcers() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
enforcers, err := object.GetEnforcers(owner)
@@ -56,7 +56,7 @@ func (c *ApiController) GetEnforcers() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
enforcers, err := object.GetPaginationEnforcers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -75,8 +75,8 @@ func (c *ApiController) GetEnforcers() {
// @Success 200 {object} object.Enforcer
// @router /get-enforcer [get]
func (c *ApiController) GetEnforcer() {
id := c.Input().Get("id")
loadModelCfg := c.Input().Get("loadModelCfg")
id := c.Ctx.Input.Query("id")
loadModelCfg := c.Ctx.Input.Query("loadModelCfg")
enforcer, err := object.GetEnforcer(id)
if err != nil {
@@ -84,10 +84,12 @@ func (c *ApiController) GetEnforcer() {
return
}
if loadModelCfg == "true" && enforcer.Model != "" {
err := enforcer.LoadModelCfg()
if err != nil {
return
if enforcer != nil {
if loadModelCfg == "true" && enforcer.Model != "" {
err = enforcer.LoadModelCfg()
if err != nil {
return
}
}
}
@@ -103,7 +105,7 @@ func (c *ApiController) GetEnforcer() {
// @Success 200 {object} object.Enforcer
// @router /update-enforcer [post]
func (c *ApiController) UpdateEnforcer() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
enforcer := object.Enforcer{}
err := json.Unmarshal(c.Ctx.Input.RequestBody, &enforcer)
@@ -154,9 +156,17 @@ func (c *ApiController) DeleteEnforcer() {
c.ServeJSON()
}
// GetPolicies
// @Title GetPolicies
// @Tag Enforcer API
// @Description get policies
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Param adapterId query string false "The adapter id"
// @Success 200 {array} xormadapter.CasbinRule
// @router /get-policies [get]
func (c *ApiController) GetPolicies() {
id := c.Input().Get("id")
adapterId := c.Input().Get("adapterId")
id := c.Ctx.Input.Query("id")
adapterId := c.Ctx.Input.Query("adapterId")
if adapterId != "" {
adapter, err := object.GetAdapter(adapterId)
@@ -188,8 +198,43 @@ func (c *ApiController) GetPolicies() {
c.ResponseOk(policies)
}
// GetFilteredPolicies
// @Title GetFilteredPolicies
// @Tag Enforcer API
// @Description get filtered policies with support for multiple filters via POST body
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Param body body []object.Filter true "Array of filter objects for multiple filters"
// @Success 200 {array} xormadapter.CasbinRule
// @router /get-filtered-policies [post]
func (c *ApiController) GetFilteredPolicies() {
id := c.Ctx.Input.Query("id")
var filters []object.Filter
err := json.Unmarshal(c.Ctx.Input.RequestBody, &filters)
if err != nil {
c.ResponseError(err.Error())
return
}
filteredPolicies, err := object.GetFilteredPoliciesMulti(id, filters)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(filteredPolicies)
}
// UpdatePolicy
// @Title UpdatePolicy
// @Tag Enforcer API
// @Description update policy
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Param body body []xormadapter.CasbinRule true "Array containing old and new policy"
// @Success 200 {object} Response
// @router /update-policy [post]
func (c *ApiController) UpdatePolicy() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var policies []xormadapter.CasbinRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policies)
@@ -207,8 +252,16 @@ func (c *ApiController) UpdatePolicy() {
c.ServeJSON()
}
// AddPolicy
// @Title AddPolicy
// @Tag Enforcer API
// @Description add policy
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Param body body xormadapter.CasbinRule true "The policy to add"
// @Success 200 {object} Response
// @router /add-policy [post]
func (c *ApiController) AddPolicy() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var policy xormadapter.CasbinRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)
@@ -226,8 +279,16 @@ func (c *ApiController) AddPolicy() {
c.ServeJSON()
}
// RemovePolicy
// @Title RemovePolicy
// @Tag Enforcer API
// @Description remove policy
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Param body body xormadapter.CasbinRule true "The policy to remove"
// @Success 200 {object} Response
// @router /remove-policy [post]
func (c *ApiController) RemovePolicy() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var policy xormadapter.CasbinRule
err := json.Unmarshal(c.Ctx.Input.RequestBody, &policy)

View File

@@ -33,8 +33,8 @@ import (
// @Success 200 {object} controllers.Response The Response object
// @router /faceid-signin-begin [get]
func (c *ApiController) FaceIDSigninBegin() {
userOwner := c.Input().Get("owner")
userName := c.Input().Get("name")
userOwner := c.Ctx.Input.Query("owner")
userName := c.Ctx.Input.Query("name")
user, err := object.GetUserByFields(userOwner, userName)
if err != nil {

175
controllers/form.go Normal file
View File

@@ -0,0 +1,175 @@
// 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 controllers
import (
"encoding/json"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetGlobalForms
// @Title GetGlobalForms
// @Tag Form API
// @Description get global forms
// @Success 200 {array} object.Form The Response object
// @router /get-global-forms [get]
func (c *ApiController) GetGlobalForms() {
forms, err := object.GetGlobalForms()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedForms(forms, true))
}
// GetForms
// @Title GetForms
// @Tag Form API
// @Description get forms
// @Param owner query string true "The owner of form"
// @Success 200 {array} object.Form The Response object
// @router /get-forms [get]
func (c *ApiController) GetForms() {
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
forms, err := object.GetForms(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedForms(forms, true))
} else {
limit := util.ParseInt(limit)
count, err := object.GetFormCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
forms, err := object.GetPaginationForms(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(forms, paginator.Nums())
}
}
// GetForm
// @Title GetForm
// @Tag Form API
// @Description get form
// @Param id query string true "The id (owner/name) of form"
// @Success 200 {object} object.Form The Response object
// @router /get-form [get]
func (c *ApiController) GetForm() {
id := c.Ctx.Input.Query("id")
form, err := object.GetForm(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedForm(form, true))
}
// UpdateForm
// @Title UpdateForm
// @Tag Form API
// @Description update form
// @Param id query string true "The id (owner/name) of the form"
// @Param body body object.Form true "The details of the form"
// @Success 200 {object} controllers.Response The Response object
// @router /update-form [post]
func (c *ApiController) UpdateForm() {
id := c.Ctx.Input.Query("id")
var form object.Form
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateForm(id, &form)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
// AddForm
// @Title AddForm
// @Tag Form API
// @Description add form
// @Param body body object.Form true "The details of the form"
// @Success 200 {object} controllers.Response The Response object
// @router /add-form [post]
func (c *ApiController) AddForm() {
var form object.Form
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.AddForm(&form)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
// DeleteForm
// @Title DeleteForm
// @Tag Form API
// @Description delete form
// @Param body body object.Form true "The details of the form"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-form [post]
func (c *ApiController) DeleteForm() {
var form object.Form
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteForm(&form)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@@ -23,7 +23,7 @@ import "github.com/casdoor/casdoor/object"
// @Success 200 {object} controllers.Response The Response object
// @router /get-dashboard [get]
func (c *ApiController) GetDashboard() {
owner := c.Input().Get("owner")
owner := c.Ctx.Input.Query("owner")
data, err := object.GetDashboard(owner)
if err != nil {

View File

@@ -17,7 +17,7 @@ import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,14 +30,14 @@ import (
// @Success 200 {array} object.Group The Response object
// @router /get-groups [get]
func (c *ApiController) GetGroups() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
withTree := c.Input().Get("withTree")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
withTree := c.Ctx.Input.Query("withTree")
if limit == "" || page == "" {
groups, err := object.GetGroups(owner)
@@ -66,7 +66,7 @@ func (c *ApiController) GetGroups() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
groups, err := object.GetPaginationGroups(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -109,7 +109,7 @@ func (c *ApiController) GetGroups() {
// @Success 200 {object} object.Group The Response object
// @router /get-group [get]
func (c *ApiController) GetGroup() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
group, err := object.GetGroup(id)
if err != nil {
@@ -135,7 +135,7 @@ func (c *ApiController) GetGroup() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-group [post]
func (c *ApiController) UpdateGroup() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var group object.Group
err := json.Unmarshal(c.Ctx.Input.RequestBody, &group)

View File

@@ -24,7 +24,11 @@ import (
func (c *ApiController) UploadGroups() {
userId := c.GetSessionUsername()
owner, user := util.GetOwnerAndNameFromId(userId)
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {

View File

@@ -16,8 +16,10 @@ package controllers
import (
"encoding/json"
"fmt"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +32,13 @@ import (
// @Success 200 {array} object.Invitation The Response object
// @router /get-invitations [get]
func (c *ApiController) GetInvitations() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
invitations, err := object.GetInvitations(owner)
@@ -54,7 +56,7 @@ func (c *ApiController) GetInvitations() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
invitations, err := object.GetPaginationInvitations(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,7 +75,7 @@ func (c *ApiController) GetInvitations() {
// @Success 200 {object} object.Invitation The Response object
// @router /get-invitation [get]
func (c *ApiController) GetInvitation() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
invitation, err := object.GetInvitation(id)
if err != nil {
@@ -92,14 +94,18 @@ func (c *ApiController) GetInvitation() {
// @Success 200 {object} object.Invitation The Response object
// @router /get-invitation-info [get]
func (c *ApiController) GetInvitationCodeInfo() {
code := c.Input().Get("code")
applicationId := c.Input().Get("applicationId")
code := c.Ctx.Input.Query("code")
applicationId := c.Ctx.Input.Query("applicationId")
application, err := object.GetApplication(applicationId)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), applicationId))
return
}
invitation, msg := object.GetInvitationByCode(code, application.Organization, c.GetAcceptLanguage())
if msg != "" {
@@ -119,7 +125,7 @@ func (c *ApiController) GetInvitationCodeInfo() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-invitation [post]
func (c *ApiController) UpdateInvitation() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var invitation object.Invitation
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
@@ -178,7 +184,7 @@ func (c *ApiController) DeleteInvitation() {
// @Success 200 {object} controllers.Response The Response object
// @router /verify-invitation [get]
func (c *ApiController) VerifyInvitation() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
payment, attachInfo, err := object.VerifyInvitation(id)
if err != nil {
@@ -188,3 +194,90 @@ func (c *ApiController) VerifyInvitation() {
c.ResponseOk(payment, attachInfo)
}
// SendInvitation
// @Title VerifyInvitation
// @Tag Invitation API
// @Description verify invitation
// @Param id query string true "The id ( owner/name ) of the invitation"
// @Param body body []string true "The details of the invitation"
// @Success 200 {object} controllers.Response The Response object
// @router /send-invitation [post]
func (c *ApiController) SendInvitation() {
id := c.Ctx.Input.Query("id")
var destinations []string
err := json.Unmarshal(c.Ctx.Input.RequestBody, &destinations)
if !c.IsAdmin() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
invitation, err := object.GetInvitation(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if invitation == nil {
c.ResponseError(fmt.Sprintf(c.T("invitation:Invitation %s does not exist"), id))
return
}
organization, err := object.GetOrganization(fmt.Sprintf("admin/%s", invitation.Owner))
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s does not exist"), invitation.Owner))
return
}
var application *object.Application
if invitation.Application != "" {
application, err = object.GetApplication(fmt.Sprintf("admin/%s-org-%s", invitation.Application, invitation.Owner))
if err != nil {
c.ResponseError(err.Error())
return
}
} else {
application, err = object.GetApplicationByOrganizationName(invitation.Owner)
if err != nil {
c.ResponseError(err.Error())
return
}
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The organization: %s should have one application at least"), invitation.Owner))
return
}
if application.IsShared {
application.Name = fmt.Sprintf("%s-org-%s", application.Name, invitation.Owner)
}
provider, err := application.GetEmailProvider("Invitation")
if err != nil {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("verification:please add an Email provider to the \"Providers\" list for the application: %s"), invitation.Owner))
return
}
content := provider.Metadata
content = strings.ReplaceAll(content, "%code", invitation.Code)
content = strings.ReplaceAll(content, "%link", invitation.GetInvitationLink(c.Ctx.Request.Host, application.Name))
err = object.SendEmail(provider, provider.Title, content, destinations, organization.DisplayName)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk()
}

View File

@@ -16,6 +16,7 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
@@ -45,14 +46,22 @@ type LdapSyncResp struct {
// @Success 200 {object} controllers.LdapResp The Response object
// @router /get-ldap-users [get]
func (c *ApiController) GetLdapUsers() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
_, ldapId := util.GetOwnerAndNameFromId(id)
_, ldapId, err := util.GetOwnerAndNameFromIdWithError(id)
if err != nil {
c.ResponseError(err.Error())
return
}
ldapServer, err := object.GetLdap(ldapId)
if err != nil {
c.ResponseError(err.Error())
return
}
if ldapServer == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The LDAP: %s does not exist"), ldapId))
return
}
conn, err := ldapServer.GetLdapConn()
if err != nil {
@@ -105,7 +114,7 @@ func (c *ApiController) GetLdapUsers() {
// @Success 200 {array} object.Ldap The Response object
// @router /get-ldaps [get]
func (c *ApiController) GetLdaps() {
owner := c.Input().Get("owner")
owner := c.Ctx.Input.Query("owner")
c.ResponseOk(object.GetMaskedLdaps(object.GetLdaps(owner)))
}
@@ -118,14 +127,18 @@ func (c *ApiController) GetLdaps() {
// @Success 200 {object} object.Ldap The Response object
// @router /get-ldap [get]
func (c *ApiController) GetLdap() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
if util.IsStringsEmpty(id) {
c.ResponseError(c.T("general:Missing parameter"))
return
}
_, name := util.GetOwnerAndNameFromId(id)
_, name, err := util.GetOwnerAndNameFromIdWithError(id)
if err != nil {
c.ResponseError(err.Error())
return
}
ldap, err := object.GetLdap(name)
if err != nil {
c.ResponseError(err.Error())
@@ -253,11 +266,15 @@ func (c *ApiController) DeleteLdap() {
// @Success 200 {object} controllers.LdapSyncResp The Response object
// @router /sync-ldap-users [post]
func (c *ApiController) SyncLdapUsers() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
owner, ldapId := util.GetOwnerAndNameFromId(id)
owner, ldapId, err := util.GetOwnerAndNameFromIdWithError(id)
if err != nil {
c.ResponseError(err.Error())
return
}
var users []object.LdapUser
err := json.Unmarshal(c.Ctx.Input.RequestBody, &users)
err = json.Unmarshal(c.Ctx.Input.RequestBody, &users)
if err != nil {
c.ResponseError(err.Error())
return

View File

@@ -58,7 +58,20 @@ func (c *ApiController) MfaSetupInitiate() {
return
}
mfaProps, err := MfaUtil.Initiate(user.GetId())
organization, err := object.GetOrganizationByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
issuer := ""
if organization != nil && organization.DisplayName != "" {
issuer = organization.DisplayName
} else if organization != nil {
issuer = organization.Name
}
mfaProps, err := MfaUtil.Initiate(user.GetId(), issuer)
if err != nil {
c.ResponseError(err.Error())
return
@@ -66,6 +79,7 @@ func (c *ApiController) MfaSetupInitiate() {
recoveryCode := uuid.NewString()
mfaProps.RecoveryCodes = []string{recoveryCode}
mfaProps.MfaRememberInHours = organization.MfaRememberInHours
resp := mfaProps
c.ResponseOk(resp)
@@ -117,6 +131,28 @@ func (c *ApiController) MfaSetupVerify() {
return
}
config.Secret = dest
} else if mfaType == object.RadiusType {
if dest == "" {
c.ResponseError("RADIUS username is missing")
return
}
config.Secret = dest
if secret == "" {
c.ResponseError("RADIUS provider is missing")
return
}
config.URL = secret
} else if mfaType == object.PushType {
if dest == "" {
c.ResponseError("push notification receiver is missing")
return
}
config.Secret = dest
if secret == "" {
c.ResponseError("push notification provider is missing")
return
}
config.URL = secret
}
mfaUtil := object.GetMfaUtil(mfaType, config)
@@ -193,6 +229,28 @@ func (c *ApiController) MfaSetupEnable() {
}
user.CountryCode = countryCode
}
} else if mfaType == object.RadiusType {
if dest == "" {
c.ResponseError("RADIUS username is missing")
return
}
config.Secret = dest
if secret == "" {
c.ResponseError("RADIUS provider is missing")
return
}
config.URL = secret
} else if mfaType == object.PushType {
if dest == "" {
c.ResponseError("push notification receiver is missing")
return
}
config.Secret = dest
if secret == "" {
c.ResponseError("push notification provider is missing")
return
}
config.URL = secret
}
if recoveryCodes == "" {

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Model The Response object
// @router /get-models [get]
func (c *ApiController) GetModels() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
models, err := object.GetModels(owner)
@@ -54,7 +54,7 @@ func (c *ApiController) GetModels() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
models, err := object.GetPaginationModels(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,7 +73,7 @@ func (c *ApiController) GetModels() {
// @Success 200 {object} object.Model The Response object
// @router /get-model [get]
func (c *ApiController) GetModel() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
model, err := object.GetModel(id)
if err != nil {
@@ -93,7 +93,7 @@ func (c *ApiController) GetModel() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-model [post]
func (c *ApiController) UpdateModel() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var model object.Model
err := json.Unmarshal(c.Ctx.Input.RequestBody, &model)

74
controllers/oauth_dcr.go Normal file
View File

@@ -0,0 +1,74 @@
// Copyright 2026 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 controllers
import (
"encoding/json"
"net/http"
"github.com/casdoor/casdoor/object"
)
// DynamicClientRegister
// @Title DynamicClientRegister
// @Tag OAuth API
// @Description Register a new OAuth 2.0 client dynamically (RFC 7591)
// @Param organization query string false "The organization name (defaults to built-in)"
// @Param body body object.DynamicClientRegistrationRequest true "Client registration request"
// @Success 201 {object} object.DynamicClientRegistrationResponse
// @Failure 400 {object} object.DcrError
// @router /api/oauth/register [post]
func (c *ApiController) DynamicClientRegister() {
var req object.DynamicClientRegistrationRequest
err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
if err != nil {
c.Ctx.Output.Status = http.StatusBadRequest
c.Data["json"] = object.DcrError{
Error: "invalid_client_metadata",
ErrorDescription: "invalid request body: " + err.Error(),
}
c.ServeJSON()
return
}
// Get organization from query parameter or default to built-in
organization := c.Ctx.Input.Query("organization")
if organization == "" {
organization = "built-in"
}
// Register the client
response, dcrErr, err := object.RegisterDynamicClient(&req, organization)
if err != nil {
c.Ctx.Output.Status = http.StatusInternalServerError
c.Data["json"] = object.DcrError{
Error: "server_error",
ErrorDescription: err.Error(),
}
c.ServeJSON()
return
}
if dcrErr != nil {
c.Ctx.Output.Status = http.StatusBadRequest
c.Data["json"] = dcrErr
c.ServeJSON()
return
}
// Return 201 Created
c.Ctx.Output.Status = http.StatusCreated
c.Data["json"] = response
c.ServeJSON()
}

View File

@@ -1,76 +0,0 @@
// 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.
package controllers
import (
"strings"
"github.com/casdoor/casdoor/object"
)
// GetOidcDiscovery
// @Title GetOidcDiscovery
// @Tag OIDC API
// @Description Get Oidc Discovery
// @Success 200 {object} object.OidcDiscovery
// @router /.well-known/openid-configuration [get]
func (c *RootController) GetOidcDiscovery() {
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOidcDiscovery(host)
c.ServeJSON()
}
// GetJwks
// @Title GetJwks
// @Tag OIDC API
// @Success 200 {object} jose.JSONWebKey
// @router /.well-known/jwks [get]
func (c *RootController) GetJwks() {
jwks, err := object.GetJsonWebKeySet()
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = jwks
c.ServeJSON()
}
// GetWebFinger
// @Title GetWebFinger
// @Tag OIDC API
// @Param resource query string true "resource"
// @Success 200 {object} object.WebFinger
// @router /.well-known/webfinger [get]
func (c *RootController) GetWebFinger() {
resource := c.Input().Get("resource")
rels := []string{}
host := c.Ctx.Request.Host
for key, value := range c.Input() {
if strings.HasPrefix(key, "rel") {
rels = append(rels, value...)
}
}
webfinger, err := object.GetWebFinger(resource, rels, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = webfinger
c.Ctx.Output.ContentType("application/jrd+json")
c.ServeJSON()
}

195
controllers/order.go Normal file
View File

@@ -0,0 +1,195 @@
// 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 controllers
import (
"encoding/json"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetOrders
// @Title GetOrders
// @Tag Order API
// @Description get orders
// @Param owner query string true "The owner of orders"
// @Success 200 {array} object.Order The Response object
// @router /get-orders [get]
func (c *ApiController) GetOrders() {
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
var orders []*object.Order
var err error
if c.IsAdmin() {
// If field is "user", filter by that user even for admins
if field == "user" && value != "" {
orders, err = object.GetUserOrders(owner, value)
} else {
orders, err = object.GetOrders(owner)
}
} else {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
orders, err = object.GetUserOrders(owner, userName)
}
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(orders)
} else {
limit := util.ParseInt(limit)
if !c.IsAdmin() {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
field = "user"
value = userName
}
count, err := object.GetOrderCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
orders, err := object.GetPaginationOrders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(orders, paginator.Nums())
}
}
// GetUserOrders
// @Title GetUserOrders
// @Tag Order API
// @Description get orders for a user
// @Param owner query string true "The owner of orders"
// @Param user query string true "The username of the user"
// @Success 200 {array} object.Order The Response object
// @router /get-user-orders [get]
func (c *ApiController) GetUserOrders() {
owner := c.Ctx.Input.Query("owner")
user := c.Ctx.Input.Query("user")
orders, err := object.GetUserOrders(owner, user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(orders)
}
// GetOrder
// @Title GetOrder
// @Tag Order API
// @Description get order
// @Param id query string true "The id ( owner/name ) of the order"
// @Success 200 {object} object.Order The Response object
// @router /get-order [get]
func (c *ApiController) GetOrder() {
id := c.Ctx.Input.Query("id")
order, err := object.GetOrder(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(order)
}
// UpdateOrder
// @Title UpdateOrder
// @Tag Order API
// @Description update order
// @Param id query string true "The id ( owner/name ) of the order"
// @Param body body object.Order true "The details of the order"
// @Success 200 {object} controllers.Response The Response object
// @router /update-order [post]
func (c *ApiController) UpdateOrder() {
id := c.Ctx.Input.Query("id")
var order object.Order
err := json.Unmarshal(c.Ctx.Input.RequestBody, &order)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateOrder(id, &order))
c.ServeJSON()
}
// AddOrder
// @Title AddOrder
// @Tag Order API
// @Description add order
// @Param body body object.Order true "The details of the order"
// @Success 200 {object} controllers.Response The Response object
// @router /add-order [post]
func (c *ApiController) AddOrder() {
var order object.Order
err := json.Unmarshal(c.Ctx.Input.RequestBody, &order)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddOrder(&order))
c.ServeJSON()
}
// DeleteOrder
// @Title DeleteOrder
// @Tag Order API
// @Description delete order
// @Param body body object.Order true "The details of the order"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-order [post]
func (c *ApiController) DeleteOrder() {
var order object.Order
err := json.Unmarshal(c.Ctx.Input.RequestBody, &order)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteOrder(&order))
c.ServeJSON()
}

160
controllers/order_pay.go Normal file
View File

@@ -0,0 +1,160 @@
// 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 controllers
import (
"encoding/json"
"fmt"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// PlaceOrder
// @Title PlaceOrder
// @Tag Order API
// @Description place an order for a product
// @Param productId query string true "The id ( owner/name ) of the product"
// @Param pricingName query string false "The name of the pricing (for subscription)"
// @Param planName query string false "The name of the plan (for subscription)"
// @Param customPrice query number false "Custom price for recharge products"
// @Param userName query string false "The username to place order for (admin only)"
// @Success 200 {object} object.Order The Response object
// @router /place-order [post]
func (c *ApiController) PlaceOrder() {
owner := c.Ctx.Input.Query("owner")
paidUserName := c.Ctx.Input.Query("userName")
var req struct {
ProductInfos []object.ProductInfo `json:"productInfos"`
}
err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
if err != nil {
c.ResponseError(err.Error())
return
}
productInfos := req.ProductInfos
if len(productInfos) == 0 {
c.ResponseError(c.T("product:Product list cannot be empty"))
return
}
var userId string
if paidUserName != "" {
userId = util.GetId(owner, paidUserName)
if userId != c.GetSessionUsername() && !c.IsAdmin() && userId != c.GetPaidUsername() {
c.ResponseError(c.T("general:Only admin user can specify user"))
return
}
c.SetSession("paidUsername", "")
} else {
userId = c.GetSessionUsername()
}
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return
}
order, err := object.PlaceOrder(owner, productInfos, user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(order)
}
// PayOrder
// @Title PayOrder
// @Tag Order API
// @Description pay an existing order
// @Param id query string true "The id ( owner/name ) of the order"
// @Param providerName query string true "The name of the provider"
// @Success 200 {object} controllers.Response The Response object
// @router /pay-order [post]
func (c *ApiController) PayOrder() {
id := c.Ctx.Input.Query("id")
host := c.Ctx.Request.Host
providerName := c.Ctx.Input.Query("providerName")
paymentEnv := c.Ctx.Input.Query("paymentEnv")
order, err := object.GetOrder(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if order == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The order: %s does not exist"), id))
return
}
userId := c.GetSessionUsername()
orderUserId := util.GetId(order.Owner, order.User)
if userId != orderUserId && !c.IsAdmin() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
payment, attachInfo, err := object.PayOrder(providerName, host, paymentEnv, order, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payment, attachInfo)
}
// CancelOrder
// @Title CancelOrder
// @Tag Order API
// @Description cancel an order
// @Param id query string true "The id ( owner/name ) of the order"
// @Success 200 {object} controllers.Response The Response object
// @router /cancel-order [post]
func (c *ApiController) CancelOrder() {
id := c.Ctx.Input.Query("id")
order, err := object.GetOrder(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if order == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The order: %s does not exist"), id))
return
}
userId := c.GetSessionUsername()
orderUserId := util.GetId(order.Owner, order.User)
if userId != orderUserId && !c.IsAdmin() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
c.Data["json"] = wrapActionResponse(object.CancelOrder(order))
c.ServeJSON()
}

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,14 +30,14 @@ import (
// @Success 200 {array} object.Organization The Response object
// @router /get-organizations [get]
func (c *ApiController) GetOrganizations() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organizationName := c.Input().Get("organizationName")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
organizationName := c.Ctx.Input.Query("organizationName")
isGlobalAdmin := c.IsGlobalAdmin()
if limit == "" || page == "" {
@@ -71,7 +71,7 @@ func (c *ApiController) GetOrganizations() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
organizations, err := object.GetMaskedOrganizations(object.GetPaginationOrganizations(owner, organizationName, paginator.Offset(), limit, field, value, sortField, sortOrder))
if err != nil {
c.ResponseError(err.Error())
@@ -91,13 +91,17 @@ func (c *ApiController) GetOrganizations() {
// @Success 200 {object} object.Organization The Response object
// @router /get-organization [get]
func (c *ApiController) GetOrganization() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
organization, err := object.GetMaskedOrganization(object.GetOrganization(id))
if err != nil {
c.ResponseError(err.Error())
return
}
if organization != nil && organization.MfaRememberInHours == 0 {
organization.MfaRememberInHours = 12
}
c.ResponseOk(organization)
}
@@ -110,7 +114,7 @@ func (c *ApiController) GetOrganization() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-organization [post]
func (c *ApiController) UpdateOrganization() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var organization object.Organization
err := json.Unmarshal(c.Ctx.Input.RequestBody, &organization)
@@ -126,6 +130,10 @@ func (c *ApiController) UpdateOrganization() {
isGlobalAdmin, _ := c.isGlobalAdmin()
if organization.BalanceCurrency == "" {
organization.BalanceCurrency = "USD"
}
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization, isGlobalAdmin))
c.ServeJSON()
}
@@ -161,6 +169,10 @@ func (c *ApiController) AddOrganization() {
return
}
if organization.BalanceCurrency == "" {
organization.BalanceCurrency = "USD"
}
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
c.ServeJSON()
}
@@ -193,7 +205,7 @@ func (c *ApiController) DeleteOrganization() {
// @router /get-default-application [get]
func (c *ApiController) GetDefaultApplication() {
userId := c.GetSessionUsername()
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
application, err := object.GetDefaultApplication(id)
if err != nil {
@@ -213,7 +225,7 @@ func (c *ApiController) GetDefaultApplication() {
// @Success 200 {array} object.Organization The Response object
// @router /get-organization-names [get]
func (c *ApiController) GetOrganizationNames() {
owner := c.Input().Get("owner")
owner := c.Ctx.Input.Query("owner")
organizationNames, err := object.GetOrganizationsByFields(owner, []string{"name", "display_name"}...)
if err != nil {
c.ResponseError(err.Error())

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,16 +30,35 @@ import (
// @Success 200 {array} object.Payment The Response object
// @router /get-payments [get]
func (c *ApiController) GetPayments() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
payments, err := object.GetPayments(owner)
var payments []*object.Payment
var err error
if c.IsAdmin() {
// If field is "user", filter by that user even for admins
if field == "user" && value != "" {
payments, err = object.GetUserPayments(owner, value)
} else {
payments, err = object.GetPayments(owner)
}
} else {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
payments, err = object.GetUserPayments(owner, userName)
}
if err != nil {
c.ResponseError(err.Error())
return
@@ -48,13 +67,23 @@ func (c *ApiController) GetPayments() {
c.ResponseOk(payments)
} else {
limit := util.ParseInt(limit)
if !c.IsAdmin() {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
field = "user"
value = userName
}
count, err := object.GetPaymentCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
payments, err := object.GetPaginationPayments(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -75,8 +104,8 @@ func (c *ApiController) GetPayments() {
// @Success 200 {array} object.Payment The Response object
// @router /get-user-payments [get]
func (c *ApiController) GetUserPayments() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
owner := c.Ctx.Input.Query("owner")
user := c.Ctx.Input.Query("user")
payments, err := object.GetUserPayments(owner, user)
if err != nil {
@@ -95,7 +124,7 @@ func (c *ApiController) GetUserPayments() {
// @Success 200 {object} object.Payment The Response object
// @router /get-payment [get]
func (c *ApiController) GetPayment() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
payment, err := object.GetPayment(id)
if err != nil {
@@ -115,7 +144,7 @@ func (c *ApiController) GetPayment() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-payment [post]
func (c *ApiController) UpdatePayment() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var payment object.Payment
err := json.Unmarshal(c.Ctx.Input.RequestBody, &payment)
@@ -179,7 +208,7 @@ func (c *ApiController) NotifyPayment() {
body := c.Ctx.Input.RequestBody
payment, err := object.NotifyPayment(body, owner, paymentName)
payment, err := object.NotifyPayment(body, owner, paymentName, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@@ -196,7 +225,7 @@ func (c *ApiController) NotifyPayment() {
// @Success 200 {object} controllers.Response The Response object
// @router /invoice-payment [post]
func (c *ApiController) InvoicePayment() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
payment, err := object.GetPayment(id)
if err != nil {

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Permission The Response object
// @router /get-permissions [get]
func (c *ApiController) GetPermissions() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
permissions, err := object.GetPermissions(owner)
@@ -54,7 +54,7 @@ func (c *ApiController) GetPermissions() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
permissions, err := object.GetPaginationPermissions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -94,7 +94,7 @@ func (c *ApiController) GetPermissionsBySubmitter() {
// @Success 200 {array} object.Permission The Response object
// @router /get-permissions-by-role [get]
func (c *ApiController) GetPermissionsByRole() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
permissions, err := object.GetPermissionsByRole(id)
if err != nil {
c.ResponseError(err.Error())
@@ -112,7 +112,7 @@ func (c *ApiController) GetPermissionsByRole() {
// @Success 200 {object} object.Permission The Response object
// @router /get-permission [get]
func (c *ApiController) GetPermission() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
permission, err := object.GetPermission(id)
if err != nil {
@@ -132,7 +132,7 @@ func (c *ApiController) GetPermission() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-permission [post]
func (c *ApiController) UpdatePermission() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var permission object.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)

View File

@@ -24,7 +24,11 @@ import (
func (c *ApiController) UploadPermissions() {
userId := c.GetSessionUsername()
owner, user := util.GetOwnerAndNameFromId(userId)
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Plan The Response object
// @router /get-plans [get]
func (c *ApiController) GetPlans() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
plans, err := object.GetPlans(owner)
@@ -54,7 +54,7 @@ func (c *ApiController) GetPlans() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
plan, err := object.GetPaginatedPlans(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -74,8 +74,8 @@ func (c *ApiController) GetPlans() {
// @Success 200 {object} object.Plan The Response object
// @router /get-plan [get]
func (c *ApiController) GetPlan() {
id := c.Input().Get("id")
includeOption := c.Input().Get("includeOption") == "true"
id := c.Ctx.Input.Query("id")
includeOption := c.Ctx.Input.Query("includeOption") == "true"
plan, err := object.GetPlan(id)
if err != nil {
@@ -107,7 +107,7 @@ func (c *ApiController) GetPlan() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-plan [post]
func (c *ApiController) UpdatePlan() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
owner := util.GetOwnerFromId(id)
var plan object.Plan
err := json.Unmarshal(c.Ctx.Input.RequestBody, &plan)

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Pricing The Response object
// @router /get-pricings [get]
func (c *ApiController) GetPricings() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
pricings, err := object.GetPricings(owner)
@@ -54,7 +54,7 @@ func (c *ApiController) GetPricings() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
pricing, err := object.GetPaginatedPricings(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,7 +73,7 @@ func (c *ApiController) GetPricings() {
// @Success 200 {object} object.Pricing The Response object
// @router /get-pricing [get]
func (c *ApiController) GetPricing() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
pricing, err := object.GetPricing(id)
if err != nil {
@@ -93,7 +93,7 @@ func (c *ApiController) GetPricing() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-pricing [post]
func (c *ApiController) UpdatePricing() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var pricing object.Pricing
err := json.Unmarshal(c.Ctx.Input.RequestBody, &pricing)

View File

@@ -16,10 +16,8 @@ package controllers
import (
"encoding/json"
"fmt"
"strconv"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -32,13 +30,13 @@ import (
// @Success 200 {array} object.Product The Response object
// @router /get-products [get]
func (c *ApiController) GetProducts() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
products, err := object.GetProducts(owner)
@@ -56,7 +54,7 @@ func (c *ApiController) GetProducts() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
products, err := object.GetPaginationProducts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -75,7 +73,7 @@ func (c *ApiController) GetProducts() {
// @Success 200 {object} object.Product The Response object
// @router /get-product [get]
func (c *ApiController) GetProduct() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
product, err := object.GetProduct(id)
if err != nil {
@@ -101,7 +99,7 @@ func (c *ApiController) GetProduct() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-product [post]
func (c *ApiController) UpdateProduct() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var product object.Product
err := json.Unmarshal(c.Ctx.Input.RequestBody, &product)
@@ -151,64 +149,3 @@ func (c *ApiController) DeleteProduct() {
c.Data["json"] = wrapActionResponse(object.DeleteProduct(&product))
c.ServeJSON()
}
// BuyProduct
// @Title BuyProduct
// @Tag Product API
// @Description buy product
// @Param id query string true "The id ( owner/name ) of the product"
// @Param providerName query string true "The name of the provider"
// @Success 200 {object} controllers.Response The Response object
// @router /buy-product [post]
func (c *ApiController) BuyProduct() {
id := c.Input().Get("id")
host := c.Ctx.Request.Host
providerName := c.Input().Get("providerName")
paymentEnv := c.Input().Get("paymentEnv")
customPriceStr := c.Input().Get("customPrice")
if customPriceStr == "" {
customPriceStr = "0"
}
customPrice, err := strconv.ParseFloat(customPriceStr, 64)
if err != nil {
c.ResponseError(err.Error())
return
}
// buy `pricingName/planName` for `paidUserName`
pricingName := c.Input().Get("pricingName")
planName := c.Input().Get("planName")
paidUserName := c.Input().Get("userName")
owner, _ := util.GetOwnerAndNameFromId(id)
userId := util.GetId(owner, paidUserName)
if paidUserName != "" && paidUserName != c.GetSessionUsername() && !c.IsAdmin() {
c.ResponseError(c.T("general:Only admin user can specify user"))
return
}
if paidUserName == "" {
userId = c.GetSessionUsername()
}
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return
}
payment, attachInfo, err := object.BuyProduct(id, user, providerName, pricingName, planName, host, paymentEnv, customPrice)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payment, attachInfo)
}

View File

@@ -16,6 +16,7 @@ package controllers
import (
"github.com/casdoor/casdoor/object"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// GetPrometheusInfo
@@ -37,3 +38,17 @@ func (c *ApiController) GetPrometheusInfo() {
c.ResponseOk(prometheusInfo)
}
// GetMetrics
// @Title GetMetrics
// @Tag System API
// @Description get Prometheus metrics
// @Success 200 {string} Prometheus metrics in text format
// @router /metrics [get]
func (c *ApiController) GetMetrics() {
_, ok := c.RequireAdmin()
if !ok {
return
}
promhttp.Handler().ServeHTTP(c.Ctx.ResponseWriter, c.Ctx.Request)
}

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Provider The Response object
// @router /get-providers [get]
func (c *ApiController) GetProviders() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
ok, isMaskEnabled := c.IsMaskedEnabled()
if !ok {
@@ -59,7 +59,7 @@ func (c *ApiController) GetProviders() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
paginationProviders, err := object.GetPaginationProviders(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -78,12 +78,12 @@ func (c *ApiController) GetProviders() {
// @Success 200 {array} object.Provider The Response object
// @router /get-global-providers [get]
func (c *ApiController) GetGlobalProviders() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
ok, isMaskEnabled := c.IsMaskedEnabled()
if !ok {
@@ -106,7 +106,7 @@ func (c *ApiController) GetGlobalProviders() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
paginationGlobalProviders, err := object.GetPaginationGlobalProviders(paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -126,7 +126,7 @@ func (c *ApiController) GetGlobalProviders() {
// @Success 200 {object} object.Provider The Response object
// @router /get-provider [get]
func (c *ApiController) GetProvider() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
ok, isMaskEnabled := c.IsMaskedEnabled()
if !ok {
@@ -164,7 +164,7 @@ func (c *ApiController) requireProviderPermission(provider *object.Provider) boo
// @Success 200 {object} controllers.Response The Response object
// @router /update-provider [post]
func (c *ApiController) UpdateProvider() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)

View File

@@ -19,7 +19,7 @@ import (
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -38,13 +38,13 @@ func (c *ApiController) GetRecords() {
return
}
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organizationName := c.Input().Get("organizationName")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
organizationName := c.Ctx.Input.Query("organizationName")
if limit == "" || page == "" {
records, err := object.GetRecords()
@@ -66,7 +66,7 @@ func (c *ApiController) GetRecords() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
records, err := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
if err != nil {
c.ResponseError(err.Error())

View File

@@ -20,10 +20,11 @@ import (
"fmt"
"io"
"mime"
"path"
"path/filepath"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -43,14 +44,14 @@ import (
// @Success 200 {array} object.Resource The Response object
// @router /get-resources [get]
func (c *ApiController) GetResources() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
user := c.Ctx.Input.Query("user")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
isOrgAdmin, ok := c.IsOrgAdmin()
if !ok {
@@ -92,7 +93,7 @@ func (c *ApiController) GetResources() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
resources, err := object.GetPaginationResources(owner, user, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -111,7 +112,7 @@ func (c *ApiController) GetResources() {
// @Success 200 {object} object.Resource The Response object
// @router /get-resource [get]
func (c *ApiController) GetResource() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
resource, err := object.GetResource(id)
if err != nil {
@@ -131,7 +132,7 @@ func (c *ApiController) GetResource() {
// @Success 200 {object} controllers.Response Success or error
// @router /update-resource [post]
func (c *ApiController) UpdateResource() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var resource object.Resource
err := json.Unmarshal(c.Ctx.Input.RequestBody, &resource)
@@ -177,9 +178,11 @@ func (c *ApiController) DeleteResource() {
}
if resource.Provider != "" {
c.Input().Set("provider", resource.Provider)
inputs, _ := c.Input()
inputs.Set("provider", resource.Provider)
}
c.Input().Set("fullFilePath", resource.Name)
inputs, _ := c.Input()
inputs.Set("fullFilePath", resource.Name)
provider, err := c.GetProviderFromContext("Storage")
if err != nil {
c.ResponseError(err.Error())
@@ -187,6 +190,11 @@ func (c *ApiController) DeleteResource() {
}
_, resource.Name = refineFullFilePath(resource.Name)
tag := c.Ctx.Input.Query("tag")
if tag == "Direct" {
resource.Name = path.Join(provider.PathPrefix, resource.Name)
}
err = object.DeleteFile(provider, resource.Name, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
@@ -212,14 +220,14 @@ func (c *ApiController) DeleteResource() {
// @Success 200 {object} object.Resource FileUrl, objectKey
// @router /upload-resource [post]
func (c *ApiController) UploadResource() {
owner := c.Input().Get("owner")
username := c.Input().Get("user")
application := c.Input().Get("application")
tag := c.Input().Get("tag")
parent := c.Input().Get("parent")
fullFilePath := c.Input().Get("fullFilePath")
createdTime := c.Input().Get("createdTime")
description := c.Input().Get("description")
owner := c.Ctx.Input.Query("owner")
username := c.Ctx.Input.Query("user")
application := c.Ctx.Input.Query("application")
tag := c.Ctx.Input.Query("tag")
parent := c.Ctx.Input.Query("parent")
fullFilePath := c.Ctx.Input.Query("fullFilePath")
createdTime := c.Ctx.Input.Query("createdTime")
description := c.Ctx.Input.Query("description")
file, header, err := c.GetFile("file")
if err != nil {
@@ -358,7 +366,7 @@ func (c *ApiController) UploadResource() {
}
applicationObj.TermsOfUse = fileUrl
_, err = object.UpdateApplication(applicationId, applicationObj)
_, err = object.UpdateApplication(applicationId, applicationObj, true, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +30,13 @@ import (
// @Success 200 {array} object.Role The Response object
// @router /get-roles [get]
func (c *ApiController) GetRoles() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
roles, err := object.GetRoles(owner)
@@ -54,7 +54,7 @@ func (c *ApiController) GetRoles() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
roles, err := object.GetPaginationRoles(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,7 +73,7 @@ func (c *ApiController) GetRoles() {
// @Success 200 {object} object.Role The Response object
// @router /get-role [get]
func (c *ApiController) GetRole() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
role, err := object.GetRole(id)
if err != nil {
@@ -93,7 +93,7 @@ func (c *ApiController) GetRole() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-role [post]
func (c *ApiController) UpdateRole() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var role object.Role
err := json.Unmarshal(c.Ctx.Input.RequestBody, &role)

View File

@@ -24,7 +24,11 @@ import (
func (c *ApiController) UploadRoles() {
userId := c.GetSessionUsername()
owner, user := util.GetOwnerAndNameFromId(userId)
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {

View File

@@ -17,13 +17,14 @@ package controllers
import (
"fmt"
"net/http"
"net/url"
"github.com/casdoor/casdoor/object"
)
func (c *ApiController) GetSamlMeta() {
host := c.Ctx.Request.Host
paramApp := c.Input().Get("application")
paramApp := c.Ctx.Input.Query("application")
application, err := object.GetApplication(paramApp)
if err != nil {
c.ResponseError(err.Error())
@@ -57,10 +58,13 @@ func (c *ApiController) HandleSamlRedirect() {
owner := c.Ctx.Input.Param(":owner")
application := c.Ctx.Input.Param(":application")
relayState := c.Input().Get("RelayState")
samlRequest := c.Input().Get("SAMLRequest")
relayState := c.Ctx.Input.Query("RelayState")
samlRequest := c.Ctx.Input.Query("SAMLRequest")
username := c.Ctx.Input.Query("username")
loginHint := c.Ctx.Input.Query("login_hint")
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host)
relayState = url.QueryEscape(relayState)
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host, username, loginHint)
c.Redirect(targetURL, http.StatusSeeOther)
}

View File

@@ -140,8 +140,11 @@ func (c *ApiController) SendEmail() {
}
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
matchContent := object.ResetLinkReg.Find([]byte(content))
content = strings.Replace(content, string(matchContent), "", -1)
for _, receiver := range emailForm.Receivers {
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
err = object.SendEmail(provider, emailForm.Title, content, []string{receiver}, emailForm.Sender)
if err != nil {
c.ResponseError(err.Error())
return

View File

@@ -15,9 +15,11 @@
package controllers
import (
"context"
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,13 +32,13 @@ import (
// @Success 200 {array} string The Response object
// @router /get-sessions [get]
func (c *ApiController) GetSessions() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Input().Get("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
owner := c.Ctx.Input.Query("owner")
if limit == "" || page == "" {
sessions, err := object.GetSessions(owner)
@@ -53,7 +55,7 @@ func (c *ApiController) GetSessions() {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
sessions, err := object.GetPaginationSessions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -68,11 +70,11 @@ func (c *ApiController) GetSessions() {
// @Title GetSingleSession
// @Tag Session API
// @Description Get session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionPkId query string true "The session ID in format: organization/user/application (e.g., built-in/admin/app-built-in)"
// @Success 200 {array} string The Response object
// @router /get-session [get]
func (c *ApiController) GetSingleSession() {
id := c.Input().Get("sessionPkId")
id := c.Ctx.Input.Query("sessionPkId")
session, err := object.GetSingleSession(id)
if err != nil {
@@ -87,8 +89,8 @@ func (c *ApiController) GetSingleSession() {
// @Title UpdateSession
// @Tag Session API
// @Description Update session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @Param body body object.Session true "The session object to update"
// @Success 200 {object} controllers.Response The Response object
// @router /update-session [post]
func (c *ApiController) UpdateSession() {
var session object.Session
@@ -106,9 +108,8 @@ func (c *ApiController) UpdateSession() {
// @Title AddSession
// @Tag Session API
// @Description Add session for one user in one application. If there are other existing sessions, join the session into the list.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionId query string true "sessionId to be added"
// @Success 200 {array} string The Response object
// @Param body body object.Session true "The session object to add"
// @Success 200 {object} controllers.Response The Response object
// @router /add-session [post]
func (c *ApiController) AddSession() {
var session object.Session
@@ -126,8 +127,8 @@ func (c *ApiController) AddSession() {
// @Title DeleteSession
// @Tag Session API
// @Description Delete session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @Param body body object.Session true "The session object to delete"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-session [post]
func (c *ApiController) DeleteSession() {
var session object.Session
@@ -137,7 +138,21 @@ func (c *ApiController) DeleteSession() {
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetSessionId(session.Owner, session.Name, session.Application)))
curSessionId := c.Ctx.Input.CruSession.SessionID(context.Background())
sessionId := c.Ctx.Input.Query("sessionId")
if curSessionId == sessionId && sessionId != "" {
c.ResponseError(fmt.Sprintf(c.T("session:session id %s is the current session and cannot be deleted"), curSessionId))
return
}
if sessionId != "" {
c.Data["json"] = wrapActionResponse(object.DeleteSessionId(util.GetSessionId(session.Owner, session.Name, session.Application), sessionId))
c.ServeJSON()
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetSessionId(session.Owner, session.Name, session.Application), curSessionId))
c.ServeJSON()
}
@@ -145,13 +160,13 @@ func (c *ApiController) DeleteSession() {
// @Title IsSessionDuplicated
// @Tag Session API
// @Description Check if there are other different sessions for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionId query string true "sessionId to be checked"
// @Param sessionPkId query string true "The session ID in format: organization/user/application (e.g., built-in/admin/app-built-in)"
// @Param sessionId query string true "The specific session ID to check"
// @Success 200 {array} string The Response object
// @router /is-session-duplicated [get]
func (c *ApiController) IsSessionDuplicated() {
id := c.Input().Get("sessionPkId")
sessionId := c.Input().Get("sessionId")
id := c.Ctx.Input.Query("sessionPkId")
sessionId := c.Ctx.Input.Query("sessionId")
isUserSessionDuplicated, err := object.IsSessionDuplicated(id, sessionId)
if err != nil {

View File

@@ -16,8 +16,9 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,16 +31,35 @@ import (
// @Success 200 {array} object.Subscription The Response object
// @router /get-subscriptions [get]
func (c *ApiController) GetSubscriptions() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
subscriptions, err := object.GetSubscriptions(owner)
var subscriptions []*object.Subscription
var err error
if c.IsAdmin() {
// If field is "user", filter by that user even for admins
if field == "user" && value != "" {
subscriptions, err = object.GetSubscriptionsByUser(owner, value)
} else {
subscriptions, err = object.GetSubscriptions(owner)
}
} else {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
subscriptions, err = object.GetSubscriptionsByUser(owner, userName)
}
if err != nil {
c.ResponseError(err.Error())
return
@@ -48,13 +68,23 @@ func (c *ApiController) GetSubscriptions() {
c.ResponseOk(subscriptions)
} else {
limit := util.ParseInt(limit)
if !c.IsAdmin() {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
field = "user"
value = userName
}
count, err := object.GetSubscriptionCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
subscription, err := object.GetPaginationSubscriptions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,7 +103,7 @@ func (c *ApiController) GetSubscriptions() {
// @Success 200 {object} object.Subscription The Response object
// @router /get-subscription [get]
func (c *ApiController) GetSubscription() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
subscription, err := object.GetSubscription(id)
if err != nil {
@@ -93,7 +123,7 @@ func (c *ApiController) GetSubscription() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-subscription [post]
func (c *ApiController) UpdateSubscription() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var subscription object.Subscription
err := json.Unmarshal(c.Ctx.Input.RequestBody, &subscription)
@@ -121,6 +151,26 @@ func (c *ApiController) AddSubscription() {
return
}
// Check if plan restricts user to one subscription
if subscription.Plan != "" {
plan, err := object.GetPlan(util.GetId(subscription.Owner, subscription.Plan))
if err != nil {
c.ResponseError(err.Error())
return
}
if plan != nil && plan.IsExclusive {
hasSubscription, err := object.HasActiveSubscriptionForPlan(subscription.Owner, subscription.User, subscription.Plan)
if err != nil {
c.ResponseError(err.Error())
return
}
if hasSubscription {
c.ResponseError(fmt.Sprintf("User already has an active subscription for plan: %s", subscription.Plan))
return
}
}
}
c.Data["json"] = wrapActionResponse(object.AddSubscription(&subscription))
c.ServeJSON()
}

View File

@@ -16,8 +16,9 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,14 +31,14 @@ import (
// @Success 200 {array} object.Syncer The Response object
// @router /get-syncers [get]
func (c *ApiController) GetSyncers() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
organization := c.Ctx.Input.Query("organization")
if limit == "" || page == "" {
syncers, err := object.GetMaskedSyncers(object.GetOrganizationSyncers(owner, organization))
@@ -55,7 +56,7 @@ func (c *ApiController) GetSyncers() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
syncers, err := object.GetMaskedSyncers(object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder))
if err != nil {
c.ResponseError(err.Error())
@@ -74,7 +75,7 @@ func (c *ApiController) GetSyncers() {
// @Success 200 {object} object.Syncer The Response object
// @router /get-syncer [get]
func (c *ApiController) GetSyncer() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
syncer, err := object.GetMaskedSyncer(object.GetSyncer(id))
if err != nil {
@@ -94,7 +95,7 @@ func (c *ApiController) GetSyncer() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-syncer [post]
func (c *ApiController) UpdateSyncer() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
@@ -103,7 +104,7 @@ func (c *ApiController) UpdateSyncer() {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer))
c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer, c.IsGlobalAdmin(), c.GetAcceptLanguage()))
c.ServeJSON()
}
@@ -153,12 +154,16 @@ func (c *ApiController) DeleteSyncer() {
// @Success 200 {object} controllers.Response The Response object
// @router /run-syncer [get]
func (c *ApiController) RunSyncer() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
syncer, err := object.GetSyncer(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if syncer == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The syncer: %s does not exist"), id))
return
}
err = object.RunSyncer(syncer)
if err != nil {
@@ -177,7 +182,7 @@ func (c *ApiController) TestSyncerDb() {
return
}
err = object.TestSyncerDb(syncer)
err = object.TestSyncer(syncer)
if err != nil {
c.ResponseError(err.Error())
return

View File

@@ -15,7 +15,10 @@
package controllers
import (
"errors"
"github.com/casdoor/casdoor/util"
"github.com/go-git/go-git/v5"
)
// GetSystemInfo
@@ -46,10 +49,10 @@ func (c *ApiController) GetSystemInfo() {
// @Success 200 {object} util.VersionInfo The Response object
// @router /get-version-info [get]
func (c *ApiController) GetVersionInfo() {
errInfo := ""
versionInfo, err := util.GetVersionInfo()
if err != nil {
errInfo = "Git error: " + err.Error()
if err != nil && !errors.Is(err, git.ErrRepositoryNotExists) {
c.ResponseError(err.Error())
return
}
if versionInfo.Version != "" {
@@ -57,14 +60,7 @@ func (c *ApiController) GetVersionInfo() {
return
}
versionInfo, err = util.GetVersionInfoFromFile()
if err != nil {
errInfo = errInfo + ", File error: " + err.Error()
c.ResponseError(errInfo)
return
}
c.ResponseOk(versionInfo)
c.ResponseOk(util.GetBuiltInVersionInfo())
}
// Health

271
controllers/ticket.go Normal file
View File

@@ -0,0 +1,271 @@
// Copyright 2024 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 controllers
import (
"encoding/json"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetTickets
// @Title GetTickets
// @Tag Ticket API
// @Description get tickets
// @Param owner query string true "The owner of tickets"
// @Success 200 {array} object.Ticket The Response object
// @router /get-tickets [get]
func (c *ApiController) GetTickets() {
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
user := c.getCurrentUser()
isAdmin := c.IsAdmin()
var tickets []*object.Ticket
var err error
if limit == "" || page == "" {
if isAdmin {
tickets, err = object.GetTickets(owner)
} else {
tickets, err = object.GetUserTickets(owner, user.GetId())
}
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(tickets)
} else {
limit := util.ParseInt(limit)
var count int64
if isAdmin {
count, err = object.GetTicketCount(owner, field, value)
} else {
// For non-admin users, only show their own tickets
tickets, err = object.GetUserTickets(owner, user.GetId())
if err != nil {
c.ResponseError(err.Error())
return
}
count = int64(len(tickets))
}
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
if isAdmin {
tickets, err = object.GetPaginationTickets(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
}
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(tickets, paginator.Nums())
}
}
// GetTicket
// @Title GetTicket
// @Tag Ticket API
// @Description get ticket
// @Param id query string true "The id ( owner/name ) of the ticket"
// @Success 200 {object} object.Ticket The Response object
// @router /get-ticket [get]
func (c *ApiController) GetTicket() {
id := c.Ctx.Input.Query("id")
ticket, err := object.GetTicket(id)
if err != nil {
c.ResponseError(err.Error())
return
}
// Check permission: user can only view their own tickets unless they are admin
user := c.getCurrentUser()
isAdmin := c.IsAdmin()
if ticket != nil && !isAdmin && ticket.User != user.GetId() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
c.ResponseOk(ticket)
}
// UpdateTicket
// @Title UpdateTicket
// @Tag Ticket API
// @Description update ticket
// @Param id query string true "The id ( owner/name ) of the ticket"
// @Param body body object.Ticket true "The details of the ticket"
// @Success 200 {object} controllers.Response The Response object
// @router /update-ticket [post]
func (c *ApiController) UpdateTicket() {
id := c.Ctx.Input.Query("id")
var ticket object.Ticket
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ticket)
if err != nil {
c.ResponseError(err.Error())
return
}
// Check permission
user := c.getCurrentUser()
isAdmin := c.IsAdmin()
existingTicket, err := object.GetTicket(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if existingTicket == nil {
c.ResponseError(c.T("ticket:Ticket not found"))
return
}
// Normal users can only close their own tickets
if !isAdmin {
if existingTicket.User != user.GetId() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
// Normal users can only change state to "Closed"
if ticket.State != "Closed" && ticket.State != existingTicket.State {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
// Preserve original fields that users shouldn't modify
ticket.Owner = existingTicket.Owner
ticket.Name = existingTicket.Name
ticket.User = existingTicket.User
ticket.CreatedTime = existingTicket.CreatedTime
}
c.Data["json"] = wrapActionResponse(object.UpdateTicket(id, &ticket))
c.ServeJSON()
}
// AddTicket
// @Title AddTicket
// @Tag Ticket API
// @Description add ticket
// @Param body body object.Ticket true "The details of the ticket"
// @Success 200 {object} controllers.Response The Response object
// @router /add-ticket [post]
func (c *ApiController) AddTicket() {
var ticket object.Ticket
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ticket)
if err != nil {
c.ResponseError(err.Error())
return
}
// Set the user field to the current user
user := c.getCurrentUser()
ticket.User = user.GetId()
c.Data["json"] = wrapActionResponse(object.AddTicket(&ticket))
c.ServeJSON()
}
// DeleteTicket
// @Title DeleteTicket
// @Tag Ticket API
// @Description delete ticket
// @Param body body object.Ticket true "The details of the ticket"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-ticket [post]
func (c *ApiController) DeleteTicket() {
var ticket object.Ticket
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ticket)
if err != nil {
c.ResponseError(err.Error())
return
}
// Only admins can delete tickets
if !c.IsAdmin() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
c.Data["json"] = wrapActionResponse(object.DeleteTicket(&ticket))
c.ServeJSON()
}
// AddTicketMessage
// @Title AddTicketMessage
// @Tag Ticket API
// @Description add a message to a ticket
// @Param id query string true "The id ( owner/name ) of the ticket"
// @Param body body object.TicketMessage true "The message to add"
// @Success 200 {object} controllers.Response The Response object
// @router /add-ticket-message [post]
func (c *ApiController) AddTicketMessage() {
id := c.Ctx.Input.Query("id")
var message object.TicketMessage
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
// Check permission
user := c.getCurrentUser()
isAdmin := c.IsAdmin()
ticket, err := object.GetTicket(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if ticket == nil {
c.ResponseError(c.T("ticket:Ticket not found"))
return
}
// Users can only add messages to their own tickets, admins can add to any ticket
if !isAdmin && ticket.User != user.GetId() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
// Set the author and admin flag
message.Author = user.GetId()
message.IsAdmin = isAdmin
c.Data["json"] = wrapActionResponse(object.AddTicketMessage(id, &message))
c.ServeJSON()
}

View File

@@ -19,7 +19,7 @@ import (
"fmt"
"time"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -28,20 +28,20 @@ import (
// @Title GetTokens
// @Tag Token API
// @Description get tokens
// @Param owner query string true "The owner of tokens"
// @Param owner query string true "The organization name (e.g., built-in)"
// @Param pageSize query string true "The size of each page"
// @Param p query string true "The number of the page"
// @Success 200 {array} object.Token The Response object
// @router /get-tokens [get]
func (c *ApiController) GetTokens() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
organization := c.Ctx.Input.Query("organization")
if limit == "" || page == "" {
token, err := object.GetTokens(owner, organization)
if err != nil {
@@ -58,7 +58,7 @@ func (c *ApiController) GetTokens() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
tokens, err := object.GetPaginationTokens(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -73,11 +73,11 @@ func (c *ApiController) GetTokens() {
// @Title GetToken
// @Tag Token API
// @Description get token
// @Param id query string true "The id ( owner/name ) of token"
// @Param id query string true "The token ID in format: organization/token-name (e.g., built-in/token-123456)"
// @Success 200 {object} object.Token The Response object
// @router /get-token [get]
func (c *ApiController) GetToken() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
token, err := object.GetToken(id)
if err != nil {
c.ResponseError(err.Error())
@@ -91,12 +91,12 @@ func (c *ApiController) GetToken() {
// @Title UpdateToken
// @Tag Token API
// @Description update token
// @Param id query string true "The id ( owner/name ) of token"
// @Param id query string true "The token ID in format: organization/token-name (e.g., built-in/token-123456)"
// @Param body body object.Token true "Details of the token"
// @Success 200 {object} controllers.Response The Response object
// @router /update-token [post]
func (c *ApiController) UpdateToken() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var token object.Token
err := json.Unmarshal(c.Ctx.Input.RequestBody, &token)
@@ -105,7 +105,7 @@ func (c *ApiController) UpdateToken() {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token))
c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token, c.IsGlobalAdmin()))
c.ServeJSON()
}
@@ -160,19 +160,23 @@ func (c *ApiController) DeleteToken() {
// @Success 401 {object} object.TokenError The Response object
// @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() {
clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret")
grantType := c.Input().Get("grant_type")
code := c.Input().Get("code")
verifier := c.Input().Get("code_verifier")
scope := c.Input().Get("scope")
nonce := c.Input().Get("nonce")
username := c.Input().Get("username")
password := c.Input().Get("password")
tag := c.Input().Get("tag")
avatar := c.Input().Get("avatar")
refreshToken := c.Input().Get("refresh_token")
deviceCode := c.Input().Get("device_code")
clientId := c.Ctx.Input.Query("client_id")
clientSecret := c.Ctx.Input.Query("client_secret")
grantType := c.Ctx.Input.Query("grant_type")
code := c.Ctx.Input.Query("code")
verifier := c.Ctx.Input.Query("code_verifier")
scope := c.Ctx.Input.Query("scope")
nonce := c.Ctx.Input.Query("nonce")
username := c.Ctx.Input.Query("username")
password := c.Ctx.Input.Query("password")
tag := c.Ctx.Input.Query("tag")
avatar := c.Ctx.Input.Query("avatar")
refreshToken := c.Ctx.Input.Query("refresh_token")
deviceCode := c.Ctx.Input.Query("device_code")
subjectToken := c.Ctx.Input.Query("subject_token")
subjectTokenType := c.Ctx.Input.Query("subject_token_type")
audience := c.Ctx.Input.Query("audience")
resource := c.Ctx.Input.Query("resource")
if clientId == "" && clientSecret == "" {
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
@@ -219,6 +223,18 @@ func (c *ApiController) GetOAuthToken() {
if refreshToken == "" {
refreshToken = tokenRequest.RefreshToken
}
if subjectToken == "" {
subjectToken = tokenRequest.SubjectToken
}
if subjectTokenType == "" {
subjectTokenType = tokenRequest.SubjectTokenType
}
if audience == "" {
audience = tokenRequest.Audience
}
if resource == "" {
resource = tokenRequest.Resource
}
}
}
@@ -263,7 +279,7 @@ func (c *ApiController) GetOAuthToken() {
}
host := c.Ctx.Request.Host
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, nonce, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, nonce, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage(), subjectToken, subjectTokenType, audience, resource)
if err != nil {
c.ResponseError(err.Error())
return
@@ -288,11 +304,11 @@ func (c *ApiController) GetOAuthToken() {
// @Success 401 {object} object.TokenError The Response object
// @router /login/oauth/refresh_token [post]
func (c *ApiController) RefreshToken() {
grantType := c.Input().Get("grant_type")
refreshToken := c.Input().Get("refresh_token")
scope := c.Input().Get("scope")
clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret")
grantType := c.Ctx.Input.Query("grant_type")
refreshToken := c.Ctx.Input.Query("refresh_token")
scope := c.Ctx.Input.Query("scope")
clientId := c.Ctx.Input.Query("client_id")
clientSecret := c.Ctx.Input.Query("client_secret")
host := c.Ctx.Request.Host
if clientId == "" {
@@ -342,11 +358,11 @@ func (c *ApiController) ResponseTokenError(errorMsg string) {
// @Success 401 {object} object.TokenError The Response object
// @router /login/oauth/introspect [post]
func (c *ApiController) IntrospectToken() {
tokenValue := c.Input().Get("token")
tokenValue := c.Ctx.Input.Query("token")
clientId, clientSecret, ok := c.Ctx.Request.BasicAuth()
if !ok {
clientId = c.Input().Get("client_id")
clientSecret = c.Input().Get("client_secret")
clientId = c.Ctx.Input.Query("client_id")
clientSecret = c.Ctx.Input.Query("client_secret")
if clientId == "" || clientSecret == "" {
c.ResponseTokenError(object.InvalidRequest)
return
@@ -369,7 +385,7 @@ func (c *ApiController) IntrospectToken() {
c.ServeJSON()
}
tokenTypeHint := c.Input().Get("token_type_hint")
tokenTypeHint := c.Ctx.Input.Query("token_type_hint")
var token *object.Token
if tokenTypeHint != "" {
token, err = object.GetTokenByTokenValue(tokenValue, tokenTypeHint)

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -30,16 +30,35 @@ import (
// @Success 200 {array} object.Transaction The Response object
// @router /get-transactions [get]
func (c *ApiController) GetTransactions() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
transactions, err := object.GetTransactions(owner)
var transactions []*object.Transaction
var err error
if c.IsAdmin() {
// If field is "user", filter by that user even for admins
if field == "user" && value != "" {
transactions, err = object.GetUserTransactions(owner, value)
} else {
transactions, err = object.GetTransactions(owner)
}
} else {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
transactions, err = object.GetUserTransactions(owner, userName)
}
if err != nil {
c.ResponseError(err.Error())
return
@@ -48,13 +67,26 @@ func (c *ApiController) GetTransactions() {
c.ResponseOk(transactions)
} else {
limit := util.ParseInt(limit)
// Apply user filter for non-admin users
if !c.IsAdmin() {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
field = "user"
value = userName
}
count, err := object.GetTransactionCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
transactions, err := object.GetPaginationTransactions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -65,28 +97,6 @@ func (c *ApiController) GetTransactions() {
}
}
// GetUserTransactions
// @Title GetUserTransaction
// @Tag Transaction API
// @Description get transactions for a user
// @Param owner query string true "The owner of transactions"
// @Param organization query string true "The organization of the user"
// @Param user query string true "The username of the user"
// @Success 200 {array} object.Transaction The Response object
// @router /get-user-transactions [get]
func (c *ApiController) GetUserTransactions() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
transactions, err := object.GetUserTransactions(owner, user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transactions)
}
// GetTransaction
// @Title GetTransaction
// @Tag Transaction API
@@ -95,7 +105,7 @@ func (c *ApiController) GetUserTransactions() {
// @Success 200 {object} object.Transaction The Response object
// @router /get-transaction [get]
func (c *ApiController) GetTransaction() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
transaction, err := object.GetTransaction(id)
if err != nil {
@@ -103,6 +113,27 @@ func (c *ApiController) GetTransaction() {
return
}
if transaction == nil {
c.ResponseOk(nil)
return
}
// Check if non-admin user is trying to access someone else's transaction
if !c.IsAdmin() {
user := c.GetSessionUsername()
_, userName, userErr := util.GetOwnerAndNameFromIdWithError(user)
if userErr != nil {
c.ResponseError(userErr.Error())
return
}
// Only allow users to view their own transactions
if transaction.User != userName {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
}
c.ResponseOk(transaction)
}
@@ -115,7 +146,7 @@ func (c *ApiController) GetTransaction() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-transaction [post]
func (c *ApiController) UpdateTransaction() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
@@ -124,7 +155,7 @@ func (c *ApiController) UpdateTransaction() {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction))
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction, c.GetAcceptLanguage()))
c.ServeJSON()
}
@@ -133,6 +164,7 @@ func (c *ApiController) UpdateTransaction() {
// @Tag Transaction API
// @Description add transaction
// @Param body body object.Transaction true "The details of the transaction"
// @Param dryRun query string false "Dry run mode: set to 'true' or '1' to validate without committing"
// @Success 200 {object} controllers.Response The Response object
// @router /add-transaction [post]
func (c *ApiController) AddTransaction() {
@@ -143,8 +175,22 @@ func (c *ApiController) AddTransaction() {
return
}
c.Data["json"] = wrapActionResponse(object.AddTransaction(&transaction))
c.ServeJSON()
dryRunParam := c.Ctx.Input.Query("dryRun")
dryRun := dryRunParam != ""
affected, transactionId, err := object.AddTransaction(&transaction, c.GetAcceptLanguage(), dryRun)
if err != nil {
c.ResponseError(err.Error())
return
}
if !affected {
c.Data["json"] = wrapActionResponse(false)
c.ServeJSON()
return
}
c.ResponseOk(transactionId)
}
// DeleteTransaction
@@ -162,6 +208,6 @@ func (c *ApiController) DeleteTransaction() {
return
}
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction))
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction, c.GetAcceptLanguage()))
c.ServeJSON()
}

View File

@@ -15,16 +15,20 @@
package controllers
type TokenRequest struct {
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
GrantType string `json:"grant_type"`
Code string `json:"code"`
Verifier string `json:"code_verifier"`
Scope string `json:"scope"`
Nonce string `json:"nonce"`
Username string `json:"username"`
Password string `json:"password"`
Tag string `json:"tag"`
Avatar string `json:"avatar"`
RefreshToken string `json:"refresh_token"`
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
GrantType string `json:"grant_type"`
Code string `json:"code"`
Verifier string `json:"code_verifier"`
Scope string `json:"scope"`
Nonce string `json:"nonce"`
Username string `json:"username"`
Password string `json:"password"`
Tag string `json:"tag"`
Avatar string `json:"avatar"`
RefreshToken string `json:"refresh_token"`
SubjectToken string `json:"subject_token"`
SubjectTokenType string `json:"subject_token_type"`
Audience string `json:"audience"`
Resource string `json:"resource"` // RFC 8707 Resource Indicator
}

View File

@@ -19,7 +19,7 @@ import (
"fmt"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
@@ -32,12 +32,12 @@ import (
// @Success 200 {array} object.User The Response object
// @router /get-global-users [get]
func (c *ApiController) GetGlobalUsers() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
users, err := object.GetMaskedUsers(object.GetGlobalUsers())
@@ -55,7 +55,7 @@ func (c *ApiController) GetGlobalUsers() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
users, err := object.GetPaginationGlobalUsers(paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
@@ -80,14 +80,14 @@ func (c *ApiController) GetGlobalUsers() {
// @Success 200 {array} object.User The Response object
// @router /get-users [get]
func (c *ApiController) GetUsers() {
owner := c.Input().Get("owner")
groupName := c.Input().Get("groupName")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Ctx.Input.Query("owner")
groupName := c.Ctx.Input.Query("groupName")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
if limit == "" || page == "" {
if groupName != "" {
@@ -115,7 +115,7 @@ func (c *ApiController) GetUsers() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
users, err := object.GetPaginationUsers(owner, paginator.Offset(), limit, field, value, sortField, sortOrder, groupName)
if err != nil {
c.ResponseError(err.Error())
@@ -144,11 +144,11 @@ func (c *ApiController) GetUsers() {
// @Success 200 {object} object.User The Response object
// @router /get-user [get]
func (c *ApiController) GetUser() {
id := c.Input().Get("id")
email := c.Input().Get("email")
phone := c.Input().Get("phone")
userId := c.Input().Get("userId")
owner := c.Input().Get("owner")
id := c.Ctx.Input.Query("id")
email := c.Ctx.Input.Query("email")
phone := c.Ctx.Input.Query("phone")
userId := c.Ctx.Input.Query("userId")
owner := c.Ctx.Input.Query("owner")
var err error
var userFromUserId *object.User
if userId != "" && owner != "" {
@@ -252,13 +252,17 @@ func (c *ApiController) GetUser() {
// @Title UpdateUser
// @Tag User API
// @Description update user
// @Param id query string true "The id ( owner/name ) of the user"
// @Param id query string false "The id ( owner/name ) of the user"
// @Param userId query string false "The userId (UUID) of the user"
// @Param owner query string false "The owner of the user (required when using userId)"
// @Param body body object.User true "The details of the user"
// @Success 200 {object} controllers.Response The Response object
// @router /update-user [post]
func (c *ApiController) UpdateUser() {
id := c.Input().Get("id")
columnsStr := c.Input().Get("columns")
id := c.Ctx.Input.Query("id")
userId := c.Ctx.Input.Query("userId")
owner := c.Ctx.Input.Query("owner")
columnsStr := c.Ctx.Input.Query("columns")
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
@@ -267,17 +271,38 @@ func (c *ApiController) UpdateUser() {
return
}
if id == "" {
if id == "" && userId == "" {
id = c.GetSessionUsername()
if id == "" {
c.ResponseError(c.T("general:Missing parameter"))
return
}
}
oldUser, err := object.GetUser(id)
if err != nil {
c.ResponseError(err.Error())
return
var userFromUserId *object.User
if userId != "" && owner != "" {
userFromUserId, err = object.GetUserByUserId(owner, userId)
if err != nil {
c.ResponseError(err.Error())
return
}
if userFromUserId == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return
}
id = util.GetId(userFromUserId.Owner, userFromUserId.Name)
}
var oldUser *object.User
if userId != "" {
oldUser = userFromUserId
} else {
oldUser, err = object.GetUser(id)
if err != nil {
c.ResponseError(err.Error())
return
}
}
if oldUser == nil {
@@ -311,7 +336,7 @@ func (c *ApiController) UpdateUser() {
}
isAdmin := c.IsAdmin()
allowDisplayNameEmpty := c.Input().Get("allowEmpty") != ""
allowDisplayNameEmpty := c.Ctx.Input.Query("allowEmpty") != ""
if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, allowDisplayNameEmpty, c.GetAcceptLanguage()); !pass {
c.ResponseError(err)
return
@@ -367,6 +392,17 @@ func (c *ApiController) AddUser() {
return
}
// Set RegisterSource based on the current user if not already set
if user.RegisterType == "" {
user.RegisterType = "Add User"
}
if user.RegisterSource == "" {
currentUser := c.getCurrentUser()
if currentUser != nil {
user.RegisterSource = currentUser.GetId()
}
}
c.Data["json"] = wrapActionResponse(object.AddUser(&user, c.GetAcceptLanguage()))
c.ServeJSON()
}
@@ -464,11 +500,6 @@ func (c *ApiController) SetPassword() {
// return
// }
if strings.Contains(newPassword, " ") {
c.ResponseError(c.T("user:New password cannot contain blank space."))
return
}
userId := util.GetId(userOwner, userName)
user, err := object.GetUser(userId)
@@ -481,6 +512,41 @@ func (c *ApiController) SetPassword() {
return
}
// Get organization to check for password obfuscation settings
organization, err := object.GetOrganizationByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:the organization: %s is not found"), user.Owner))
return
}
// Deobfuscate passwords if organization has password obfuscator configured
// Note: Deobfuscation is optional - if it fails, we treat the password as plain text
// This allows SDKs and raw HTTP API calls to work without obfuscation support
if organization.PasswordObfuscatorType != "" && organization.PasswordObfuscatorType != "Plain" {
if oldPassword != "" {
deobfuscatedOldPassword, deobfuscateErr := util.GetUnobfuscatedPassword(organization.PasswordObfuscatorType, organization.PasswordObfuscatorKey, oldPassword)
if deobfuscateErr == nil {
oldPassword = deobfuscatedOldPassword
}
}
if newPassword != "" {
deobfuscatedNewPassword, deobfuscateErr := util.GetUnobfuscatedPassword(organization.PasswordObfuscatorType, organization.PasswordObfuscatorKey, newPassword)
if deobfuscateErr == nil {
newPassword = deobfuscatedNewPassword
}
}
}
if strings.Contains(newPassword, " ") {
c.ResponseError(c.T("user:New password cannot contain blank space."))
return
}
requestUserId := c.GetSessionUsername()
if requestUserId == "" && code == "" {
c.ResponseError(c.T("general:Please login first"), "Please login first")
@@ -524,30 +590,28 @@ func (c *ApiController) SetPassword() {
}
}
} else if code == "" {
if user.Ldap == "" {
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
} else {
err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage())
}
if err != nil {
c.ResponseError(err.Error())
return
if targetUser.Password != "" || user.Ldap != "" {
if user.Ldap == "" {
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
} else {
err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage())
}
if err != nil {
c.ResponseError(err.Error())
return
}
}
}
msg := object.CheckPasswordComplexity(targetUser, newPassword)
msg := object.CheckPasswordComplexity(targetUser, newPassword, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
return
}
organization, err := object.GetOrganizationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:the organization: %s is not found"), targetUser.Owner))
// Check if the new password is the same as the current password
if !object.CheckPasswordNotSameAsCurrent(targetUser, newPassword, organization) {
c.ResponseError(c.T("user:The new password must be different from your current password"))
return
}
@@ -626,9 +690,9 @@ func (c *ApiController) CheckUserPassword() {
// @Success 200 {array} object.User The Response object
// @router /get-sorted-users [get]
func (c *ApiController) GetSortedUsers() {
owner := c.Input().Get("owner")
sorter := c.Input().Get("sorter")
limit := util.ParseInt(c.Input().Get("limit"))
owner := c.Ctx.Input.Query("owner")
sorter := c.Ctx.Input.Query("sorter")
limit := util.ParseInt(c.Ctx.Input.Query("limit"))
users, err := object.GetMaskedUsers(object.GetSortedUsers(owner, sorter, limit))
if err != nil {
@@ -648,8 +712,8 @@ func (c *ApiController) GetSortedUsers() {
// @Success 200 {int} int The count of filtered users for an organization
// @router /get-user-count [get]
func (c *ApiController) GetUserCount() {
owner := c.Input().Get("owner")
isOnline := c.Input().Get("isOnline")
owner := c.Ctx.Input.Query("owner")
isOnline := c.Ctx.Input.Query("isOnline")
var count int64
var err error
@@ -713,3 +777,205 @@ func (c *ApiController) RemoveUserFromGroup() {
c.ResponseOk(affected)
}
// ImpersonateUser
// @Title ImpersonateUser
// @Tag User API
// @Description set impersonation user for current admin session
// @Param username formData string true "The username to impersonate (owner/name)"
// @Success 200 {object} controllers.Response The Response object
// @router /impersonation-user [post]
func (c *ApiController) ImpersonateUser() {
org, ok := c.RequireAdmin()
if !ok {
return
}
username := c.Ctx.Request.Form.Get("username")
if username == "" {
c.ResponseError(c.T("general:Missing parameter"))
return
}
owner, _, err := util.GetOwnerAndNameFromIdWithError(username)
if err != nil {
c.ResponseError(err.Error())
return
}
if !(owner == org || org == "") {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
targetUser, err := object.GetUser(username)
if err != nil {
c.ResponseError(err.Error())
return
}
if targetUser == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), username))
return
}
err = c.SetSession("impersonateUser", username)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Ctx.SetCookie("impersonateUser", username, 0, "/")
c.ResponseOk()
}
// ExitImpersonateUser
// @Title ExitImpersonateUser
// @Tag User API
// @Description clear impersonation info for current session
// @Success 200 {object} controllers.Response The Response object
// @router /exit-impersonation-user [post]
func (c *ApiController) ExitImpersonateUser() {
_, ok := c.Ctx.Input.GetData("impersonating").(bool)
if !ok {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
err := c.SetSession("impersonateUser", "")
if err != nil {
c.ResponseError(err.Error())
return
}
c.Ctx.SetCookie("impersonateUser", "", -1, "/")
c.ResponseOk()
}
// VerifyIdentification
// @Title VerifyIdentification
// @Tag User API
// @Description verify user's real identity using ID Verification provider
// @Param owner query string false "The owner of the user (optional, defaults to logged-in user)"
// @Param name query string false "The name of the user (optional, defaults to logged-in user)"
// @Param provider query string false "The name of the ID Verification provider (optional, auto-selected if not provided)"
// @Success 200 {object} controllers.Response The Response object
// @router /verify-identification [post]
func (c *ApiController) VerifyIdentification() {
owner := c.Ctx.Input.Query("owner")
name := c.Ctx.Input.Query("name")
providerName := c.Ctx.Input.Query("provider")
// If user not specified, use logged-in user
if owner == "" || name == "" {
loggedInUser := c.GetSessionUsername()
if loggedInUser == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
var err error
owner, name, err = util.GetOwnerAndNameFromIdWithError(loggedInUser)
if err != nil {
c.ResponseError(err.Error())
return
}
} else {
// If user is specified, check if current user has permission to verify other users
// Only admins can verify other users
loggedInUser := c.GetSessionUsername()
if loggedInUser != util.GetId(owner, name) && !c.IsAdmin() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
}
user, err := object.GetUser(util.GetId(owner, name))
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(owner, name)))
return
}
if user.IdCard == "" || user.IdCardType == "" || user.RealName == "" {
c.ResponseError(c.T("user:ID card information and real name are required"))
return
}
if user.IsVerified {
c.ResponseError(c.T("user:User is already verified"))
return
}
var provider *object.Provider
// If provider not specified, find suitable IDV provider from user's application
if providerName == "" {
application, err := object.GetApplicationByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(c.T("user:No application found for user"))
return
}
// Find IDV provider from application
idvProvider, err := object.GetIdvProviderByApplication(util.GetId(application.Owner, application.Name), "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if idvProvider == nil {
c.ResponseError(c.T("provider:No ID Verification provider configured"))
return
}
provider = idvProvider
} else {
provider, err = object.GetProvider(providerName)
if err != nil {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), providerName))
return
}
if provider.Category != "ID Verification" {
c.ResponseError(c.T("provider:Provider is not an ID Verification provider"))
return
}
}
idvProvider := object.GetIdvProviderFromProvider(provider)
if idvProvider == nil {
c.ResponseError(c.T("provider:Failed to initialize ID Verification provider"))
return
}
verified, err := idvProvider.VerifyIdentity(user.IdCardType, user.IdCard, user.RealName)
if err != nil {
c.ResponseError(err.Error())
return
}
if !verified {
c.ResponseError(c.T("user:Identity verification failed"))
return
}
// Set IsVerified to true upon successful verification
user.IsVerified = true
_, err = object.UpdateUser(user.GetId(), user, []string{"is_verified"}, false)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(user.RealName)
}

View File

@@ -40,8 +40,23 @@ func saveFile(path string, file *multipart.File) (err error) {
}
func (c *ApiController) UploadUsers() {
if !c.IsAdmin() {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
userObj := c.getCurrentUser()
if userObj == nil {
c.ResponseError(c.T("auth:Unauthorized operation"))
return
}
userId := c.GetSessionUsername()
owner, user := util.GetOwnerAndNameFromId(userId)
owner, user, err := util.GetOwnerAndNameFromIdWithError(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {
@@ -58,7 +73,7 @@ func (c *ApiController) UploadUsers() {
return
}
affected, err := object.UploadUsers(owner, path)
affected, err := object.UploadUsers(owner, path, userObj, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return

View File

@@ -54,13 +54,6 @@ func (c *ApiController) ResponseError(error string, data ...interface{}) {
return
}
enableErrorMask := conf.GetConfigBool("enableErrorMask")
if enableErrorMask {
if strings.HasPrefix(error, "The user: ") && strings.HasSuffix(error, " doesn't exist") || strings.HasPrefix(error, "用户: ") && strings.HasSuffix(error, "不存在") {
error = c.T("check:password or code is incorrect")
}
}
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
}
@@ -113,7 +106,7 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
}
if object.IsAppUser(userId) {
tmpUserId := c.Input().Get("userId")
tmpUserId := c.Ctx.Input.Query("userId")
if tmpUserId != "" {
userId = tmpUserId
}
@@ -179,7 +172,7 @@ func (c *ApiController) IsOrgAdmin() (bool, bool) {
// IsMaskedEnabled ...
func (c *ApiController) IsMaskedEnabled() (bool, bool) {
isMaskEnabled := true
withSecret := c.Input().Get("withSecret")
withSecret := c.Ctx.Input.Query("withSecret")
if withSecret == "1" {
isMaskEnabled = false
@@ -209,14 +202,14 @@ func refineFullFilePath(fullFilePath string) (string, string) {
}
func (c *ApiController) GetProviderFromContext(category string) (*object.Provider, error) {
providerName := c.Input().Get("provider")
providerName := c.Ctx.Input.Query("provider")
if providerName == "" {
field := c.Input().Get("field")
value := c.Input().Get("value")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
if field == "provider" && value != "" {
providerName = value
} else {
fullFilePath := c.Input().Get("fullFilePath")
fullFilePath := c.Ctx.Input.Query("fullFilePath")
providerName, _ = refineFullFilePath(fullFilePath)
}
}

View File

@@ -20,7 +20,7 @@ import (
"fmt"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/captcha"
"github.com/casdoor/casdoor/form"
"github.com/casdoor/casdoor/object"
@@ -44,16 +44,27 @@ const (
// @Success 200 {array} object.Verification The Response object
// @router /get-payments [get]
func (c *ApiController) GetVerifications() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization, ok := c.RequireAdmin()
if !ok {
return
}
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
owner := c.Ctx.Input.Query("owner")
// For global admin with organizationName parameter, use it to filter
// For org admin, use their organization
if c.IsGlobalAdmin() && owner != "" {
organization = owner
}
if limit == "" || page == "" {
payments, err := object.GetVerifications(owner)
payments, err := object.GetVerifications(organization)
if err != nil {
c.ResponseError(err.Error())
return
@@ -62,14 +73,14 @@ func (c *ApiController) GetVerifications() {
c.ResponseOk(payments)
} else {
limit := util.ParseInt(limit)
count, err := object.GetVerificationCount(owner, field, value)
count, err := object.GetVerificationCount(organization, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
payments, err := object.GetPaginationVerifications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
payments, err := object.GetPaginationVerifications(organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
@@ -89,8 +100,8 @@ func (c *ApiController) GetVerifications() {
// @Success 200 {array} object.Verification The Response object
// @router /get-user-payments [get]
func (c *ApiController) GetUserVerifications() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
owner := c.Ctx.Input.Query("owner")
user := c.Ctx.Input.Query("user")
payments, err := object.GetUserVerifications(owner, user)
if err != nil {
@@ -109,7 +120,7 @@ func (c *ApiController) GetUserVerifications() {
// @Success 200 {object} object.Verification The Response object
// @router /get-payment [get]
func (c *ApiController) GetVerification() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
payment, err := object.GetVerification(id)
if err != nil {
@@ -140,42 +151,33 @@ func (c *ApiController) SendVerificationCode() {
return
}
provider, err := object.GetCaptchaProviderByApplication(vform.ApplicationId, "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if provider != nil {
if vform.CaptchaType != provider.Type {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
if provider.Type != "Default" {
vform.ClientSecret = provider.ClientSecret
}
if vform.CaptchaType != "none" {
if captchaProvider := captcha.GetCaptchaProvider(vform.CaptchaType); captchaProvider == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
return
} else if isHuman, err := captchaProvider.VerifyCaptcha(vform.CaptchaToken, provider.ClientId, vform.ClientSecret, provider.ClientId2); err != nil {
c.ResponseError(err.Error())
return
} else if !isHuman {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
}
}
application, err := object.GetApplication(vform.ApplicationId)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), vform.ApplicationId))
return
}
// Check if "Forgot password?" signin item is visible when using forget verification
if vform.Method == ForgetVerification {
isForgotPasswordEnabled := false
for _, item := range application.SigninItems {
if item.Name == "Forgot password?" {
isForgotPasswordEnabled = item.Visible
break
}
}
// Block access if the signin item is not found or is explicitly hidden
if !isForgotPasswordEnabled {
c.ResponseError(c.T("verification:The forgot password feature is disabled"))
return
}
}
organization, err := object.GetOrganization(util.GetId(application.Owner, application.Organization))
if err != nil {
c.ResponseError(c.T(err.Error()))
@@ -187,6 +189,7 @@ func (c *ApiController) SendVerificationCode() {
}
var user *object.User
// Try to resolve user for CAPTCHA rule checking
// checkUser != "", means method is ForgetVerification
if vform.CheckUser != "" {
owner := application.Organization
@@ -204,18 +207,86 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
return
}
}
// mfaUserSession != "", means method is MfaAuthVerification
if mfaUserSession := c.getMfaUserSession(); mfaUserSession != "" {
} else if mfaUserSession := c.getMfaUserSession(); mfaUserSession != "" {
// mfaUserSession != "", means method is MfaAuthVerification
user, err = object.GetUser(mfaUserSession)
if err != nil {
c.ResponseError(err.Error())
return
}
} else if vform.Method == ResetVerification {
// For reset verification, get the current logged-in user
user = c.getCurrentUser()
} else if vform.Method == LoginVerification {
// For login verification, try to find user by email/phone for CAPTCHA check
// This is a preliminary lookup; the actual validation happens later in the switch statement
if vform.Type == object.VerifyTypeEmail && util.IsEmailValid(vform.Dest) {
user, err = object.GetUserByEmail(organization.Name, vform.Dest)
if err != nil {
c.ResponseError(err.Error())
return
}
} else if vform.Type == object.VerifyTypePhone {
// Prefer resolving the user directly by phone, consistent with the later login switch,
// so that Dynamic CAPTCHA is not skipped due to missing/invalid country code.
user, err = object.GetUserByPhone(organization.Name, vform.Dest)
if err != nil {
c.ResponseError(err.Error())
return
}
}
}
// Determine username for CAPTCHA check
username := ""
if user != nil {
username = user.Name
} else if vform.CheckUser != "" {
username = vform.CheckUser
}
// Check if CAPTCHA should be enabled based on the rule (Dynamic/Always/Internet-Only)
enableCaptcha, err := object.CheckToEnableCaptcha(application, organization.Name, username, clientIp)
if err != nil {
c.ResponseError(err.Error())
return
}
// Only verify CAPTCHA if it should be enabled
if enableCaptcha {
captchaProvider, err := object.GetCaptchaProviderByApplication(vform.ApplicationId, "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if captchaProvider != nil {
if vform.CaptchaType != captchaProvider.Type {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
if captchaProvider.Type != "Default" {
vform.ClientSecret = captchaProvider.ClientSecret
}
if vform.CaptchaType != "none" {
if captchaService := captcha.GetCaptchaProvider(vform.CaptchaType); captchaService == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
return
} else if isHuman, err := captchaService.VerifyCaptcha(vform.CaptchaToken, captchaProvider.ClientId, vform.ClientSecret, captchaProvider.ClientId2); err != nil {
c.ResponseError(err.Error())
return
} else if !isHuman {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
}
}
}
sendResp := errors.New("invalid dest type")
var provider *object.Provider
switch vform.Type {
case object.VerifyTypeEmail:
@@ -258,7 +329,7 @@ func (c *ApiController) SendVerificationCode() {
return
}
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest)
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest, vform.Method, c.Ctx.Request.Host, application.Name, application)
case object.VerifyTypePhone:
if vform.Method == LoginVerification || vform.Method == ForgetVerification {
if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest {
@@ -304,7 +375,7 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode))
return
} else {
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone)
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone, application)
}
}
@@ -435,9 +506,15 @@ func (c *ApiController) ResetEmailOrPhone() {
switch destType {
case object.VerifyTypeEmail:
id := user.GetId()
user.Email = dest
user.EmailVerified = true
_, err = object.UpdateUser(user.GetId(), user, []string{"email", "email_verified"}, false)
columns := []string{"email", "email_verified"}
if organization.UseEmailAsUsername {
user.Name = user.Email
columns = append(columns, "name")
}
_, err = object.UpdateUser(id, user, columns, false)
case object.VerifyTypePhone:
user.Phone = dest
_, err = object.SetUserField(user, "phone", user.Phone)
@@ -449,6 +526,9 @@ func (c *ApiController) ResetEmailOrPhone() {
c.ResponseError(err.Error())
return
}
if organization.UseEmailAsUsername {
c.SetSessionUsername(user.GetId())
}
err = object.DisableVerificationCode(checkDest)
if err != nil {

View File

@@ -17,6 +17,7 @@ package controllers
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"github.com/casdoor/casdoor/form"
@@ -47,6 +48,13 @@ func (c *ApiController) WebAuthnSignupBegin() {
registerOptions := func(credCreationOpts *protocol.PublicKeyCredentialCreationOptions) {
credCreationOpts.CredentialExcludeList = user.CredentialExcludeList()
credCreationOpts.AuthenticatorSelection.ResidentKey = "preferred"
credCreationOpts.Attestation = "none"
ext := map[string]interface{}{
"credProps": true,
}
credCreationOpts.Extensions = ext
}
options, sessionData, err := webauthnObj.BeginRegistration(
user,
@@ -118,7 +126,34 @@ func (c *ApiController) WebAuthnSigninBegin() {
return
}
options, sessionData, err := webauthnObj.BeginDiscoverableLogin()
userOwner := c.Ctx.Input.Query("owner")
userName := c.Ctx.Input.Query("name")
var options *protocol.CredentialAssertion
var sessionData *webauthn.SessionData
if userName == "" {
options, sessionData, err = webauthnObj.BeginDiscoverableLogin()
} else {
var user *object.User
user, err = object.GetUserByFields(userOwner, userName)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(userOwner, userName)))
return
}
if len(user.WebauthnCredentials) == 0 {
c.ResponseError(c.T("webauthn:Found no credentials for this user"))
return
}
options, sessionData, err = webauthnObj.BeginLogin(user)
}
if err != nil {
c.ResponseError(err.Error())
return
@@ -136,8 +171,8 @@ func (c *ApiController) WebAuthnSigninBegin() {
// @Success 200 {object} controllers.Response "The Response object"
// @router /webauthn/signin/finish [post]
func (c *ApiController) WebAuthnSigninFinish() {
responseType := c.Input().Get("responseType")
clientId := c.Input().Get("clientId")
responseType := c.Ctx.Input.Query("responseType")
clientId := c.Ctx.Input.Query("clientId")
webauthnObj, err := object.GetWebAuthnObject(c.Ctx.Request.Host)
if err != nil {
c.ResponseError(err.Error())
@@ -153,15 +188,27 @@ func (c *ApiController) WebAuthnSigninFinish() {
c.Ctx.Request.Body = io.NopCloser(bytes.NewBuffer(c.Ctx.Input.RequestBody))
var user *object.User
handler := func(rawID, userHandle []byte) (webauthn.User, error) {
user, err = object.GetUserByWebauthID(base64.StdEncoding.EncodeToString(rawID))
if sessionData.UserID != nil {
userId := string(sessionData.UserID)
user, err = object.GetUser(userId)
if err != nil {
return nil, err
c.ResponseError(err.Error())
return
}
return user, nil
_, err = webauthnObj.FinishLogin(user, sessionData, c.Ctx.Request)
} else {
handler := func(rawID, userHandle []byte) (webauthn.User, error) {
user, err = object.GetUserByWebauthID(base64.StdEncoding.EncodeToString(rawID))
if err != nil {
return nil, err
}
return user, nil
}
_, err = webauthnObj.FinishDiscoverableLogin(handler, sessionData, c.Ctx.Request)
}
_, err = webauthnObj.FinishDiscoverableLogin(handler, sessionData, c.Ctx.Request)
if err != nil {
c.ResponseError(err.Error())
return

View File

@@ -17,7 +17,7 @@ package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/beego/beego/v2/core/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@@ -31,14 +31,14 @@ import (
// @router /get-webhooks [get]
// @Security test_apiKey
func (c *ApiController) GetWebhooks() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
organization := c.Input().Get("organization")
owner := c.Ctx.Input.Query("owner")
limit := c.Ctx.Input.Query("pageSize")
page := c.Ctx.Input.Query("p")
field := c.Ctx.Input.Query("field")
value := c.Ctx.Input.Query("value")
sortField := c.Ctx.Input.Query("sortField")
sortOrder := c.Ctx.Input.Query("sortOrder")
organization := c.Ctx.Input.Query("organization")
if limit == "" || page == "" {
webhooks, err := object.GetWebhooks(owner, organization)
@@ -56,7 +56,7 @@ func (c *ApiController) GetWebhooks() {
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
paginator := pagination.NewPaginator(c.Ctx.Request, limit, count)
webhooks, err := object.GetPaginationWebhooks(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
@@ -76,7 +76,7 @@ func (c *ApiController) GetWebhooks() {
// @Success 200 {object} object.Webhook The Response object
// @router /get-webhook [get]
func (c *ApiController) GetWebhook() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
webhook, err := object.GetWebhook(id)
if err != nil {
@@ -96,7 +96,7 @@ func (c *ApiController) GetWebhook() {
// @Success 200 {object} controllers.Response The Response object
// @router /update-webhook [post]
func (c *ApiController) UpdateWebhook() {
id := c.Input().Get("id")
id := c.Ctx.Input.Query("id")
var webhook object.Webhook
err := json.Unmarshal(c.Ctx.Input.RequestBody, &webhook)
@@ -105,7 +105,7 @@ func (c *ApiController) UpdateWebhook() {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook))
c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook, c.IsGlobalAdmin(), c.GetAcceptLanguage()))
c.ServeJSON()
}

View File

@@ -0,0 +1,45 @@
// Copyright 2026 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 controllers
import (
"github.com/casdoor/casdoor/object"
)
// GetOauthProtectedResourceMetadata
// @Title GetOauthProtectedResourceMetadata
// @Tag OAuth 2.0 API
// @Description Get OAuth 2.0 Protected Resource Metadata (RFC 9728)
// @Success 200 {object} object.OauthProtectedResourceMetadata
// @router /.well-known/oauth-protected-resource [get]
func (c *RootController) GetOauthProtectedResourceMetadata() {
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOauthProtectedResourceMetadata(host)
c.ServeJSON()
}
// GetOauthProtectedResourceMetadataByApplication
// @Title GetOauthProtectedResourceMetadataByApplication
// @Tag OAuth 2.0 API
// @Description Get OAuth 2.0 Protected Resource Metadata for specific application (RFC 9728)
// @Param application path string true "application name"
// @Success 200 {object} object.OauthProtectedResourceMetadata
// @router /.well-known/:application/oauth-protected-resource [get]
func (c *RootController) GetOauthProtectedResourceMetadataByApplication() {
application := c.Ctx.Input.Param(":application")
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOauthProtectedResourceMetadataByApplication(host, application)
c.ServeJSON()
}

View File

@@ -0,0 +1,165 @@
// 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.
package controllers
import (
"strings"
"github.com/casdoor/casdoor/object"
)
// GetOidcDiscovery
// @Title GetOidcDiscovery
// @Tag OIDC API
// @Description Get Oidc Discovery
// @Success 200 {object} object.OidcDiscovery
// @router /.well-known/openid-configuration [get]
func (c *RootController) GetOidcDiscovery() {
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOidcDiscovery(host, "")
c.ServeJSON()
}
// GetOidcDiscoveryByApplication
// @Title GetOidcDiscoveryByApplication
// @Tag OIDC API
// @Description Get Oidc Discovery for specific application
// @Param application path string true "application name"
// @Success 200 {object} object.OidcDiscovery
// @router /.well-known/:application/openid-configuration [get]
func (c *RootController) GetOidcDiscoveryByApplication() {
application := c.Ctx.Input.Param(":application")
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOidcDiscovery(host, application)
c.ServeJSON()
}
// GetJwks
// @Title GetJwks
// @Tag OIDC API
// @Success 200 {object} jose.JSONWebKey
// @router /.well-known/jwks [get]
func (c *RootController) GetJwks() {
jwks, err := object.GetJsonWebKeySet("")
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = jwks
c.ServeJSON()
}
// GetJwksByApplication
// @Title GetJwksByApplication
// @Tag OIDC API
// @Param application path string true "application name"
// @Success 200 {object} jose.JSONWebKey
// @router /.well-known/:application/jwks [get]
func (c *RootController) GetJwksByApplication() {
application := c.Ctx.Input.Param(":application")
jwks, err := object.GetJsonWebKeySet(application)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = jwks
c.ServeJSON()
}
// GetWebFinger
// @Title GetWebFinger
// @Tag OIDC API
// @Param resource query string true "resource"
// @Success 200 {object} object.WebFinger
// @router /.well-known/webfinger [get]
func (c *RootController) GetWebFinger() {
resource := c.Ctx.Input.Query("resource")
rels := []string{}
host := c.Ctx.Request.Host
inputs, _ := c.Input()
for key, value := range inputs {
if strings.HasPrefix(key, "rel") {
rels = append(rels, value...)
}
}
webfinger, err := object.GetWebFinger(resource, rels, host, "")
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = webfinger
c.Ctx.Output.ContentType("application/jrd+json")
c.ServeJSON()
}
// GetWebFingerByApplication
// @Title GetWebFingerByApplication
// @Tag OIDC API
// @Param application path string true "application name"
// @Param resource query string true "resource"
// @Success 200 {object} object.WebFinger
// @router /.well-known/:application/webfinger [get]
func (c *RootController) GetWebFingerByApplication() {
application := c.Ctx.Input.Param(":application")
resource := c.Ctx.Input.Query("resource")
rels := []string{}
host := c.Ctx.Request.Host
inputs, _ := c.Input()
for key, value := range inputs {
if strings.HasPrefix(key, "rel") {
rels = append(rels, value...)
}
}
webfinger, err := object.GetWebFinger(resource, rels, host, application)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = webfinger
c.Ctx.Output.ContentType("application/jrd+json")
c.ServeJSON()
}
// GetOAuthServerMetadata
// @Title GetOAuthServerMetadata
// @Tag OAuth API
// @Description Get OAuth 2.0 Authorization Server Metadata (RFC 8414)
// @Success 200 {object} object.OidcDiscovery
// @router /.well-known/oauth-authorization-server [get]
func (c *RootController) GetOAuthServerMetadata() {
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOidcDiscovery(host, "")
c.ServeJSON()
}
// GetOAuthServerMetadataByApplication
// @Title GetOAuthServerMetadataByApplication
// @Tag OAuth API
// @Description Get OAuth 2.0 Authorization Server Metadata for specific application (RFC 8414)
// @Param application path string true "application name"
// @Success 200 {object} object.OidcDiscovery
// @router /.well-known/:application/oauth-authorization-server [get]
func (c *RootController) GetOAuthServerMetadataByApplication() {
application := c.Ctx.Input.Param(":application")
host := c.Ctx.Request.Host
c.Data["json"] = object.GetOidcDiscovery(host, application)
c.ServeJSON()
}

View File

@@ -38,9 +38,20 @@ func NewMd5UserSaltCredManager() *Md5UserSaltCredManager {
}
func (cm *Md5UserSaltCredManager) GetHashedPassword(password string, salt string) string {
if salt == "" {
return getMd5HexDigest(password)
}
return getMd5HexDigest(getMd5HexDigest(password) + salt)
}
func (cm *Md5UserSaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
// For backward-compatibility
if salt == "" {
if hashedPwd == cm.GetHashedPassword(getMd5HexDigest(plainPwd), salt) {
return true
}
}
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

View File

@@ -38,9 +38,20 @@ func NewSha256SaltCredManager() *Sha256SaltCredManager {
}
func (cm *Sha256SaltCredManager) GetHashedPassword(password string, salt string) string {
if salt == "" {
return getSha256HexDigest(password)
}
return getSha256HexDigest(getSha256HexDigest(password) + salt)
}
func (cm *Sha256SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
// For backward-compatibility
if salt == "" {
if hashedPwd == cm.GetHashedPassword(getSha256HexDigest(plainPwd), salt) {
return true
}
}
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

View File

@@ -38,9 +38,20 @@ func NewSha512SaltCredManager() *Sha512SaltCredManager {
}
func (cm *Sha512SaltCredManager) GetHashedPassword(password string, salt string) string {
if salt == "" {
return getSha512HexDigest(password)
}
return getSha512HexDigest(getSha512HexDigest(password) + salt)
}
func (cm *Sha512SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
// For backward-compatibility
if salt == "" {
if hashedPwd == cm.GetHashedPassword(getSha512HexDigest(plainPwd), salt) {
return true
}
}
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

View File

@@ -13,7 +13,6 @@
// limitations under the License.
//go:build !skipCi
// +build !skipCi
package deployment

View File

@@ -1,8 +1,10 @@
#!/bin/bash
if [ "${MYSQL_ROOT_PASSWORD}" = "" ] ;then MYSQL_ROOT_PASSWORD=123456 ;fi
service mariadb start
if [ -z "${driverName:-}" ]; then
export driverName=sqlite
fi
if [ -z "${dataSourceName:-}" ]; then
export dataSourceName="file:casdoor.db?cache=shared"
fi
mysqladmin -u root password ${MYSQL_ROOT_PASSWORD}
exec /server --createDatabase=true
exec /server

View File

@@ -96,15 +96,17 @@ func NewAzureACSEmailProvider(accessKey string, endpoint string) *AzureACSEmailP
}
}
func newEmail(fromAddress string, toAddress string, subject string, content string) *Email {
func newEmail(fromAddress string, toAddress []string, subject string, content string) *Email {
var to []EmailAddress
for _, addr := range toAddress {
to = append(to, EmailAddress{
DisplayName: addr,
Address: addr,
})
}
return &Email{
Recipients: Recipients{
To: []EmailAddress{
{
DisplayName: toAddress,
Address: toAddress,
},
},
To: to,
},
SenderAddress: fromAddress,
Content: Content{
@@ -116,7 +118,7 @@ func newEmail(fromAddress string, toAddress string, subject string, content stri
}
}
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error {
email := newEmail(fromAddress, toAddress, subject, content)
postBody, err := json.Marshal(email)

View File

@@ -48,21 +48,26 @@ func NewHttpEmailProvider(endpoint string, method string, httpHeaders map[string
return client
}
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error {
var req *http.Request
var err error
fromAddressField := "fromAddress"
fromNameField := "fromName"
toAddressField := "toAddress"
toAddressesField := "toAddresses"
subjectField := "subject"
contentField := "content"
for k, v := range c.bodyMapping {
switch k {
case "fromAddress":
fromAddressField = v
case "fromName":
fromNameField = v
case "toAddress":
toAddressField = v
case "toAddresses":
toAddressesField = v
case "subject":
subjectField = v
case "content":
@@ -72,8 +77,8 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
if c.method == "POST" || c.method == "PUT" || c.method == "DELETE" {
bodyMap := make(map[string]string)
bodyMap[fromAddressField] = fromAddress
bodyMap[fromNameField] = fromName
bodyMap[toAddressField] = toAddress
bodyMap[subjectField] = subject
bodyMap[contentField] = content
@@ -89,6 +94,13 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
for k, v := range bodyMap {
formValues.Add(k, v)
}
if len(toAddress) == 1 {
formValues.Add(toAddressField, toAddress[0])
} else {
for _, addr := range toAddress {
formValues.Add(toAddressesField, addr)
}
}
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
}
@@ -104,8 +116,15 @@ func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress
}
q := req.URL.Query()
q.Add(fromAddressField, fromAddress)
q.Add(fromNameField, fromName)
q.Add(toAddressField, toAddress)
if len(toAddress) == 1 {
q.Add(toAddressField, toAddress[0])
} else {
for _, addr := range toAddress {
q.Add(toAddressesField, addr)
}
}
q.Add(subjectField, subject)
q.Add(contentField, content)
req.URL.RawQuery = q.Encode()

View File

@@ -15,10 +15,10 @@
package email
type EmailProvider interface {
Send(fromAddress string, fromName, toAddress string, subject string, content string) error
Send(fromAddress string, fromName string, toAddress []string, subject string, content string) error
}
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool, endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string) EmailProvider {
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, sslMode string, endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string, enableProxy bool) EmailProvider {
if typ == "Azure ACS" {
return NewAzureACSEmailProvider(clientSecret, host)
} else if typ == "Custom HTTP Email" {
@@ -26,6 +26,6 @@ func GetEmailProvider(typ string, clientId string, clientSecret string, host str
} else if typ == "SendGrid" {
return NewSendgridEmailProvider(clientSecret, host, endpoint)
} else {
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, sslMode, enableProxy)
}
}

View File

@@ -41,13 +41,24 @@ func NewSendgridEmailProvider(apiKey string, host string, endpoint string) *Send
return &SendgridEmailProvider{ApiKey: apiKey, Host: host, Endpoint: endpoint}
}
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
client := s.initSendgridClient()
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddresses []string, subject string, content string) error {
from := mail.NewEmail(fromName, fromAddress)
to := mail.NewEmail("", toAddress)
message := mail.NewSingleEmail(from, subject, to, "", content)
message := mail.NewV3Mail()
message.SetFrom(from)
message.AddContent(mail.NewContent("text/html", content))
personalization := mail.NewPersonalization()
for _, toAddress := range toAddresses {
to := mail.NewEmail(toAddress, toAddress)
personalization.AddTos(to)
}
personalization.Subject = subject
message.AddPersonalizations(personalization)
client := s.initSendgridClient()
resp, err := client.Send(message)
if err != nil {
return err

View File

@@ -16,7 +16,6 @@ package email
import (
"crypto/tls"
"strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/gomail/v2"
@@ -26,15 +25,22 @@ type SmtpEmailProvider struct {
Dialer *gomail.Dialer
}
func NewSmtpEmailProvider(userName string, password string, host string, port int, typ string, disableSsl bool) *SmtpEmailProvider {
func NewSmtpEmailProvider(userName string, password string, host string, port int, typ string, sslMode string, enableProxy bool) *SmtpEmailProvider {
dialer := gomail.NewDialer(host, port, userName, password)
if typ == "SUBMAIL" {
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
dialer.SSL = !disableSsl
// Handle SSL mode: "Auto" (or empty) means don't override gomail's default behavior
// "Enable" means force SSL on, "Disable" means force SSL off
if sslMode == "Enable" {
dialer.SSL = true
} else if sslMode == "Disable" {
dialer.SSL = false
}
// If sslMode is "Auto" or empty, don't set dialer.SSL - let gomail decide based on port
if strings.HasSuffix(host, ".amazonaws.com") {
if enableProxy {
socks5Proxy := conf.GetConfigString("socks5Proxy")
if socks5Proxy != "" {
dialer.SetSocks5Proxy(socks5Proxy)
@@ -44,11 +50,15 @@ func NewSmtpEmailProvider(userName string, password string, host string, port in
return &SmtpEmailProvider{Dialer: dialer}
}
func (s *SmtpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
func (s *SmtpEmailProvider) Send(fromAddress string, fromName string, toAddresses []string, subject string, content string) error {
message := gomail.NewMessage()
message.SetAddressHeader("From", fromAddress, fromName)
message.SetHeader("To", toAddress)
var addresses []string
for _, address := range toAddresses {
addresses = append(addresses, message.FormatAddress(address, ""))
}
message.SetHeader("To", addresses...)
message.SetHeader("Subject", subject)
message.SetBody("text/html", content)

View File

@@ -46,6 +46,7 @@ type AuthForm struct {
State string `json:"state"`
RedirectUri string `json:"redirectUri"`
Method string `json:"method"`
CodeVerifier string `json:"codeVerifier"`
EmailCode string `json:"emailCode"`
PhoneCode string `json:"phoneCode"`
@@ -61,9 +62,10 @@ type AuthForm struct {
CaptchaToken string `json:"captchaToken"`
ClientSecret string `json:"clientSecret"`
MfaType string `json:"mfaType"`
Passcode string `json:"passcode"`
RecoveryCode string `json:"recoveryCode"`
MfaType string `json:"mfaType"`
Passcode string `json:"passcode"`
RecoveryCode string `json:"recoveryCode"`
EnableMfaRemember bool `json:"enableMfaRemember"`
Plan string `json:"plan"`
Pricing string `json:"pricing"`

View File

@@ -47,7 +47,7 @@ func (form *VerificationForm) CheckParameter(checkType int, lang string) string
return i18n.Translate(lang, "general:Missing parameter") + ": dest."
}
if form.CaptchaType == "" {
return i18n.Translate(lang, "general:Missing parameter") + ": checkType."
return i18n.Translate(lang, "general:Missing parameter") + ": captchaType."
}
if !strings.Contains(form.ApplicationId, "/") {
return i18n.Translate(lang, "verification:Wrong parameter") + ": applicationId."

229
go.mod
View File

@@ -1,36 +1,45 @@
module github.com/casdoor/casdoor
go 1.21
go 1.23.0
require (
github.com/Masterminds/squirrel v1.5.3
github.com/NdoleStudio/lemonsqueezy-go v1.2.4
github.com/PaddleHQ/paddle-go-sdk v1.0.0
github.com/adyen/adyen-go-api-library/v11 v11.0.0
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/alibabacloud-go/cloudauth-20190307/v3 v3.9.2
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4
github.com/alibabacloud-go/facebody-20191230/v5 v5.1.2
github.com/alibabacloud-go/openapi-util v0.1.0
github.com/alibabacloud-go/tea v1.3.2
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
github.com/aliyun/alibaba-cloud-sdk-go v1.63.107
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible
github.com/aliyun/credentials-go v1.3.10
github.com/aws/aws-sdk-go v1.45.5
github.com/beego/beego v1.12.12
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0
github.com/beego/beego/v2 v2.3.8
github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.25.0
github.com/casdoor/gomail/v2 v2.1.0
github.com/casdoor/gomail/v2 v2.2.0
github.com/casdoor/ldapserver v1.2.0
github.com/casdoor/notify v1.0.1
github.com/casdoor/notify2 v1.6.0
github.com/casdoor/oss v1.8.0
github.com/casdoor/xorm-adapter/v3 v3.1.0
github.com/casvisor/casvisor-go-sdk v1.4.0
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.9.0
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3
github.com/fogleman/gg v1.3.0
github.com/go-asn1-ber/asn1-ber v1.5.5
github.com/go-git/go-git/v5 v5.13.0
github.com/go-git/go-git/v5 v5.16.3
github.com/go-jose/go-jose/v4 v4.1.2
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-mysql-org/go-mysql v1.7.0
github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.6.0
github.com/go-pay/gopay v1.5.115
github.com/go-pay/util v0.0.4
github.com/go-sql-driver/mysql v1.8.1
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/go-webauthn/webauthn v0.10.2
github.com/golang-jwt/jwt/v5 v5.2.2
@@ -39,54 +48,61 @@ require (
github.com/lestrrat-go/jwx v1.2.29
github.com/lib/pq v1.10.9
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
github.com/markbates/goth v1.79.0
github.com/markbates/goth v1.82.0
github.com/microsoft/go-mssqldb v1.9.0
github.com/mitchellh/mapstructure v1.5.0
github.com/nyaruka/phonenumbers v1.1.5
github.com/nyaruka/phonenumbers v1.2.2
github.com/polarsource/polar-go v0.12.0
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.11.1
github.com/prometheus/client_model v0.4.0
github.com/prometheus/client_golang v1.19.0
github.com/prometheus/client_model v0.6.0
github.com/qiangmzsx/string-adapter/v2 v2.1.0
github.com/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.9.0
github.com/russellhaering/goxmldsig v1.2.0
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/sendgrid/sendgrid-go v3.16.0+incompatible
github.com/shirou/gopsutil/v4 v4.25.9
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.1
github.com/stripe/stripe-go/v74 v74.29.0
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
github.com/xorm-io/builder v0.3.13
github.com/xorm-io/core v0.7.4
github.com/xorm-io/xorm v1.1.6
golang.org/x/crypto v0.32.0
golang.org/x/net v0.34.0
golang.org/x/oauth2 v0.17.0
golang.org/x/text v0.21.0
google.golang.org/api v0.150.0
gopkg.in/square/go-jose.v2 v2.6.0
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68
maunium.net/go/mautrix v0.16.0
golang.org/x/crypto v0.40.0
golang.org/x/net v0.41.0
golang.org/x/oauth2 v0.27.0
golang.org/x/text v0.27.0
google.golang.org/api v0.215.0
layeh.com/radius v0.0.0-20231213012653-1006025d24f8
maunium.net/go/mautrix v0.22.1
modernc.org/sqlite v1.18.2
)
require (
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/compute v1.23.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.3 // indirect
cloud.google.com/go/storage v1.35.1 // indirect
cel.dev/expr v0.18.0 // indirect
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/auth v0.13.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.2.2 // indirect
cloud.google.com/go/monitoring v1.21.2 // indirect
cloud.google.com/go/storage v1.47.0 // indirect
dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-storage-blob-go v0.15.0 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20221121042443-a3fd332d56d9 // indirect
github.com/SherClockHolmes/webpush-go v1.2.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20240116134246-a8cbe886bab0 // indirect
github.com/SherClockHolmes/webpush-go v1.4.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/darabonba-number v1.0.4 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
@@ -97,56 +113,68 @@ require (
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-utils v1.3.6 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.62.545 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible // indirect
github.com/aliyun/credentials-go v1.3.10 // indirect
github.com/apistd/uni-go-sdk v0.0.2 // indirect
github.com/atc0005/go-teams-notify/v2 v2.13.0 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/baidubce/bce-sdk-go v0.9.156 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blinkbean/dingtalk v0.0.0-20210905093040-7d935c0f7e19 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bwmarrin/discordgo v0.27.1 // indirect
github.com/blinkbean/dingtalk v1.1.3 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bwmarrin/discordgo v0.28.1 // indirect
github.com/caarlos0/go-reddit/v3 v3.0.1 // indirect
github.com/casdoor/casdoor-go-sdk v0.50.0 // indirect
github.com/casdoor/go-reddit/v2 v2.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dghubble/oauth1 v0.7.2 // indirect
github.com/dghubble/sling v1.4.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dghubble/oauth1 v0.7.3 // indirect
github.com/dghubble/sling v1.4.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/di-wu/parser v0.2.2 // indirect
github.com/di-wu/xsd-datetime v1.0.0 // indirect
github.com/drswork/go-twitter v0.0.0-20221107160839-dea1b6ed53d7 // indirect
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/ebitengine/purego v0.9.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/ggicci/httpin v0.19.0 // indirect
github.com/ggicci/owl v0.8.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.0 // indirect
github.com/go-lark/lark v1.9.0 // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-lark/lark v1.15.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-pay/crypto v0.0.1 // indirect
github.com/go-pay/errgroup v0.0.3 // indirect
github.com/go-pay/smap v0.0.2 // indirect
github.com/go-pay/xlog v0.0.3 // indirect
github.com/go-pay/xtime v0.0.2 // indirect
github.com/go-webauthn/x v0.1.9 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregdel/pushover v1.2.1 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/gregdel/pushover v1.3.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -156,17 +184,17 @@ require (
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/line/line-bot-sdk-go v7.8.0+incompatible // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/markbates/going v1.0.0 // indirect
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mileusna/viber v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -175,75 +203,84 @@ require (
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/qiniu/go-sdk/v7 v7.12.1 // indirect
github.com/redis/go-redis/v9 v9.5.5 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rs/zerolog v1.30.0 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/scim2/filter-parser/v2 v2.2.0 // indirect
github.com/sendgrid/rest v2.6.9+incompatible // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/slack-go/slack v0.12.3 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/slack-go/slack v0.15.0 // indirect
github.com/spyzhov/ajson v0.8.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.744 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.744 // indirect
github.com/tidwall/gjson v1.16.0 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/tklauser/go-sysconf v0.3.15 // indirect
github.com/tklauser/numcpus v0.10.0 // indirect
github.com/twilio/twilio-go v1.13.0 // indirect
github.com/ucloud/ucloud-sdk-go v0.22.5 // indirect
github.com/utahta/go-linenotify v0.5.0 // indirect
github.com/volcengine/volc-sdk-golang v1.0.117 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.mau.fi/util v0.0.0-20230805171708-199bf3eec776 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.mau.fi/util v0.8.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
go.opentelemetry.io/otel v1.32.0 // indirect
go.opentelemetry.io/otel/metric v1.32.0 // indirect
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
go.opentelemetry.io/otel/trace v1.32.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.23.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/time v0.8.0 // indirect
golang.org/x/tools v0.34.0 // indirect
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
google.golang.org/grpc v1.68.0 // indirect
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
maunium.net/go/maulogger/v2 v2.4.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.37.0 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
modernc.org/libc v1.18.0 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.3.0 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

1566
go.sum

File diff suppressed because it is too large Load Diff

140
i18n/deduplicate_test.go Normal file
View File

@@ -0,0 +1,140 @@
// Copyright 2026 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 i18n
import (
"bytes"
"encoding/json"
"fmt"
"os"
"testing"
)
// DuplicateInfo represents information about a duplicate key
type DuplicateInfo struct {
Key string
OldPrefix string
NewPrefix string
OldPrefixKey string // e.g., "general:Submitter"
NewPrefixKey string // e.g., "permission:Submitter"
}
// findDuplicateKeysInJSON finds duplicate keys across the entire JSON file
// Returns a list of duplicate information showing old and new prefix:key pairs
// The order is determined by the order keys appear in the JSON file (git history)
func findDuplicateKeysInJSON(filePath string) ([]DuplicateInfo, error) {
// Read the JSON file
fileContent, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to read file %s: %w", filePath, err)
}
// Track the first occurrence of each key (prefix where it was first seen)
keyFirstPrefix := make(map[string]string)
var duplicates []DuplicateInfo
// To preserve order, we need to parse the JSON with order preservation
// We'll use a decoder to read through the top-level object
decoder := json.NewDecoder(bytes.NewReader(fileContent))
// Read the opening brace of the top-level object
token, err := decoder.Token()
if err != nil {
return nil, fmt.Errorf("failed to read token: %w", err)
}
if delim, ok := token.(json.Delim); !ok || delim != '{' {
return nil, fmt.Errorf("expected object start, got %v", token)
}
// Read all namespaces in order
for decoder.More() {
// Read the namespace (prefix) name
token, err := decoder.Token()
if err != nil {
return nil, fmt.Errorf("failed to read namespace: %w", err)
}
prefix, ok := token.(string)
if !ok {
return nil, fmt.Errorf("expected string namespace, got %v", token)
}
// Read the namespace object as raw message
var namespaceData map[string]string
if err := decoder.Decode(&namespaceData); err != nil {
return nil, fmt.Errorf("failed to decode namespace %s: %w", prefix, err)
}
// Now check each key in this namespace
for key := range namespaceData {
// Check if this key was already seen in a different prefix
if firstPrefix, exists := keyFirstPrefix[key]; exists {
// This is a duplicate - the key exists in another prefix
duplicates = append(duplicates, DuplicateInfo{
Key: key,
OldPrefix: firstPrefix,
NewPrefix: prefix,
OldPrefixKey: fmt.Sprintf("%s:%s", firstPrefix, key),
NewPrefixKey: fmt.Sprintf("%s:%s", prefix, key),
})
} else {
// First time seeing this key, record the prefix
keyFirstPrefix[key] = prefix
}
}
}
return duplicates, nil
}
// TestDeduplicateFrontendI18n checks for duplicate i18n keys in the frontend en.json file
func TestDeduplicateFrontendI18n(t *testing.T) {
filePath := "../web/src/locales/en/data.json"
// Find duplicate keys
duplicates, err := findDuplicateKeysInJSON(filePath)
if err != nil {
t.Fatalf("Failed to check for duplicates in frontend i18n file: %v", err)
}
// Print all duplicates and fail the test if any are found
if len(duplicates) > 0 {
t.Errorf("Found duplicate i18n keys in frontend file (%s):", filePath)
for _, dup := range duplicates {
t.Errorf(" i18next.t(\"%s\") duplicates with i18next.t(\"%s\")", dup.NewPrefixKey, dup.OldPrefixKey)
}
t.Fail()
}
}
// TestDeduplicateBackendI18n checks for duplicate i18n keys in the backend en.json file
func TestDeduplicateBackendI18n(t *testing.T) {
filePath := "../i18n/locales/en/data.json"
// Find duplicate keys
duplicates, err := findDuplicateKeysInJSON(filePath)
if err != nil {
t.Fatalf("Failed to check for duplicates in backend i18n file: %v", err)
}
// Print all duplicates and fail the test if any are found
if len(duplicates) > 0 {
t.Errorf("Found duplicate i18n keys in backend file (%s):", filePath)
for _, dup := range duplicates {
t.Errorf(" i18n.Translate(\"%s\") duplicates with i18n.Translate(\"%s\")", dup.NewPrefixKey, dup.OldPrefixKey)
}
t.Fail()
}
}

View File

@@ -19,6 +19,7 @@ import (
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"github.com/casdoor/casdoor/util"
@@ -47,7 +48,11 @@ func getAllI18nStringsFrontend(fileContent string) []string {
}
for _, match := range matches {
res = append(res, match[1])
target, err := strconv.Unquote("\"" + match[1] + "\"")
if err != nil {
target = match[1]
}
res = append(res, target)
}
return res
}
@@ -61,7 +66,12 @@ func getAllI18nStringsBackend(fileContent string, isObjectPackage bool) []string
}
for _, match := range matches {
match := strings.SplitN(match[1], ",", 2)
res = append(res, match[1][2:])
target, err := strconv.Unquote("\"" + match[1][2:] + "\"")
if err != nil {
target = match[1][2:]
}
res = append(res, target)
}
} else {
matches := reI18nBackendController.FindAllStringSubmatch(fileContent, -1)
@@ -69,7 +79,11 @@ func getAllI18nStringsBackend(fileContent string, isObjectPackage bool) []string
return res
}
for _, match := range matches {
res = append(res, match[1][1:])
target, err := strconv.Unquote("\"" + match[1][1:] + "\"")
if err != nil {
target = match[1][1:]
}
res = append(res, target)
}
}
@@ -141,10 +155,26 @@ func parseAllWords(category string) *I18nData {
return &data
}
// copyI18nData creates a deep copy of an I18nData structure to prevent shared reference issues
// between language translations. This ensures each language starts with fresh English defaults
// rather than inheriting values from previously processed languages.
func copyI18nData(src *I18nData) *I18nData {
dst := I18nData{}
for namespace, pairs := range *src {
dst[namespace] = make(map[string]string)
for key, value := range pairs {
dst[namespace][key] = value
}
}
return &dst
}
func applyToOtherLanguage(category string, language string, newData *I18nData) {
oldData := readI18nFile(category, language)
println(oldData)
applyData(newData, oldData)
writeI18nFile(category, language, newData)
// Create a copy of newData to avoid modifying the shared data across languages
dataCopy := copyI18nData(newData)
applyData(dataCopy, oldData)
writeI18nFile(category, language, dataCopy)
}

View File

@@ -13,7 +13,6 @@
// limitations under the License.
//go:build !skipCi
// +build !skipCi
package i18n
@@ -23,58 +22,30 @@ func TestGenerateI18nFrontend(t *testing.T) {
data := parseAllWords("frontend")
applyToOtherLanguage("frontend", "en", data)
applyToOtherLanguage("frontend", "zh", data)
applyToOtherLanguage("frontend", "es", data)
applyToOtherLanguage("frontend", "fr", data)
applyToOtherLanguage("frontend", "de", data)
applyToOtherLanguage("frontend", "id", data)
applyToOtherLanguage("frontend", "ja", data)
applyToOtherLanguage("frontend", "ko", data)
applyToOtherLanguage("frontend", "ru", data)
applyToOtherLanguage("frontend", "zh", data)
applyToOtherLanguage("frontend", "vi", data)
applyToOtherLanguage("frontend", "pt", data)
applyToOtherLanguage("frontend", "it", data)
applyToOtherLanguage("frontend", "ms", data)
applyToOtherLanguage("frontend", "tr", data)
applyToOtherLanguage("frontend", "ar", data)
applyToOtherLanguage("frontend", "he", data)
applyToOtherLanguage("frontend", "nl", data)
applyToOtherLanguage("frontend", "pl", data)
applyToOtherLanguage("frontend", "fi", data)
applyToOtherLanguage("frontend", "sv", data)
applyToOtherLanguage("frontend", "uk", data)
applyToOtherLanguage("frontend", "kk", data)
applyToOtherLanguage("frontend", "fa", data)
applyToOtherLanguage("frontend", "cs", data)
applyToOtherLanguage("frontend", "sk", data)
}
func TestGenerateI18nBackend(t *testing.T) {
data := parseAllWords("backend")
applyToOtherLanguage("backend", "en", data)
applyToOtherLanguage("backend", "zh", data)
applyToOtherLanguage("backend", "es", data)
applyToOtherLanguage("backend", "fr", data)
applyToOtherLanguage("backend", "de", data)
applyToOtherLanguage("backend", "id", data)
applyToOtherLanguage("backend", "ja", data)
applyToOtherLanguage("backend", "ko", data)
applyToOtherLanguage("backend", "ru", data)
applyToOtherLanguage("backend", "zh", data)
applyToOtherLanguage("backend", "vi", data)
applyToOtherLanguage("backend", "pt", data)
applyToOtherLanguage("backend", "it", data)
applyToOtherLanguage("backend", "ms", data)
applyToOtherLanguage("backend", "tr", data)
applyToOtherLanguage("backend", "ar", data)
applyToOtherLanguage("backend", "he", data)
applyToOtherLanguage("backend", "nl", data)
applyToOtherLanguage("backend", "pl", data)
applyToOtherLanguage("backend", "fi", data)
applyToOtherLanguage("backend", "sv", data)
applyToOtherLanguage("backend", "uk", data)
applyToOtherLanguage("backend", "kk", data)
applyToOtherLanguage("backend", "fa", data)
applyToOtherLanguage("backend", "cs", data)
applyToOtherLanguage("backend", "sk", data)
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Nepodařilo se přidat uživatele",
"Get init score failed, error: %w": "Nepodařilo se získat počáteční skóre, chyba: %w",
"Please sign out first": "Nejprve se prosím odhlaste",
"The application does not allow to sign up new account": "Aplikace neumožňuje registraci nového účtu"
},
"auth": {
"Challenge method should be S256": "Metoda výzvy by měla být S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Nepodařilo se vytvořit uživatele, informace o uživateli jsou neplatné: %s",
"Failed to login in: %s": "Nepodařilo se přihlásit: %s",
"Invalid token": "Neplatný token",
"State expected: %s, but got: %s": "Očekávaný stav: %s, ale získán: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet přes %%s, prosím použijte jiný způsob registrace",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet, prosím kontaktujte svou IT podporu",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) je již propojen s jiným účtem: %s (%s)",
"The application: %s does not exist": "Aplikace: %s neexistuje",
"The login method: login with LDAP is not enabled for the application": "Metoda přihlášení: přihlášení pomocí LDAP není pro aplikaci povolena",
"The login method: login with SMS is not enabled for the application": "Metoda přihlášení: přihlášení pomocí SMS není pro aplikaci povolena",
"The login method: login with email is not enabled for the application": "Metoda přihlášení: přihlášení pomocí emailu není pro aplikaci povolena",
"The login method: login with face is not enabled for the application": "Metoda přihlášení: přihlášení pomocí obličeje není pro aplikaci povolena",
"The login method: login with password is not enabled for the application": "Metoda přihlášení: přihlášení pomocí hesla není pro aplikaci povolena",
"The organization: %s does not exist": "Organizace: %s neexistuje",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "Poskytovatel: %s není pro aplikaci povolen",
"Unauthorized operation": "Neoprávněná operace",
"Unknown authentication type (not password or provider), form = %s": "Neznámý typ autentizace (není heslo nebo poskytovatel), formulář = %s",
"User's tag: %s is not listed in the application's tags": "Štítek uživatele: %s není uveden v štítcích aplikace",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Placený uživatel %s nemá aktivní nebo čekající předplatné a aplikace: %s nemá výchozí ceny",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Služba %s a %s se neshodují"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Příslušnost nemůže být prázdná",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Výchozí kód neodpovídá pravidlům pro shodu kódů",
"DisplayName cannot be blank": "Zobrazované jméno nemůže být prázdné",
"DisplayName is not valid real name": "Zobrazované jméno není platné skutečné jméno",
"Email already exists": "Email již existuje",
"Email cannot be empty": "Email nemůže být prázdný",
"Email is invalid": "Email je neplatný",
"Empty username.": "Prázdné uživatelské jméno.",
"Face data does not exist, cannot log in": "Data obličeje neexistují, nelze se přihlásit",
"Face data mismatch": "Neshoda dat obličeje",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "Křestní jméno nemůže být prázdné",
"Invitation code cannot be blank": "Pozvánkový kód nemůže být prázdný",
"Invitation code exhausted": "Pozvánkový kód vyčerpán",
"Invitation code is invalid": "Pozvánkový kód je neplatný",
"Invitation code suspended": "Pozvánkový kód pozastaven",
"LDAP user name or password incorrect": "Uživatelské jméno nebo heslo LDAP je nesprávné",
"LastName cannot be blank": "Příjmení nemůže být prázdné",
"Multiple accounts with same uid, please check your ldap server": "Více účtů se stejným uid, prosím zkontrolujte svůj ldap server",
"Organization does not exist": "Organizace neexistuje",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Telefon již existuje",
"Phone cannot be empty": "Telefon nemůže být prázdný",
"Phone number is invalid": "Telefonní číslo je neplatné",
"Please register using the email corresponding to the invitation code": "Prosím zaregistrujte se pomocí emailu odpovídajícího pozvánkovému kódu",
"Please register using the phone corresponding to the invitation code": "Prosím zaregistrujte se pomocí telefonu odpovídajícího pozvánkovému kódu",
"Please register using the username corresponding to the invitation code": "Prosím zaregistrujte se pomocí uživatelského jména odpovídajícího pozvánkovému kódu",
"Session outdated, please login again": "Relace je zastaralá, prosím přihlaste se znovu",
"The invitation code has already been used": "Pozvánkový kód již byl použit",
"The user is forbidden to sign in, please contact the administrator": "Uživatel má zakázáno se přihlásit, prosím kontaktujte administrátora",
"The user: %s doesn't exist in LDAP server": "Uživatel: %s neexistuje na LDAP serveru",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Uživatelské jméno může obsahovat pouze alfanumerické znaky, podtržítka nebo pomlčky, nemůže mít po sobě jdoucí pomlčky nebo podtržítka a nemůže začínat nebo končit pomlčkou nebo podtržítkem.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Hodnota \\\"%s\\\" pro pole účtu \\\"%s\\\" neodpovídá regulárnímu výrazu položky účtu",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Hodnota \\\"%s\\\" pro pole registrace \\\"%s\\\" neodpovídá regulárnímu výrazu položky registrace aplikace \\\"%s\\\"",
"Username already exists": "Uživatelské jméno již existuje",
"Username cannot be an email address": "Uživatelské jméno nemůže být emailová adresa",
"Username cannot contain white spaces": "Uživatelské jméno nemůže obsahovat mezery",
"Username cannot start with a digit": "Uživatelské jméno nemůže začínat číslicí",
"Username is too long (maximum is 255 characters).": "Uživatelské jméno je příliš dlouhé (maximálně 255 znaků).",
"Username must have at least 2 characters": "Uživatelské jméno musí mít alespoň 2 znaky",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Zadali jste špatné heslo nebo kód příliš mnohokrát, prosím počkejte %d minut a zkuste to znovu",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Vaše oblast neumožňuje registraci pomocí telefonu",
"password or code is incorrect": "heslo nebo kód je nesprávné",
"password or code is incorrect, you have %d remaining chances": "heslo nebo kód je nesprávné, máte %d zbývajících pokusů",
"unsupported password type: %s": "nepodporovaný typ hesla: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "Organizace: %s by měla mít alespoň jednu aplikaci",
"The user: %s doesn't exist": "Uživatel: %s neexistuje",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "nepodporuje captchaProvider: ",
"this operation is not allowed in demo mode": "tato operace není povolena v demo režimu",
"this operation requires administrator to perform": "tato operace vyžaduje administrátora"
},
"ldap": {
"Ldap server exist": "Ldap server existuje"
},
"link": {
"Please link first": "Prosím, nejprve propojte",
"This application has no providers": "Tato aplikace nemá žádné poskytovatele",
"This application has no providers of type": "Tato aplikace nemá žádné poskytovatele typu",
"This provider can't be unlinked": "Tento poskytovatel nemůže být odpojen",
"You are not the global admin, you can't unlink other users": "Nejste globální administrátor, nemůžete odpojovat jiné uživatele",
"You can't unlink yourself, you are not a member of any application": "Nemůžete odpojit sami sebe, nejste členem žádné aplikace"
},
"organization": {
"Only admin can modify the %s.": "Pouze administrátor může upravit %s.",
"The %s is immutable.": "%s je neměnný.",
"Unknown modify rule %s.": "Neznámé pravidlo úpravy %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "Oprávnění: \\\"%s\\\" neexistuje"
},
"provider": {
"Invalid application id": "Neplatné ID aplikace",
"the provider: %s does not exist": "poskytovatel: %s neexistuje"
},
"resource": {
"User is nil for tag: avatar": "Uživatel je nil pro tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Uživatelské jméno nebo úplná cesta k souboru je prázdná: uživatelské jméno = %s, úplná cesta k souboru = %s"
},
"saml": {
"Application %s not found": "Aplikace %s nebyla nalezena"
},
"saml_sp": {
"provider %s's category is not SAML": "poskytovatel %s není kategorie SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Prázdné parametry pro emailForm: %v",
"Invalid Email receivers: %s": "Neplatní příjemci emailu: %s",
"Invalid phone receivers: %s": "Neplatní příjemci telefonu: %s"
},
"storage": {
"The objectKey: %s is not allowed": "objectKey: %s není povolen",
"The provider type: %s is not supported": "typ poskytovatele: %s není podporován"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s není v této aplikaci podporován",
"Invalid application or wrong clientSecret": "Neplatná aplikace nebo špatný clientSecret",
"Invalid client_id": "Neplatné client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Přesměrovací URI: %s neexistuje v seznamu povolených přesměrovacích URI",
"Token not found, invalid accessToken": "Token nenalezen, neplatný accessToken"
},
"user": {
"Display name cannot be empty": "Zobrazované jméno nemůže být prázdné",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "Poskytovatel: %s nebyl nalezen"
},
"verification": {
"Invalid captcha provider.": "Neplatný poskytovatel captcha.",
"Phone number is invalid in your region %s": "Telefonní číslo je ve vaší oblasti %s neplatné",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "Ověřovací kód ještě nebyl odeslán!",
"Turing test failed.": "Turingův test selhal.",
"Unable to get the email modify rule.": "Nelze získat pravidlo pro úpravu emailu.",
"Unable to get the phone modify rule.": "Nelze získat pravidlo pro úpravu telefonu.",
"Unknown type": "Neznámý typ",
"Wrong verification code!": "Špatný ověřovací kód!",
"You should verify your code in %d min!": "Měli byste ověřit svůj kód do %d minut!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "prosím přidejte poskytovatele SMS do seznamu \\\"Providers\\\" pro aplikaci: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "prosím přidejte poskytovatele emailu do seznamu \\\"Providers\\\" pro aplikaci: %s",
"the user does not exist, please sign up first": "uživatel neexistuje, prosím nejprve se zaregistrujte"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Prosím, nejprve zavolejte WebAuthnSigninBegin"
}
}

View File

@@ -2,107 +2,128 @@
"account": {
"Failed to add user": "Konnte den Benutzer nicht hinzufügen",
"Get init score failed, error: %w": "Init-Score konnte nicht abgerufen werden, Fehler: %w",
"Please sign out first": "Bitte melden Sie sich zuerst ab",
"The application does not allow to sign up new account": "Die Anwendung erlaubt es nicht, sich für ein neues Konto anzumelden"
},
"auth": {
"Challenge method should be S256": "Die Challenge-Methode sollte S256 sein",
"DeviceCode Invalid": "DeviceCode Invalid",
"DeviceCode Invalid": "Gerätecode ungültig",
"Failed to create user, user information is invalid: %s": "Es konnte kein Benutzer erstellt werden, da die Benutzerinformationen ungültig sind: %s",
"Failed to login in: %s": "Konnte nicht anmelden: %s",
"Invalid token": "Ungültiges Token",
"State expected: %s, but got: %s": "Erwarteter Zustand: %s, aber erhalten: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Das Konto für den Anbieter: %s und Benutzernamen: %s (%s) existiert nicht und darf nicht über %%s als neues Konto erstellt werden. Bitte nutzen Sie einen anderen Weg, um sich anzumelden",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Das Konto für den Anbieter: %s und Benutzernamen: %s (%s) existiert nicht und darf nicht über %s als neues Konto erstellt werden. Bitte nutzen Sie einen anderen Weg, um sich anzumelden",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) existiert nicht und es ist nicht erlaubt, ein neues Konto anzumelden. Bitte wenden Sie sich an Ihren IT-Support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) ist bereits mit einem anderen Konto verknüpft: %s (%s)",
"The application: %s does not exist": "Die Anwendung: %s existiert nicht",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The application: %s has disabled users to signin": "Die Anwendung: %s hat die Anmeldung von Benutzern deaktiviert",
"The group: %s does not exist": "Die Gruppe: %s existiert nicht",
"The login method: login with LDAP is not enabled for the application": "Die Anmeldemethode: Anmeldung mit LDAP ist für die Anwendung nicht aktiviert",
"The login method: login with SMS is not enabled for the application": "Die Anmeldemethode: Anmeldung per SMS ist für die Anwendung nicht aktiviert",
"The login method: login with email is not enabled for the application": "Die Anmeldemethode: Anmeldung per E-Mail ist für die Anwendung nicht aktiviert",
"The login method: login with face is not enabled for the application": "Die Anmeldemethode: Anmeldung per Gesicht ist für die Anwendung nicht aktiviert",
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" ist für die Anwendung nicht aktiviert",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The order: %s does not exist": "Die Bestellung: %s existiert nicht",
"The organization: %s does not exist": "Die Organisation: %s existiert nicht",
"The organization: %s has disabled users to signin": "Die Organisation: %s hat die Anmeldung von Benutzern deaktiviert",
"The plan: %s does not exist": "Der Plan: %s existiert nicht",
"The pricing: %s does not exist": "Die Preisgestaltung: %s existiert nicht",
"The pricing: %s does not have plan: %s": "Die Preisgestaltung: %s hat keinen Plan: %s",
"The provider: %s does not exist": "Der Anbieter: %s existiert nicht",
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
"Unauthorized operation": "Nicht autorisierte Operation",
"Unknown authentication type (not password or provider), form = %s": "Unbekannter Authentifizierungstyp (nicht Passwort oder Anbieter), Formular = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
"User's tag: %s is not listed in the application's tags": "Benutzer-Tag: %s ist nicht in den Tags der Anwendung aufgeführt",
"UserCode Expired": "Benutzercode abgelaufen",
"UserCode Invalid": "Benutzercode ungültig",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Bezahlter Benutzer %s hat kein aktives oder ausstehendes Abonnement und die Anwendung: %s hat keine Standardpreisgestaltung",
"the application for user %s is not found": "Die Anwendung für Benutzer %s wurde nicht gefunden",
"the organization: %s is not found": "Die Organisation: %s wurde nicht gefunden"
},
"cas": {
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"%s does not meet the CIDR format requirements: %s": "%s erfüllt nicht die CIDR-Formatanforderungen: %s",
"Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"CIDR for IP: %s should not be empty": "CIDR für IP: %s darf nicht leer sein",
"Default code does not match the code's matching rules": "Standardcode entspricht nicht den Übereinstimmungsregeln des Codes",
"DisplayName cannot be blank": "Anzeigename kann nicht leer sein",
"DisplayName is not valid real name": "DisplayName ist kein gültiger Vorname",
"DisplayName is not valid real name": "Der Anzeigename ist kein gültiger echter Name",
"Email already exists": "E-Mail existiert bereits",
"Email cannot be empty": "E-Mail darf nicht leer sein",
"Email is invalid": "E-Mail ist ungültig",
"Empty username.": "Leerer Benutzername.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"Face data does not exist, cannot log in": "Gesichtsdaten existieren nicht, Anmeldung nicht möglich",
"Face data mismatch": "Gesichtsdaten stimmen nicht überein",
"Failed to parse client IP: %s": "Fehler beim Parsen der Client-IP: %s",
"FirstName cannot be blank": "Vorname darf nicht leer sein",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Ldap Benutzername oder Passwort falsch",
"Guest users must upgrade their account by setting a username and password before they can sign in directly": "Gastbenutzer müssen ihr Konto aktualisieren, indem sie einen Benutzernamen und ein Passwort festlegen, bevor sie sich direkt anmelden können",
"Invitation code cannot be blank": "Einladungscode darf nicht leer sein",
"Invitation code exhausted": "Einladungscode aufgebraucht",
"Invitation code is invalid": "Einladungscode ist ungültig",
"Invitation code suspended": "Einladungscode ausgesetzt",
"LastName cannot be blank": "Nachname darf nicht leer sein",
"Multiple accounts with same uid, please check your ldap server": "Mehrere Konten mit derselben uid, bitte überprüfen Sie Ihren LDAP-Server",
"Organization does not exist": "Organisation existiert nicht",
"Password cannot be empty": "Password cannot be empty",
"Password cannot be empty": "Passwort darf nicht leer sein",
"Phone already exists": "Telefon existiert bereits",
"Phone cannot be empty": "Das Telefon darf nicht leer sein",
"Phone number is invalid": "Die Telefonnummer ist ungültig",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Please register using the email corresponding to the invitation code": "Bitte registrieren Sie sich mit der E-Mail, die zum Einladungscode gehört",
"Please register using the phone corresponding to the invitation code": "Bitte registrieren Sie sich mit der Telefonnummer, die zum Einladungscode gehört",
"Please register using the username corresponding to the invitation code": "Bitte registrieren Sie sich mit dem Benutzernamen, der zum Einladungscode gehört",
"Session outdated, please login again": "Sitzung abgelaufen, bitte erneut anmelden",
"The invitation code has already been used": "The invitation code has already been used",
"The invitation code has already been used": "Der Einladungscode wurde bereits verwendet",
"The password must contain at least one special character": "Das Passwort muss mindestens ein Sonderzeichen enthalten",
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Das Passwort muss mindestens einen Großbuchstaben, einen Kleinbuchstaben und eine Ziffer enthalten",
"The password must have at least 6 characters": "Das Passwort muss mindestens 6 Zeichen haben",
"The password must have at least 8 characters": "Das Passwort muss mindestens 8 Zeichen haben",
"The password must not contain any repeated characters": "Das Passwort darf keine wiederholten Zeichen enthalten",
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Der Benutzer wurde gelöscht und kann nicht zur Anmeldung verwendet werden. Bitte wenden Sie sich an den Administrator",
"The user is forbidden to sign in, please contact the administrator": "Dem Benutzer ist der Zugang verboten, bitte kontaktieren Sie den Administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The user: %s doesn't exist in LDAP server": "Der Benutzer: %s existiert nicht im LDAP-Server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Der Benutzername darf nur alphanumerische Zeichen, Unterstriche oder Bindestriche enthalten, keine aufeinanderfolgenden Bindestriche oder Unterstriche haben und darf nicht mit einem Bindestrich oder Unterstrich beginnen oder enden.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "Der Wert \"%s\" für das Kontenfeld \"%s\" stimmt nicht mit dem Kontenelement-Regex überein",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "Der Wert \"%s\" für das Registrierungsfeld \"%s\" stimmt nicht mit dem Registrierungselement-Regex der Anwendung \"%s\" überein",
"Username already exists": "Benutzername existiert bereits",
"Username cannot be an email address": "Benutzername kann keine E-Mail-Adresse sein",
"Username cannot contain white spaces": "Benutzername darf keine Leerzeichen enthalten",
"Username cannot start with a digit": "Benutzername darf nicht mit einer Ziffer beginnen",
"Username is too long (maximum is 255 characters).": "Benutzername ist zu lang (das Maximum beträgt 255 Zeichen).",
"Username must have at least 2 characters": "Benutzername muss mindestens 2 Zeichen lang sein",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Benutzername unterstützt E-Mail-Format. Der Benutzername darf nur alphanumerische Zeichen, Unterstriche oder Bindestriche enthalten, keine aufeinanderfolgenden Bindestriche oder Unterstriche haben und darf nicht mit einem Bindestrich oder Unterstrich beginnen oder enden. Achten Sie auch auf das E-Mail-Format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Sie haben zu oft das falsche Passwort oder den falschen Code eingegeben. Bitte warten Sie %d Minuten und versuchen Sie es erneut",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your IP address: %s has been banned according to the configuration of: ": "Ihre IP-Adresse: %s wurde laut Konfiguration gesperrt von: ",
"Your password has expired. Please reset your password by clicking \"Forgot password\"": "Ihr Passwort ist abgelaufen. Bitte setzen Sie Ihr Passwort zurück, indem Sie auf \"Passwort vergessen\" klicken",
"Your region is not allow to signup by phone": "Ihre Region ist nicht berechtigt, sich telefonisch anzumelden",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "Das Passwort oder der Code ist falsch. Du hast noch %d Versuche übrig",
"password or code is incorrect": "Passwort oder Code ist falsch",
"password or code is incorrect, you have %s remaining chances": "Das Passwort oder der Code ist falsch. Du hast noch %s Versuche übrig",
"unsupported password type: %s": "Nicht unterstützter Passworttyp: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
"the adapter: %s is not found": "Der Adapter: %s wurde nicht gefunden"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import groups": "Gruppen importieren fehlgeschlagen",
"Failed to import users": "Fehler beim Importieren von Benutzern",
"Insufficient balance: new balance %v would be below credit limit %v": "Unzureichendes Guthaben: neues Guthaben %v wäre unter dem Kreditlimit %v",
"Insufficient balance: new organization balance %v would be below credit limit %v": "Unzureichendes Guthaben: neues Organisationsguthaben %v wäre unter dem Kreditlimit %v",
"Missing parameter": "Fehlender Parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Only admin user can specify user": "Nur Administrator kann Benutzer angeben",
"Please login first": "Bitte zuerst einloggen",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The LDAP: %s does not exist": "Das LDAP: %s existiert nicht",
"The organization: %s should have one application at least": "Die Organisation: %s sollte mindestens eine Anwendung haben",
"The syncer: %s does not exist": "Der Synchronizer: %s existiert nicht",
"The user: %s doesn't exist": "Der Benutzer %s existiert nicht",
"Wrong userId": "Wrong userId",
"The user: %s is not found": "Der Benutzer: %s wurde nicht gefunden",
"User is required for User category transaction": "Benutzer ist für Benutzer-Kategorie-Transaktionen erforderlich",
"Wrong userId": "Falsche Benutzer-ID",
"don't support captchaProvider: ": "Unterstütze captchaProvider nicht:",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
"this operation is not allowed in demo mode": "Dieser Vorgang ist im Demo-Modus nicht erlaubt",
"this operation requires administrator to perform": "Dieser Vorgang erfordert einen Administrator zur Ausführung"
},
"invitation": {
"Invitation %s does not exist": "Einladung %s existiert nicht"
},
"ldap": {
"Ldap server exist": "Es gibt einen LDAP-Server"
@@ -119,13 +140,19 @@
"Only admin can modify the %s.": "Nur der Administrator kann das %s ändern.",
"The %s is immutable.": "Das %s ist unveränderlich.",
"Unknown modify rule %s.": "Unbekannte Änderungsregel %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "Das Hinzufügen eines neuen Benutzers zur 'eingebauten' Organisation ist derzeit deaktiviert. Bitte beachten Sie: Alle Benutzer in der 'eingebauten' Organisation sind globale Administratoren in Casdoor. Siehe die Docs: https://casdoor.org/docs/basic/core-concepts#how -does-casdoor-manage-sich selbst. Wenn Sie immer noch einen Benutzer für die 'eingebaute' Organisation erstellen möchten, gehen Sie auf die Einstellungsseite der Organisation und aktivieren Sie die Option 'Habt Berechtigungszustimmung'."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
"The permission: \"%s\" doesn't exist": "Die Berechtigung: \"%s\" existiert nicht"
},
"product": {
"Product list cannot be empty": "Produktliste darf nicht leer sein"
},
"provider": {
"Failed to initialize ID Verification provider": "ID-Verifizierungsanbieter konnte nicht initialisiert werden",
"Invalid application id": "Ungültige Anwendungs-ID",
"No ID Verification provider configured": "Kein ID-Verifizierungsanbieter konfiguriert",
"Provider is not an ID Verification provider": "Anbieter ist kein ID-Verifizierungsanbieter",
"the provider: %s does not exist": "Der Anbieter %s existiert nicht"
},
"resource": {
@@ -143,12 +170,18 @@
"Invalid Email receivers: %s": "Ungültige E-Mail-Empfänger: %s",
"Invalid phone receivers: %s": "Ungültige Telefonempfänger: %s"
},
"session": {
"session id %s is the current session and cannot be deleted": "Sitzungs-ID %s ist die aktuelle Sitzung und kann nicht gelöscht werden"
},
"storage": {
"The objectKey: %s is not allowed": "Der Objektschlüssel %s ist nicht erlaubt",
"The provider type: %s is not supported": "Der Anbieter-Typ %s wird nicht unterstützt"
},
"subscription": {
"Error": "Error"
"Error": "Fehler"
},
"ticket": {
"Ticket not found": "Ticket nicht gefunden"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s wird von dieser Anwendung nicht unterstützt",
@@ -159,10 +192,15 @@
},
"user": {
"Display name cannot be empty": "Anzeigename darf nicht leer sein",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"ID card information and real name are required": "Personalausweisinformationen und vollständiger Name sind erforderlich",
"Identity verification failed": "Identitätsprüfung fehlgeschlagen",
"MFA email is enabled but email is empty": "MFA-E-Mail ist aktiviert, aber E-Mail ist leer",
"MFA phone is enabled but phone number is empty": "MFA-Telefon ist aktiviert, aber Telefonnummer ist leer",
"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"
"No application found for user": "Keine Anwendung für Benutzer gefunden",
"The new password must be different from your current password": "Das neue Passwort muss sich von Ihrem aktuellen Passwort unterscheiden",
"User is already verified": "Benutzer ist bereits verifiziert",
"the user's owner and name should not be empty": "Eigentümer und Name des Benutzers dürfen nicht leer sein"
},
"util": {
"No application is found for userId: %s": "Es wurde keine Anwendung für die Benutzer-ID gefunden: %s",
@@ -172,19 +210,21 @@
"verification": {
"Invalid captcha provider.": "Ungültiger Captcha-Anbieter.",
"Phone number is invalid in your region %s": "Die Telefonnummer ist in Ihrer Region %s ungültig",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The forgot password feature is disabled": "Die Funktion \"Passwort vergessen\" ist deaktiviert",
"The verification code has already been used!": "Der Verifizierungscode wurde bereits verwendet!",
"The verification code has not been sent yet!": "Der Verifizierungscode wurde noch nicht gesendet!",
"Turing test failed.": "Turing-Test fehlgeschlagen.",
"Unable to get the email modify rule.": "Nicht in der Lage, die E-Mail-Änderungsregel zu erhalten.",
"Unable to get the phone modify rule.": "Nicht in der Lage, die Telefon-Änderungsregel zu erhalten.",
"Unknown type": "Unbekannter Typ",
"Wrong verification code!": "Falscher Bestätigungscode!",
"You should verify your code in %d min!": "Du solltest deinen Code in %d Minuten verifizieren!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"please add a SMS provider to the \"Providers\" list for the application: %s": "Bitte fügen Sie einen SMS-Anbieter zur \"Providers\"-Liste für die Anwendung hinzu: %s",
"please add an Email provider to the \"Providers\" list for the application: %s": "Bitte fügen Sie einen E-Mail-Anbieter zur \"Providers\"-Liste für die Anwendung hinzu: %s",
"the user does not exist, please sign up first": "Der Benutzer existiert nicht, bitte zuerst anmelden"
},
"webauthn": {
"Found no credentials for this user": "Für diesen Benutzer wurden keine Anmeldeinformationen gefunden",
"Please call WebAuthnSigninBegin first": "Bitte rufen Sie zuerst WebAuthnSigninBegin auf"
}
}

View File

@@ -2,7 +2,6 @@
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
@@ -12,16 +11,23 @@
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The application: %s has disabled users to signin": "The application: %s has disabled users to signin",
"The group: %s does not exist": "The group: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The order: %s does not exist": "The order: %s does not exist",
"The organization: %s does not exist": "The organization: %s does not exist",
"The organization: %s has disabled users to signin": "The organization: %s has disabled users to signin",
"The plan: %s does not exist": "The plan: %s does not exist",
"The pricing: %s does not exist": "The pricing: %s does not exist",
"The pricing: %s does not have plan: %s": "The pricing: %s does not have plan: %s",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
@@ -51,11 +57,11 @@
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Guest users must upgrade their account by setting a username and password before they can sign in directly": "Guest users must upgrade their account by setting a username and password before they can sign in directly",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
@@ -68,11 +74,17 @@
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The password must contain at least one special character": "The password must contain at least one special character",
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "The password must contain at least one uppercase letter, one lowercase letter and one digit",
"The password must have at least 6 characters": "The password must have at least 6 characters",
"The password must have at least 8 characters": "The password must have at least 8 characters",
"The password must not contain any repeated characters": "The password must not contain any repeated characters",
"The user has been deleted and cannot be used to sign in, please contact the administrator": "The user has been deleted and cannot be used to sign in, please contact the administrator",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "The value \"%s\" for account field \"%s\" doesn't match the account item regex",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
@@ -82,10 +94,10 @@
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your password has expired. Please reset your password by clicking \"Forgot password\"": "Your password has expired. Please reset your password by clicking \"Forgot password\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"password or code is incorrect, you have %s remaining chances": "password or code is incorrect, you have %s remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
@@ -94,16 +106,25 @@
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Insufficient balance: new balance %v would be below credit limit %v": "Insufficient balance: new balance %v would be below credit limit %v",
"Insufficient balance: new organization balance %v would be below credit limit %v": "Insufficient balance: new organization balance %v would be below credit limit %v",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The LDAP: %s does not exist": "The LDAP: %s does not exist",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The syncer: %s does not exist": "The syncer: %s does not exist",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The user: %s is not found": "The user: %s is not found",
"User is required for User category transaction": "User is required for User category transaction",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"invitation": {
"Invitation %s does not exist": "Invitation %s does not exist"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
@@ -122,10 +143,16 @@
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
"The permission: \"%s\" doesn't exist": "The permission: \"%s\" doesn't exist"
},
"product": {
"Product list cannot be empty": "Product list cannot be empty"
},
"provider": {
"Failed to initialize ID Verification provider": "Failed to initialize ID Verification provider",
"Invalid application id": "Invalid application id",
"No ID Verification provider configured": "No ID Verification provider configured",
"Provider is not an ID Verification provider": "Provider is not an ID Verification provider",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
@@ -143,6 +170,9 @@
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"session": {
"session id %s is the current session and cannot be deleted": "session id %s is the current session and cannot be deleted"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
@@ -150,6 +180,9 @@
"subscription": {
"Error": "Error"
},
"ticket": {
"Ticket not found": "Ticket not found"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
@@ -159,9 +192,14 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"ID card information and real name are required": "ID card information and real name are required",
"Identity verification failed": "Identity verification failed",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"No application found for user": "No application found for user",
"The new password must be different from your current password": "The new password must be different from your current password",
"User is already verified": "User is already verified",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
@@ -172,6 +210,7 @@
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The forgot password feature is disabled": "The forgot password feature is disabled",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
@@ -180,11 +219,12 @@
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"please add a SMS provider to the \"Providers\" list for the application: %s": "please add a SMS provider to the \"Providers\" list for the application: %s",
"please add an Email provider to the \"Providers\" list for the application: %s": "please add an Email provider to the \"Providers\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -2,107 +2,128 @@
"account": {
"Failed to add user": "No se pudo agregar el usuario",
"Get init score failed, error: %w": "Error al obtener el puntaje de inicio, error: %w",
"Please sign out first": "Por favor, cierra sesión primero",
"The application does not allow to sign up new account": "La aplicación no permite registrarse con una cuenta nueva"
},
"auth": {
"Challenge method should be S256": "El método de desafío debe ser S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"DeviceCode Invalid": "Código de dispositivo inválido",
"Failed to create user, user information is invalid: %s": "No se pudo crear el usuario, la información del usuario es inválida: %s",
"Failed to login in: %s": "No se ha podido iniciar sesión en: %s",
"Invalid token": "Token inválido",
"State expected: %s, but got: %s": "Estado esperado: %s, pero se obtuvo: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "La cuenta para el proveedor: %s y nombre de usuario: %s (%s) no existe y no está permitido registrarse como una cuenta nueva a través de %%s, por favor use otro método para registrarse",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "La cuenta para el proveedor: %s y nombre de usuario: %s (%s) no existe y no está permitido registrarse como una cuenta nueva a través de %s, por favor use otro método para registrarse",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "La cuenta para el proveedor: %s y el nombre de usuario: %s (%s) no existe y no se permite registrarse como una nueva cuenta, por favor contacte a su soporte de TI",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "La cuenta para proveedor: %s y nombre de usuario: %s (%s) ya está vinculada a otra cuenta: %s (%s)",
"The application: %s does not exist": "La aplicación: %s no existe",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The application: %s has disabled users to signin": "La aplicación: %s ha desactivado el inicio de sesión de usuarios",
"The group: %s does not exist": "El grupo: %s no existe",
"The login method: login with LDAP is not enabled for the application": "El método de inicio de sesión: inicio de sesión con LDAP no está habilitado para la aplicación",
"The login method: login with SMS is not enabled for the application": "El método de inicio de sesión: inicio de sesión con SMS no está habilitado para la aplicación",
"The login method: login with email is not enabled for the application": "El método de inicio de sesión: inicio de sesión con correo electrónico no está habilitado para la aplicación",
"The login method: login with face is not enabled for the application": "El método de inicio de sesión: inicio de sesión con reconocimiento facial no está habilitado para la aplicación",
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña no está habilitado para la aplicación",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The order: %s does not exist": "El pedido: %s no existe",
"The organization: %s does not exist": "La organización: %s no existe",
"The organization: %s has disabled users to signin": "La organización: %s ha desactivado el inicio de sesión de usuarios",
"The plan: %s does not exist": "El plan: %s no existe",
"The pricing: %s does not exist": "El precio: %s no existe",
"The pricing: %s does not have plan: %s": "El precio: %s no tiene el plan: %s",
"The provider: %s does not exist": "El proveedor: %s no existe",
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
"Unauthorized operation": "Operación no autorizada",
"Unknown authentication type (not password or provider), form = %s": "Tipo de autenticación desconocido (no es contraseña o proveedor), formulario = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
"User's tag: %s is not listed in the application's tags": "La etiqueta del usuario: %s no está incluida en las etiquetas de la aplicación",
"UserCode Expired": "Código de usuario expirado",
"UserCode Invalid": "Código de usuario inválido",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "El usuario de pago %s no tiene una suscripción activa o pendiente y la aplicación %s no tiene precios predeterminados",
"the application for user %s is not found": "no se encontró la aplicación para el usuario %s",
"the organization: %s is not found": "no se encontró la organización: %s"
},
"cas": {
"Service %s and %s do not match": "Los servicios %s y %s no coinciden"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Afiliación no puede estar en blanco",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"%s does not meet the CIDR format requirements: %s": "%s no cumple con los requisitos del formato CIDR: %s",
"Affiliation cannot be blank": "La afiliación no puede estar vacía",
"CIDR for IP: %s should not be empty": "El CIDR para la IP: %s no debe estar vacío",
"Default code does not match the code's matching rules": "El código predeterminado no cumple con las reglas de validación del código",
"DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco",
"DisplayName is not valid real name": "El nombre de pantalla no es un nombre real válido",
"Email already exists": "El correo electrónico ya existe",
"Email cannot be empty": "El correo electrónico no puede estar vacío",
"Email is invalid": "El correo electrónico no es válido",
"Empty username.": "Nombre de usuario vacío.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"Face data does not exist, cannot log in": "No existen datos faciales, no se puede iniciar sesión",
"Face data mismatch": "Los datos faciales no coinciden",
"Failed to parse client IP: %s": "Error al analizar la IP del cliente: %s",
"FirstName cannot be blank": "El nombre no puede estar en blanco",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Nombre de usuario o contraseña de Ldap incorrectos",
"Guest users must upgrade their account by setting a username and password before they can sign in directly": "Los usuarios invitados deben actualizar su cuenta configurando un nombre de usuario y una contraseña antes de poder iniciar sesión directamente",
"Invitation code cannot be blank": "El código de invitación no puede estar vacío",
"Invitation code exhausted": "Código de invitación agotado",
"Invitation code is invalid": "Código de invitación inválido",
"Invitation code suspended": "Código de invitación suspendido",
"LastName cannot be blank": "El apellido no puede estar en blanco",
"Multiple accounts with same uid, please check your ldap server": "Cuentas múltiples con el mismo uid, por favor revise su servidor ldap",
"Organization does not exist": "La organización no existe",
"Password cannot be empty": "Password cannot be empty",
"Password cannot be empty": "La contraseña no puede estar vacía",
"Phone already exists": "El teléfono ya existe",
"Phone cannot be empty": "Teléfono no puede estar vacío",
"Phone number is invalid": "El número de teléfono no es válido",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Please register using the email corresponding to the invitation code": "Regístrese usando el correo electrónico correspondiente al código de invitación",
"Please register using the phone corresponding to the invitation code": "Regístrese usando el número de teléfono correspondiente al código de invitación",
"Please register using the username corresponding to the invitation code": "Regístrese usando el nombre de usuario correspondiente al código de invitación",
"Session outdated, please login again": "Sesión expirada, por favor vuelva a iniciar sesión",
"The invitation code has already been used": "The invitation code has already been used",
"The invitation code has already been used": "El código de invitación ya ha sido utilizado",
"The password must contain at least one special character": "La contraseña debe contener al menos un carácter especial",
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "La contraseña debe contener al menos una letra mayúscula, una letra minúscula y un dígito",
"The password must have at least 6 characters": "La contraseña debe tener al menos 6 caracteres",
"The password must have at least 8 characters": "La contraseña debe tener al menos 8 caracteres",
"The password must not contain any repeated characters": "La contraseña no debe contener caracteres repetidos",
"The user has been deleted and cannot be used to sign in, please contact the administrator": "El usuario ha sido eliminado y no se puede usar para iniciar sesión, póngase en contacto con el administrador",
"The user is forbidden to sign in, please contact the administrator": "El usuario no está autorizado a iniciar sesión, por favor contacte al administrador",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The user: %s doesn't exist in LDAP server": "El usuario: %s no existe en el servidor LDAP",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "El nombre de usuario solo puede contener caracteres alfanuméricos, guiones bajos o guiones, no puede tener guiones o subrayados consecutivos, y no puede comenzar ni terminar con un guión o subrayado.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "El valor \"%s\" para el campo de cuenta \"%s\" no coincide con la expresión regular del elemento de cuenta",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "El valor \"%s\" para el campo de registro \"%s\" no coincide con la expresión regular del elemento de registro de la aplicación \"%s\"",
"Username already exists": "El nombre de usuario ya existe",
"Username cannot be an email address": "Nombre de usuario no puede ser una dirección de correo electrónico",
"Username cannot contain white spaces": "Nombre de usuario no puede contener espacios en blanco",
"Username cannot start with a digit": "El nombre de usuario no puede empezar con un dígito",
"Username is too long (maximum is 255 characters).": "El nombre de usuario es demasiado largo (el máximo es de 255 caracteres).",
"Username must have at least 2 characters": "Nombre de usuario debe tener al menos 2 caracteres",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "El nombre de usuario admite formato de correo electrónico. Además, el nombre de usuario solo puede contener caracteres alfanuméricos, guiones bajos o guiones, no puede tener guiones bajos o guiones consecutivos y no puede comenzar ni terminar con un guión o guión bajo. También preste atención al formato del correo electrónico.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Has ingresado la contraseña o código incorrecto demasiadas veces, por favor espera %d minutos e intenta de nuevo",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your IP address: %s has been banned according to the configuration of: ": "Su dirección IP: %s ha sido bloqueada según la configuración de: ",
"Your password has expired. Please reset your password by clicking \"Forgot password\"": "Su contraseña ha expirado. Restablezca su contraseña haciendo clic en \"Olvidé mi contraseña\"",
"Your region is not allow to signup by phone": "Tu región no está permitida para registrarse por teléfono",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "Contraseña o código incorrecto, tienes %d intentos restantes",
"password or code is incorrect": "contraseña o código incorrecto",
"password or code is incorrect, you have %s remaining chances": "Contraseña o código incorrecto, tienes %s intentos restantes",
"unsupported password type: %s": "Tipo de contraseña no compatible: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
"the adapter: %s is not found": "no se encontró el adaptador: %s"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import groups": "Error al importar grupos",
"Failed to import users": "Error al importar usuarios",
"Insufficient balance: new balance %v would be below credit limit %v": "Saldo insuficiente: el nuevo saldo %v estaría por debajo del límite de crédito %v",
"Insufficient balance: new organization balance %v would be below credit limit %v": "Saldo insuficiente: el nuevo saldo de la organización %v estaría por debajo del límite de crédito %v",
"Missing parameter": "Parámetro faltante",
"Only admin user can specify user": "Only admin user can specify user",
"Only admin user can specify user": "Solo el usuario administrador puede especificar usuario",
"Please login first": "Por favor, inicia sesión primero",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The LDAP: %s does not exist": "El LDAP: %s no existe",
"The organization: %s should have one application at least": "La organización: %s debe tener al menos una aplicación",
"The syncer: %s does not exist": "El sincronizador: %s no existe",
"The user: %s doesn't exist": "El usuario: %s no existe",
"Wrong userId": "Wrong userId",
"The user: %s is not found": "El usuario: %s no encontrado",
"User is required for User category transaction": "El usuario es obligatorio para la transacción de la categoría Usuario",
"Wrong userId": "ID de usuario incorrecto",
"don't support captchaProvider: ": "No apoyo a captchaProvider",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
"this operation is not allowed in demo mode": "esta operación no está permitida en modo de demostración",
"this operation requires administrator to perform": "esta operación requiere que el administrador la realice"
},
"invitation": {
"Invitation %s does not exist": "La invitación %s no existe"
},
"ldap": {
"Ldap server exist": "El servidor LDAP existe"
@@ -119,13 +140,19 @@
"Only admin can modify the %s.": "Solo el administrador puede modificar los %s.",
"The %s is immutable.": "El %s es inmutable.",
"Unknown modify rule %s.": "Regla de modificación desconocida %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "La adición de un nuevo usuario a la organización 'integrada' está actualmente deshabilitada. Tenga en cuenta: todos los usuarios de la organización 'integrada' son administradores globales en Casdoor. Consulte los docs: https://casdoor.org/docs/basic/core-concepts#how -does-casdoor-manage-itself. Si todavía desea crear un usuario para la organización 'integrada', vaya a la página de configuración de la organización y habilite la opción 'Tiene consentimiento de privilegios'."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
"The permission: \"%s\" doesn't exist": "El permiso: \"%s\" no existe"
},
"product": {
"Product list cannot be empty": "La lista de productos no puede estar vacía"
},
"provider": {
"Failed to initialize ID Verification provider": "Error al inicializar el proveedor de verificación de ID",
"Invalid application id": "Identificación de aplicación no válida",
"No ID Verification provider configured": "No hay proveedor de verificación de ID configurado",
"Provider is not an ID Verification provider": "El proveedor no es un proveedor de verificación de ID",
"the provider: %s does not exist": "El proveedor: %s no existe"
},
"resource": {
@@ -143,6 +170,9 @@
"Invalid Email receivers: %s": "Receptores de correo electrónico no válidos: %s",
"Invalid phone receivers: %s": "Receptores de teléfono no válidos: %s"
},
"session": {
"session id %s is the current session and cannot be deleted": "session id %s is the current session and cannot be deleted"
},
"storage": {
"The objectKey: %s is not allowed": "El objectKey: %s no está permitido",
"The provider type: %s is not supported": "El tipo de proveedor: %s no es compatible"
@@ -150,6 +180,9 @@
"subscription": {
"Error": "Error"
},
"ticket": {
"Ticket not found": "Ticket no encontrado"
},
"token": {
"Grant_type: %s is not supported in this application": "El tipo de subvención: %s no es compatible con esta aplicación",
"Invalid application or wrong clientSecret": "Solicitud inválida o clientSecret incorrecto",
@@ -159,10 +192,15 @@
},
"user": {
"Display name cannot be empty": "El nombre de pantalla no puede estar vacío",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"ID card information and real name are required": "Se requiere información de la tarjeta de identificación y el nombre real",
"Identity verification failed": "Falló la verificación de identidad",
"MFA email is enabled but email is empty": "El correo electrónico MFA está habilitado pero el correo está vacío",
"MFA phone is enabled but phone number is empty": "El teléfono MFA está habilitado pero el número de teléfono está vacío",
"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"
"No application found for user": "No se encontró aplicación para el usuario",
"The new password must be different from your current password": "La nueva contraseña debe ser diferente de su contraseña actual",
"User is already verified": "El usuario ya está verificado",
"the user's owner and name should not be empty": "el propietario y el nombre del usuario no deben estar vacíos"
},
"util": {
"No application is found for userId: %s": "No se encuentra ninguna aplicación para el Id de usuario: %s",
@@ -172,19 +210,21 @@
"verification": {
"Invalid captcha provider.": "Proveedor de captcha no válido.",
"Phone number is invalid in your region %s": "El número de teléfono es inválido en tu región %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The forgot password feature is disabled": "La función de contraseña olvidada está deshabilitada",
"The verification code has already been used!": "¡El código de verificación ya ha sido utilizado!",
"The verification code has not been sent yet!": "¡El código de verificación aún no ha sido enviado!",
"Turing test failed.": "El test de Turing falló.",
"Unable to get the email modify rule.": "No se puede obtener la regla de modificación de correo electrónico.",
"Unable to get the phone modify rule.": "No se pudo obtener la regla de modificación del teléfono.",
"Unknown type": "Tipo desconocido",
"Wrong verification code!": "¡Código de verificación incorrecto!",
"You should verify your code in %d min!": "¡Deberías verificar tu código en %d minutos!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"please add a SMS provider to the \"Providers\" list for the application: %s": "agregue un proveedor de SMS a la lista \"Proveedores\" para la aplicación: %s",
"please add an Email provider to the \"Providers\" list for the application: %s": "agregue un proveedor de correo electrónico a la lista \"Proveedores\" para la aplicación: %s",
"the user does not exist, please sign up first": "El usuario no existe, por favor regístrese primero"
},
"webauthn": {
"Found no credentials for this user": "No se encontraron credenciales para este usuario",
"Please call WebAuthnSigninBegin first": "Por favor, llama primero a WebAuthnSigninBegin"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "عدم موفقیت در افزودن کاربر",
"Get init score failed, error: %w": "عدم موفقیت در دریافت امتیاز اولیه، خطا: %w",
"Please sign out first": "لطفاً ابتدا خارج شوید",
"The application does not allow to sign up new account": "برنامه اجازه ثبت‌نام حساب جدید را نمی‌دهد"
},
"auth": {
"Challenge method should be S256": "روش چالش باید S256 باشد",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "عدم موفقیت در ایجاد کاربر، اطلاعات کاربر نامعتبر است: %s",
"Failed to login in: %s": "عدم موفقیت در ورود: %s",
"Invalid token": "توکن نامعتبر",
"State expected: %s, but got: %s": "وضعیت مورد انتظار: %s، اما دریافت شد: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "حساب برای ارائه‌دهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبت‌نام به‌عنوان حساب جدید از طریق %%s نیست، لطفاً از روش دیگری برای ثبت‌نام استفاده کنید",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "حساب برای ارائه‌دهنده: %s و نام کاربری: %s (%s) وجود ندارد و مجاز به ثبت‌نام به‌عنوان حساب جدید نیست، لطفاً با پشتیبانی IT خود تماس بگیرید",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "حساب برای ارائه‌دهنده: %s و نام کاربری: %s (%s) در حال حاضر به حساب دیگری مرتبط است: %s (%s)",
"The application: %s does not exist": "برنامه: %s وجود ندارد",
"The login method: login with LDAP is not enabled for the application": "روش ورود: ورود با LDAP برای برنامه فعال نیست",
"The login method: login with SMS is not enabled for the application": "روش ورود: ورود با پیامک برای برنامه فعال نیست",
"The login method: login with email is not enabled for the application": "روش ورود: ورود با ایمیل برای برنامه فعال نیست",
"The login method: login with face is not enabled for the application": "روش ورود: ورود با چهره برای برنامه فعال نیست",
"The login method: login with password is not enabled for the application": "روش ورود: ورود با رمز عبور برای برنامه فعال نیست",
"The organization: %s does not exist": "سازمان: %s وجود ندارد",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "ارائه‌دهنده: %s برای برنامه فعال نیست",
"Unauthorized operation": "عملیات غیرمجاز",
"Unknown authentication type (not password or provider), form = %s": "نوع احراز هویت ناشناخته (نه رمز عبور و نه ارائه‌دهنده)، فرم = %s",
"User's tag: %s is not listed in the application's tags": "برچسب کاربر: %s در برچسب‌های برنامه فهرست نشده است",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "کاربر پرداختی %s اشتراک فعال یا در انتظار ندارد و برنامه: %s قیمت‌گذاری پیش‌فرض ندارد",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "سرویس %s و %s مطابقت ندارند"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "وابستگی نمی‌تواند خالی باشد",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "کد پیش‌فرض با قوانین تطبیق کد مطابقت ندارد",
"DisplayName cannot be blank": "نام نمایشی نمی‌تواند خالی باشد",
"DisplayName is not valid real name": "نام نمایشی یک نام واقعی معتبر نیست",
"Email already exists": "ایمیل قبلاً وجود دارد",
"Email cannot be empty": "ایمیل نمی‌تواند خالی باشد",
"Email is invalid": "ایمیل نامعتبر است",
"Empty username.": "نام کاربری خالی است.",
"Face data does not exist, cannot log in": "داده‌های چهره وجود ندارد، نمی‌توان وارد شد",
"Face data mismatch": "عدم تطابق داده‌های چهره",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "نام نمی‌تواند خالی باشد",
"Invitation code cannot be blank": "کد دعوت نمی‌تواند خالی باشد",
"Invitation code exhausted": "کد دعوت استفاده شده است",
"Invitation code is invalid": "کد دعوت نامعتبر است",
"Invitation code suspended": "کد دعوت معلق است",
"LDAP user name or password incorrect": "نام کاربری یا رمز عبور LDAP نادرست است",
"LastName cannot be blank": "نام خانوادگی نمی‌تواند خالی باشد",
"Multiple accounts with same uid, please check your ldap server": "چندین حساب با uid یکسان، لطفاً سرور LDAP خود را بررسی کنید",
"Organization does not exist": "سازمان وجود ندارد",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "تلفن قبلاً وجود دارد",
"Phone cannot be empty": "تلفن نمی‌تواند خالی باشد",
"Phone number is invalid": "شماره تلفن نامعتبر است",
"Please register using the email corresponding to the invitation code": "لطفاً با استفاده از ایمیل مربوط به کد دعوت ثبت‌نام کنید",
"Please register using the phone corresponding to the invitation code": "لطفاً با استفاده از تلفن مربوط به کد دعوت ثبت‌نام کنید",
"Please register using the username corresponding to the invitation code": "لطفاً با استفاده از نام کاربری مربوط به کد دعوت ثبت‌نام کنید",
"Session outdated, please login again": "جلسه منقضی شده است، لطفاً دوباره وارد شوید",
"The invitation code has already been used": "کد دعوت قبلاً استفاده شده است",
"The user is forbidden to sign in, please contact the administrator": "ورود کاربر ممنوع است، لطفاً با مدیر تماس بگیرید",
"The user: %s doesn't exist in LDAP server": "کاربر: %s در سرور LDAP وجود ندارد",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "نام کاربری فقط می‌تواند حاوی کاراکترهای الفبایی عددی، زیرخط یا خط تیره باشد، نمی‌تواند خط تیره یا زیرخط متوالی داشته باشد، و نمی‌تواند با خط تیره یا زیرخط شروع یا پایان یابد.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "نام کاربری قبلاً وجود دارد",
"Username cannot be an email address": "نام کاربری نمی‌تواند یک آدرس ایمیل باشد",
"Username cannot contain white spaces": "نام کاربری نمی‌تواند حاوی فاصله باشد",
"Username cannot start with a digit": "نام کاربری نمی‌تواند با یک رقم شروع شود",
"Username is too long (maximum is 255 characters).": "نام کاربری بیش از حد طولانی است (حداکثر ۳۹ کاراکتر).",
"Username must have at least 2 characters": "نام کاربری باید حداقل ۲ کاراکتر داشته باشد",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "شما رمز عبور یا کد اشتباه را بیش از حد وارد کرده‌اید، لطفاً %d دقیقه صبر کنید و دوباره تلاش کنید",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "منطقه شما اجازه ثبت‌نام با تلفن را ندارد",
"password or code is incorrect": "رمز عبور یا کد نادرست است",
"password or code is incorrect, you have %d remaining chances": "رمز عبور یا کد نادرست است، شما %d فرصت باقی‌مانده دارید",
"unsupported password type: %s": "نوع رمز عبور پشتیبانی نشده: %s"
},
"enforcer": {
"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": "لطفاً ابتدا وارد شوید",
"The organization: %s should have one application at least": "سازمان: %s باید حداقل یک برنامه داشته باشد",
"The user: %s doesn't exist": "کاربر: %s وجود ندارد",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "از captchaProvider پشتیبانی نمی‌شود: ",
"this operation is not allowed in demo mode": "این عملیات در حالت دمو مجاز نیست",
"this operation requires administrator to perform": "این عملیات نیاز به مدیر برای انجام دارد"
},
"ldap": {
"Ldap server exist": "سرور LDAP وجود دارد"
},
"link": {
"Please link first": "لطفاً ابتدا پیوند دهید",
"This application has no providers": "این برنامه ارائه‌دهنده‌ای ندارد",
"This application has no providers of type": "این برنامه ارائه‌دهنده‌ای از نوع ندارد",
"This provider can't be unlinked": "این ارائه‌دهنده نمی‌تواند لغو پیوند شود",
"You are not the global admin, you can't unlink other users": "شما مدیر جهانی نیستید، نمی‌توانید کاربران دیگر را لغو پیوند کنید",
"You can't unlink yourself, you are not a member of any application": "شما نمی‌توانید خودتان را لغو پیوند کنید، شما عضو هیچ برنامه‌ای نیستید"
},
"organization": {
"Only admin can modify the %s.": "فقط مدیر می‌تواند %s را تغییر دهد.",
"The %s is immutable.": "%s غیرقابل تغییر است.",
"Unknown modify rule %s.": "قانون تغییر ناشناخته %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "شناسه برنامه نامعتبر",
"the provider: %s does not exist": "ارائه‌دهنده: %s وجود ندارد"
},
"resource": {
"User is nil for tag: avatar": "کاربر برای برچسب: آواتار تهی است",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "نام کاربری یا مسیر کامل فایل خالی است: نام کاربری = %s، مسیر کامل فایل = %s"
},
"saml": {
"Application %s not found": "برنامه %s یافت نشد"
},
"saml_sp": {
"provider %s's category is not SAML": "دسته‌بندی ارائه‌دهنده %s SAML نیست"
},
"service": {
"Empty parameters for emailForm: %v": "پارامترهای خالی برای emailForm: %v",
"Invalid Email receivers: %s": "گیرندگان ایمیل نامعتبر: %s",
"Invalid phone receivers: %s": "گیرندگان تلفن نامعتبر: %s"
},
"storage": {
"The objectKey: %s is not allowed": "objectKey: %s مجاز نیست",
"The provider type: %s is not supported": "نوع ارائه‌دهنده: %s پشتیبانی نمی‌شود"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "grant_type: %s در این برنامه پشتیبانی نمی‌شود",
"Invalid application or wrong clientSecret": "برنامه نامعتبر یا clientSecret نادرست",
"Invalid client_id": "client_id نامعتبر",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "آدرس بازگشت: %s در لیست آدرس‌های بازگشت مجاز وجود ندارد",
"Token not found, invalid accessToken": "توکن یافت نشد، accessToken نامعتبر"
},
"user": {
"Display name cannot be empty": "نام نمایشی نمی‌تواند خالی باشد",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"util": {
"No application is found for userId: %s": "هیچ برنامه‌ای برای userId: %s یافت نشد",
"No provider for category: %s is found for application: %s": "هیچ ارائه‌دهنده‌ای برای دسته‌بندی: %s برای برنامه: %s یافت نشد",
"The provider: %s is not found": "ارائه‌دهنده: %s یافت نشد"
},
"verification": {
"Invalid captcha provider.": "ارائه‌دهنده کپچا نامعتبر.",
"Phone number is invalid in your region %s": "شماره تلفن در منطقه شما نامعتبر است %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "کد تأیید هنوز ارسال نشده است!",
"Turing test failed.": "تست تورینگ ناموفق بود.",
"Unable to get the email modify rule.": "عدم توانایی در دریافت قانون تغییر ایمیل.",
"Unable to get the phone modify rule.": "عدم توانایی در دریافت قانون تغییر تلفن.",
"Unknown type": "نوع ناشناخته",
"Wrong verification code!": "کد تأیید اشتباه!",
"You should verify your code in %d min!": "شما باید کد خود را در %d دقیقه تأیید کنید!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "کاربر وجود ندارد، لطفاً ابتدا ثبت‌نام کنید"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "لطفاً ابتدا WebAuthnSigninBegin را فراخوانی کنید"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -2,107 +2,128 @@
"account": {
"Failed to add user": "Échec d'ajout d'utilisateur",
"Get init score failed, error: %w": "Obtention du score initiale échouée, erreur : %w",
"Please sign out first": "Veuillez vous déconnecter en premier",
"The application does not allow to sign up new account": "L'application ne permet pas de créer un nouveau compte"
},
"auth": {
"Challenge method should be S256": "La méthode de défi doit être S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"DeviceCode Invalid": "Code appareil invalide",
"Failed to create user, user information is invalid: %s": "Échec de la création de l'utilisateur, les informations utilisateur sont invalides : %s",
"Failed to login in: %s": "Échec de la connexion : %s",
"Invalid token": "Jeton invalide",
"State expected: %s, but got: %s": "État attendu : %s, mais obtenu : %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire en tant que nouveau compte via %%s, veuillez utiliser une autre méthode pour vous inscrire",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire en tant que nouveau compte via %s, veuillez utiliser une autre méthode pour vous inscrire",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire comme nouveau compte, veuillez contacter votre support informatique",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Le compte du fournisseur : %s et le nom d'utilisateur : %s (%s) sont déjà liés à un autre compte : %s (%s)",
"The application: %s does not exist": "L'application : %s n'existe pas",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The application: %s has disabled users to signin": "L'application: %s a désactivé la connexion des utilisateurs",
"The group: %s does not exist": "Le groupe : %s n'existe pas",
"The login method: login with LDAP is not enabled for the application": "La méthode de connexion : connexion LDAP n'est pas activée pour l'application",
"The login method: login with SMS is not enabled for the application": "La méthode de connexion : connexion par SMS n'est pas activée pour l'application",
"The login method: login with email is not enabled for the application": "La méthode de connexion : connexion par e-mail n'est pas activée pour l'application",
"The login method: login with face is not enabled for the application": "La méthode de connexion : connexion par visage n'est pas activée pour l'application",
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe n'est pas activée pour l'application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The order: %s does not exist": "La commande : %s n'existe pas",
"The organization: %s does not exist": "L'organisation : %s n'existe pas",
"The organization: %s has disabled users to signin": "L'organisation: %s a désactivé la connexion des utilisateurs",
"The plan: %s does not exist": "Le plan : %s n'existe pas",
"The pricing: %s does not exist": "Le tarif : %s n'existe pas",
"The pricing: %s does not have plan: %s": "Le tarif : %s n'a pas de plan : %s",
"The provider: %s does not exist": "Le fournisseur : %s n'existe pas",
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
"Unauthorized operation": "Opération non autorisée",
"Unknown authentication type (not password or provider), form = %s": "Type d'authentification inconnu (pas de mot de passe ou de fournisseur), formulaire = %s",
"User's tag: %s is not listed in the application's tags": "Le tag de lutilisateur %s nest pas répertorié dans les tags de lapplication",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
"User's tag: %s is not listed in the application's tags": "Le tag de l'utilisateur : %s n'est pas répertorié dans les tags de l'application",
"UserCode Expired": "Code utilisateur expiré",
"UserCode Invalid": "Code utilisateur invalide",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "L'utilisateur payant %s n'a pas d'abonnement actif ou en attente et l'application %s n'a pas de tarification par défaut",
"the application for user %s is not found": "L'application pour l'utilisateur %s est introuvable",
"the organization: %s is not found": "L'organisation : %s est introuvable"
},
"cas": {
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation ne peut pas être vide",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"%s does not meet the CIDR format requirements: %s": "%s ne respecte pas les exigences du format CIDR : %s",
"Affiliation cannot be blank": "L'affiliation ne peut pas être vide",
"CIDR for IP: %s should not be empty": "Le CIDR pour l'IP : %s ne doit pas être vide",
"Default code does not match the code's matching rules": "Le code par défaut ne respecte pas les règles de validation du code",
"DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide",
"DisplayName is not valid real name": "DisplayName n'est pas un nom réel valide",
"Email already exists": "E-mail déjà existant",
"Email cannot be empty": "L'e-mail ne peut pas être vide",
"Email is invalid": "L'adresse e-mail est invalide",
"Empty username.": "Nom d'utilisateur vide.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"Face data does not exist, cannot log in": "Les données faciales n'existent pas, connexion impossible",
"Face data mismatch": "Données faciales incorrectes",
"Failed to parse client IP: %s": "Échec de l'analyse de l'IP client : %s",
"FirstName cannot be blank": "Le prénom ne peut pas être laissé vide",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Nom d'utilisateur ou mot de passe LDAP incorrect",
"Guest users must upgrade their account by setting a username and password before they can sign in directly": "Les utilisateurs invités doivent mettre à niveau leur compte en définissant un nom d'utilisateur et un mot de passe avant de pouvoir se connecter directement",
"Invitation code cannot be blank": "Le code d'invitation ne peut pas être vide",
"Invitation code exhausted": "Code d'invitation épuisé",
"Invitation code is invalid": "Code d'invitation invalide",
"Invitation code suspended": "Code d'invitation suspendu",
"LastName cannot be blank": "Le nom de famille ne peut pas être vide",
"Multiple accounts with same uid, please check your ldap server": "Plusieurs comptes avec le même identifiant d'utilisateur, veuillez vérifier votre serveur LDAP",
"Organization does not exist": "L'organisation n'existe pas",
"Password cannot be empty": "Password cannot be empty",
"Password cannot be empty": "Le mot de passe ne peut pas être vide",
"Phone already exists": "Le téléphone existe déjà",
"Phone cannot be empty": "Le téléphone ne peut pas être vide",
"Phone number is invalid": "Le numéro de téléphone est invalide",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Please register using the email corresponding to the invitation code": "Veuillez vous inscrire avec l'e-mail correspondant au code d'invitation",
"Please register using the phone corresponding to the invitation code": "Veuillez vous inscrire avec le téléphone correspondant au code d'invitation",
"Please register using the username corresponding to the invitation code": "Veuillez vous inscrire avec le nom d'utilisateur correspondant au code d'invitation",
"Session outdated, please login again": "Session expirée, veuillez vous connecter à nouveau",
"The invitation code has already been used": "The invitation code has already been used",
"The invitation code has already been used": "Le code d'invitation a déjà été utilisé",
"The password must contain at least one special character": "Le mot de passe doit contenir au moins un caractère spécial",
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Le mot de passe doit contenir au moins une lettre majuscule, une lettre minuscule et un chiffre",
"The password must have at least 6 characters": "Le mot de passe doit contenir au moins 6 caractères",
"The password must have at least 8 characters": "Le mot de passe doit contenir au moins 8 caractères",
"The password must not contain any repeated characters": "Le mot de passe ne doit pas contenir de caractères répétés",
"The user has been deleted and cannot be used to sign in, please contact the administrator": "L'utilisateur a été supprimé et ne peut pas être utilisé pour se connecter, veuillez contacter l'administrateur",
"The user is forbidden to sign in, please contact the administrator": "L'utilisateur est interdit de se connecter, veuillez contacter l'administrateur",
"The user: %s doesn't exist in LDAP server": "L'utilisateur %s n'existe pas sur le serveur LDAP",
"The user: %s doesn't exist in LDAP server": "L'utilisateur : %s n'existe pas sur le serveur LDAP",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Le nom d'utilisateur ne peut contenir que des caractères alphanumériques, des traits soulignés ou des tirets, ne peut pas avoir de tirets ou de traits soulignés consécutifs et ne peut pas commencer ou se terminer par un tiret ou un trait souligné.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "La valeur \"%s\" pour le champ de compte \"%s\" ne correspond pas à l'expression régulière de l'élément de compte",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "La valeur \"%s\" pour le champ d'inscription \"%s\" ne correspond pas à l'expression régulière de l'élément d'inscription de l'application \"%s\"",
"Username already exists": "Nom d'utilisateur existe déjà",
"Username cannot be an email address": "Nom d'utilisateur ne peut pas être une adresse e-mail",
"Username cannot contain white spaces": "Nom d'utilisateur ne peut pas contenir d'espaces blancs",
"Username cannot start with a digit": "Nom d'utilisateur ne peut pas commencer par un chiffre",
"Username is too long (maximum is 255 characters).": "Nom d'utilisateur est trop long (maximum de 255 caractères).",
"Username must have at least 2 characters": "Le nom d'utilisateur doit comporter au moins 2 caractères",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Le nom d'utilisateur prend en charge le format e-mail. De plus, il ne peut contenir que des caractères alphanumériques, des tirets bas ou des traits d'union, ne peut pas avoir de traits d'union ou de tirets bas consécutifs, et ne peut pas commencer ou se terminer par un trait d'union ou un tiret bas. Faites également attention au format de l'e-mail.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Vous avez entré le mauvais mot de passe ou code plusieurs fois, veuillez attendre %d minutes et réessayer",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your IP address: %s has been banned according to the configuration of: ": "Votre adresse IP : %s a été bannie selon la configuration de : ",
"Your password has expired. Please reset your password by clicking \"Forgot password\"": "Votre mot de passe a expiré. Veuillez le réinitialiser en cliquant sur \"Mot de passe oublié\"",
"Your region is not allow to signup by phone": "Votre région n'est pas autorisée à s'inscrire par téléphone",
"password or code is incorrect": "mot de passe ou code invalide",
"password or code is incorrect, you have %d remaining chances": "Le mot de passe ou le code est incorrect, il vous reste %d chances",
"password or code is incorrect": "mot de passe ou code incorrect",
"password or code is incorrect, you have %s remaining chances": "Le mot de passe ou le code est incorrect, il vous reste %s chances",
"unsupported password type: %s": "Type de mot de passe non pris en charge : %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
"the adapter: %s is not found": "l'adaptateur : %s est introuvable"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import groups": "Échec de l'importation des groupes",
"Failed to import users": "Échec de l'importation des utilisateurs",
"Insufficient balance: new balance %v would be below credit limit %v": "Solde insuffisant : le nouveau solde %v serait inférieur à la limite de crédit %v",
"Insufficient balance: new organization balance %v would be below credit limit %v": "Solde insuffisant : le nouveau solde de l'organisation %v serait inférieur à la limite de crédit %v",
"Missing parameter": "Paramètre manquant",
"Only admin user can specify user": "Only admin user can specify user",
"Only admin user can specify user": "Seul un administrateur peut désigner un utilisateur",
"Please login first": "Veuillez d'abord vous connecter",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The LDAP: %s does not exist": "Le LDAP : %s n'existe pas",
"The organization: %s should have one application at least": "L'organisation : %s doit avoir au moins une application",
"The syncer: %s does not exist": "Le synchroniseur : %s n'existe pas",
"The user: %s doesn't exist": "L'utilisateur : %s n'existe pas",
"Wrong userId": "Wrong userId",
"The user: %s is not found": "L'utilisateur : %s est introuvable",
"User is required for User category transaction": "L'utilisateur est requis pour la transaction de catégorie Utilisateur",
"Wrong userId": "ID utilisateur incorrect",
"don't support captchaProvider: ": "ne prend pas en charge captchaProvider: ",
"this operation is not allowed in demo mode": "cette opération nest pas autorisée en mode démo",
"this operation requires administrator to perform": "this operation requires administrator to perform"
"this operation is not allowed in demo mode": "cette opération n'est pas autorisée en mode démo",
"this operation requires administrator to perform": "cette opération nécessite un administrateur pour être effectuée"
},
"invitation": {
"Invitation %s does not exist": "L'invitation %s n'existe pas"
},
"ldap": {
"Ldap server exist": "Le serveur LDAP existe"
@@ -119,13 +140,19 @@
"Only admin can modify the %s.": "Seul l'administrateur peut modifier le %s.",
"The %s is immutable.": "Le %s est immuable.",
"Unknown modify rule %s.": "Règle de modification inconnue %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "L'ajout d'un nouvel utilisateur à l'organisation « built-in » (intégrée) est actuellement désactivé. Veuillez noter : Tous les utilisateurs de l'organisation « built-in » sont des administrateurs globaux dans Casdoor. Consulter la documentation : https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Si vous souhaitez encore créer un utilisateur pour l'organisation « built-in », accédez à la page des paramètres de l'organisation et activez l'option « A le consentement aux privilèges »."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
"The permission: \"%s\" doesn't exist": "La permission : \"%s\" n'existe pas"
},
"product": {
"Product list cannot be empty": "La liste des produits ne peut pas être vide"
},
"provider": {
"Failed to initialize ID Verification provider": "Échec de l'initialisation du fournisseur de vérification d'identité",
"Invalid application id": "Identifiant d'application invalide",
"No ID Verification provider configured": "Aucun fournisseur de vérification d'identité configuré",
"Provider is not an ID Verification provider": "Le fournisseur n'est pas un fournisseur de vérification d'identité",
"the provider: %s does not exist": "Le fournisseur : %s n'existe pas"
},
"resource": {
@@ -143,12 +170,18 @@
"Invalid Email receivers: %s": "Destinataires d'e-mail invalides : %s",
"Invalid phone receivers: %s": "Destinataires de téléphone invalide : %s"
},
"session": {
"session id %s is the current session and cannot be deleted": "session id %s is the current session and cannot be deleted"
},
"storage": {
"The objectKey: %s is not allowed": "La clé d'objet : %s n'est pas autorisée",
"The provider type: %s is not supported": "Le type de fournisseur : %s n'est pas pris en charge"
},
"subscription": {
"Error": "Error"
"Error": "Erreur"
},
"ticket": {
"Ticket not found": "Ticket introuvable"
},
"token": {
"Grant_type: %s is not supported in this application": "Type_de_subvention : %s n'est pas pris en charge dans cette application",
@@ -159,10 +192,15 @@
},
"user": {
"Display name cannot be empty": "Le nom d'affichage ne peut pas être vide",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"ID card information and real name are required": "Les informations de la carte d'identité et le nom réel sont requis",
"Identity verification failed": "Échec de la vérification d'identité",
"MFA email is enabled but email is empty": "L'authentification MFA par e-mail est activée mais l'e-mail est vide",
"MFA phone is enabled but phone number is empty": "L'authentification MFA par téléphone est activée mais le numéro de téléphone est vide",
"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"
"No application found for user": "Aucune application trouvée pour l'utilisateur",
"The new password must be different from your current password": "Le nouveau mot de passe doit être différent de votre mot de passe actuel",
"User is already verified": "L'utilisateur est déjà vérifié",
"the user's owner and name should not be empty": "le propriétaire et le nom de l'utilisateur ne doivent pas être vides"
},
"util": {
"No application is found for userId: %s": "Aucune application n'a été trouvée pour l'identifiant d'utilisateur : %s",
@@ -172,19 +210,21 @@
"verification": {
"Invalid captcha provider.": "Fournisseur de captcha invalide.",
"Phone number is invalid in your region %s": "Le numéro de téléphone n'est pas valide dans votre région %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The forgot password feature is disabled": "La fonction de mot de passe oublié est désactivée",
"The verification code has already been used!": "Le code de vérification a déjà été utilisé !",
"The verification code has not been sent yet!": "Le code de vérification n'a pas encore été envoyé !",
"Turing test failed.": "Le test de Turing a échoué.",
"Unable to get the email modify rule.": "Incapable d'obtenir la règle de modification de courriel.",
"Unable to get the phone modify rule.": "Impossible d'obtenir la règle de modification de téléphone.",
"Unknown type": "Type inconnu",
"Wrong verification code!": "Mauvais code de vérification !",
"You should verify your code in %d min!": "Vous devriez vérifier votre code en %d min !",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"please add a SMS provider to the \"Providers\" list for the application: %s": "veuillez ajouter un fournisseur SMS à la liste \"Providers\" pour l'application : %s",
"please add an Email provider to the \"Providers\" list for the application: %s": "veuillez ajouter un fournisseur d'e-mail à la liste \"Providers\" pour l'application : %s",
"the user does not exist, please sign up first": "L'utilisateur n'existe pas, veuillez vous inscrire d'abord"
},
"webauthn": {
"Found no credentials for this user": "Aucune information d'identification trouvée pour cet utilisateur",
"Please call WebAuthnSigninBegin first": "Veuillez d'abord appeler WebAuthnSigninBegin"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Gagal menambahkan pengguna",
"Get init score failed, error: %w": "Gagal mendapatkan nilai inisiasi, kesalahan: %w",
"Please sign out first": "Silakan keluar terlebih dahulu",
"The application does not allow to sign up new account": "Aplikasi tidak memperbolehkan pendaftaran akun baru"
},
"auth": {
"Challenge method should be S256": "Metode tantangan harus S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Gagal membuat pengguna, informasi pengguna tidak valid: %s",
"Failed to login in: %s": "Gagal masuk: %s",
"Invalid token": "Token tidak valid",
"State expected: %s, but got: %s": "Diharapkan: %s, tapi diperoleh: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru melalui %%s, silakan gunakan cara lain untuk mendaftar",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru, silakan hubungi dukungan IT Anda",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk penyedia: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
"The application: %s does not exist": "Aplikasi: %s tidak ada",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "Metode login: login dengan sandi tidak diaktifkan untuk aplikasi tersebut",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
"Unauthorized operation": "Operasi tidak sah",
"Unknown authentication type (not password or provider), form = %s": "Jenis otentikasi tidak diketahui (bukan sandi atau penyedia), formulir = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Layanan %s dan %s tidak cocok"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Keterkaitan tidak boleh kosong",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong",
"DisplayName is not valid real name": "DisplayName bukanlah nama asli yang valid",
"Email already exists": "Email sudah ada",
"Email cannot be empty": "Email tidak boleh kosong",
"Email is invalid": "Email tidak valid",
"Empty username.": "Nama pengguna kosong.",
"Face data does not exist, cannot log in": "Data wajah tidak ada, tidak bisa login",
"Face data mismatch": "Ketidakcocokan data wajah",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "Nama depan tidak boleh kosong",
"Invitation code cannot be blank": "Kode undangan tidak boleh kosong",
"Invitation code exhausted": "Kode undangan habis",
"Invitation code is invalid": "Kode undangan tidak valid",
"Invitation code suspended": "Kode undangan ditangguhkan",
"LDAP user name or password incorrect": "Nama pengguna atau sandi LDAP salah",
"LastName cannot be blank": "Nama belakang tidak boleh kosong",
"Multiple accounts with same uid, please check your ldap server": "Beberapa akun dengan uid yang sama, harap periksa server LDAP Anda",
"Organization does not exist": "Organisasi tidak ada",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Telepon sudah ada",
"Phone cannot be empty": "Telepon tidak boleh kosong",
"Phone number is invalid": "Nomor telepon tidak valid",
"Please register using the email corresponding to the invitation code": "Silakan mendaftar menggunakan email yang sesuai dengan kode undangan",
"Please register using the phone corresponding to the invitation code": "Silakan mendaftar menggunakan email yang sesuai dengan kode undangan",
"Please register using the username corresponding to the invitation code": "Silakan mendaftar menggunakan username yang sesuai dengan kode undangan",
"Session outdated, please login again": "Sesi kadaluwarsa, silakan masuk lagi",
"The invitation code has already been used": "Kode undangan sudah digunakan",
"The user is forbidden to sign in, please contact the administrator": "Pengguna dilarang masuk, silakan hubungi administrator",
"The user: %s doesn't exist in LDAP server": "Pengguna: %s tidak ada di server LDAP",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Nama pengguna hanya bisa menggunakan karakter alfanumerik, garis bawah atau tanda hubung, tidak boleh memiliki dua tanda hubung atau garis bawah berurutan, dan tidak boleh diawali atau diakhiri dengan tanda hubung atau garis bawah.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Nilai \\\"%s\\\" pada bidang akun \\\"%s\\\" tidak cocok dengan ketentuan",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Nilai \\\"%s\\\" pada bidang pendaftaran \\\"%s\\\" tidak cocok dengan ketentuan aplikasi \\\"%s\\\"",
"Username already exists": "Nama pengguna sudah ada",
"Username cannot be an email address": "Username tidak bisa menjadi alamat email",
"Username cannot contain white spaces": "Username tidak boleh mengandung spasi",
"Username cannot start with a digit": "Username tidak dapat dimulai dengan angka",
"Username is too long (maximum is 255 characters).": "Nama pengguna terlalu panjang (maksimum 255 karakter).",
"Username must have at least 2 characters": "Nama pengguna harus memiliki setidaknya 2 karakter",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Anda telah memasukkan sandi atau kode yang salah terlalu sering, mohon tunggu selama %d menit lalu coba kembali",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Wilayah Anda tidak diizinkan untuk mendaftar melalui telepon",
"password or code is incorrect": "kata sandi atau kode salah",
"password or code is incorrect, you have %d remaining chances": "Sandi atau kode salah, Anda memiliki %d kesempatan tersisa",
"unsupported password type: %s": "jenis sandi tidak didukung: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "Organisasi: %s setidaknya harus memiliki satu aplikasi",
"The user: %s doesn't exist": "Pengguna: %s tidak ada",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "Jangan mendukung captchaProvider:",
"this operation is not allowed in demo mode": "tindakan ini tidak diizinkan pada mode demo",
"this operation requires administrator to perform": "tindakan ini membutuhkan peran administrator"
},
"ldap": {
"Ldap server exist": "Server ldap ada"
},
"link": {
"Please link first": "Silahkan tautkan terlebih dahulu",
"This application has no providers": "Aplikasi ini tidak memiliki penyedia",
"This application has no providers of type": " Aplikasi ini tidak memiliki penyedia tipe ",
"This provider can't be unlinked": "Penyedia layanan ini tidak dapat dipisahkan",
"You are not the global admin, you can't unlink other users": "Anda bukan admin global, Anda tidak dapat memutuskan tautan pengguna lain",
"You can't unlink yourself, you are not a member of any application": "Anda tidak dapat memutuskan tautan diri sendiri, karena Anda bukan anggota dari aplikasi apa pun"
},
"organization": {
"Only admin can modify the %s.": "Hanya admin yang dapat memodifikasi %s.",
"The %s is immutable.": "%s tidak dapat diubah.",
"Unknown modify rule %s.": "Aturan modifikasi tidak diketahui %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "Izin: \\\"%s\\\" tidak ada"
},
"provider": {
"Invalid application id": "ID aplikasi tidak valid",
"the provider: %s does not exist": "penyedia: %s tidak ada"
},
"resource": {
"User is nil for tag: avatar": "Pengguna kosong untuk tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Nama pengguna atau path lengkap file kosong: nama_pengguna = %s, path_lengkap_file = %s"
},
"saml": {
"Application %s not found": "Aplikasi %s tidak ditemukan"
},
"saml_sp": {
"provider %s's category is not SAML": "kategori penyedia %s bukan SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Parameter kosong untuk emailForm: %v",
"Invalid Email receivers: %s": "Penerima email tidak valid: %s",
"Invalid phone receivers: %s": "Penerima telepon tidak valid: %s"
},
"storage": {
"The objectKey: %s is not allowed": "Kunci objek: %s tidak diizinkan",
"The provider type: %s is not supported": "Jenis penyedia: %s tidak didukung"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Jenis grant (grant_type) %s tidak didukung dalam aplikasi ini",
"Invalid application or wrong clientSecret": "Aplikasi tidak valid atau clientSecret salah",
"Invalid client_id": "ID klien tidak valid",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI pengalihan: %s tidak ada dalam daftar URI Pengalihan yang diizinkan",
"Token not found, invalid accessToken": "Token tidak ditemukan, accessToken tidak valid"
},
"user": {
"Display name cannot be empty": "Nama tampilan tidak boleh kosong",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "Penyedia: %s tidak ditemukan"
},
"verification": {
"Invalid captcha provider.": "Penyedia captcha tidak valid.",
"Phone number is invalid in your region %s": "Nomor telepon tidak valid di wilayah anda %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "Kode verifikasi belum terkirim!",
"Turing test failed.": "Tes Turing gagal.",
"Unable to get the email modify rule.": "Tidak dapat memperoleh aturan modifikasi email.",
"Unable to get the phone modify rule.": "Tidak dapat memodifikasi aturan telepon.",
"Unknown type": "Tipe tidak diketahui",
"Wrong verification code!": "Kode verifikasi salah!",
"You should verify your code in %d min!": "Anda harus memverifikasi kode Anda dalam %d menit!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "silahkan tambahkan penyedia SMS ke daftar \\\"Penyedia\\\" untuk aplikasi: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "silahkan tambahkan penyedia Email ke daftar \\\"Penyedia\\\" untuk aplikasi: %s",
"the user does not exist, please sign up first": "Pengguna tidak ada, silakan daftar terlebih dahulu"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Harap panggil WebAuthnSigninBegin terlebih dahulu"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -2,107 +2,128 @@
"account": {
"Failed to add user": "ユーザーの追加に失敗しました",
"Get init score failed, error: %w": "イニットスコアの取得に失敗しました。エラー:%w",
"Please sign out first": "最初にサインアウトしてください",
"The application does not allow to sign up new account": "アプリケーションは新しいアカウントの登録を許可しません"
},
"auth": {
"Challenge method should be S256": "チャレンジメソッドはS256である必要があります",
"DeviceCode Invalid": "DeviceCode Invalid",
"DeviceCode Invalid": "デバイスコードが無効です",
"Failed to create user, user information is invalid: %s": "ユーザーの作成に失敗しました。ユーザー情報が無効です:%s",
"Failed to login in: %s": "ログインできませんでした:%s",
"Invalid token": "無効なトークン",
"State expected: %s, but got: %s": "期待される状態: %s、実際には%s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "プロバイダーのアカウント:%s とユーザー名:%s%sが存在せず、新しいアカウントを %%s 経由でサインアップすることはできません。他の方法でサインアップしてください",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "プロバイダーのアカウント:%s とユーザー名:%s%sが存在せず、新しいアカウントを %s 経由でサインアップすることはできません。他の方法でサインアップしてください",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "プロバイダー名:%sとユーザー名%s%sのアカウントは存在しません。新しいアカウントとしてサインアップすることはできません。 ITサポートに連絡してください",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "プロバイダのアカウント:%s とユーザー名:%s (%s) は既に別のアカウント:%s (%s) にリンクされています",
"The application: %s does not exist": "アプリケーション: %sは存在しません",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The application: %s has disabled users to signin": "アプリケーション: %s はユーザーのサインインを無効にしました",
"The group: %s does not exist": "グループ: %sは存在しません",
"The login method: login with LDAP is not enabled for the application": "このアプリケーションでは LDAP ログインは有効になっていません",
"The login method: login with SMS is not enabled for the application": "このアプリケーションでは SMS ログインは有効になっていません",
"The login method: login with email is not enabled for the application": "このアプリケーションではメールログインは有効になっていません",
"The login method: login with face is not enabled for the application": "このアプリケーションでは顔認証ログインは有効になっていません",
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The order: %s does not exist": "注文:%s は存在しません",
"The organization: %s does not exist": "組織「%s」は存在しません",
"The organization: %s has disabled users to signin": "組織: %s はユーザーのサインインを無効にしました",
"The plan: %s does not exist": "プラン: %sは存在しません",
"The pricing: %s does not exist": "料金: %sは存在しません",
"The pricing: %s does not have plan: %s": "料金: %sにはプラン%sがありません",
"The provider: %s does not exist": "プロバイダ「%s」は存在しません",
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
"Unauthorized operation": "不正操作",
"Unknown authentication type (not password or provider), form = %s": "不明な認証タイプ(パスワードまたはプロバイダーではない)フォーム=%s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
"User's tag: %s is not listed in the application's tags": "ユーザータグ「%s」はアプリケーションのタグに含まれていません",
"UserCode Expired": "ユーザーコードの有効期限が切れています",
"UserCode Invalid": "ユーザーコードが無効です",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "有料ユーザー「%s」には有効または保留中のサブスクリプションがなく、アプリケーション「%s」にはデフォルトの価格設定がありません",
"the application for user %s is not found": "ユーザー「%s」のアプリケーションが見つかりません",
"the organization: %s is not found": "組織「%s」が見つかりません"
},
"cas": {
"Service %s and %s do not match": "サービス%sと%sは一致しません"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"%s does not meet the CIDR format requirements: %s": "%s は CIDR フォーマットの要件を満たしていません: %s",
"Affiliation cannot be blank": "所属は空白にできません",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"CIDR for IP: %s should not be empty": "IP「%s」の CIDR は空にできません",
"Default code does not match the code's matching rules": "デフォルトコードがコードの一致ルールに一致しません",
"DisplayName cannot be blank": "表示名は空白にできません",
"DisplayName is not valid real name": "表示名は有効な実名ではありません",
"Email already exists": "メールは既に存在します",
"Email cannot be empty": "メールが空白にできません",
"Email is invalid": "電子メールは無効です",
"Empty username.": "空のユーザー名。",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"Face data does not exist, cannot log in": "顔認証データが存在しないため、ログインできません",
"Face data mismatch": "顔認証データが一致しません",
"Failed to parse client IP: %s": "クライアント IP「%s」の解析に失敗しました",
"FirstName cannot be blank": "ファーストネームは空白にできません",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Ldapのユーザー名またはパスワードが間違っています",
"Guest users must upgrade their account by setting a username and password before they can sign in directly": "ゲストユーザーは直接サインインする前に、ユーザー名とパスワードを設定してアカウントをアップグレードする必要があります",
"Invitation code cannot be blank": "招待コードは空にできません",
"Invitation code exhausted": "招待コードの使用回数が上限に達しました",
"Invitation code is invalid": "招待コードが無効です",
"Invitation code suspended": "招待コードは一時的に無効化されています",
"LastName cannot be blank": "姓は空白にできません",
"Multiple accounts with same uid, please check your ldap server": "同じuidを持つ複数のアカウントがあります。あなたのLDAPサーバーを確認してください",
"Organization does not exist": "組織は存在しません",
"Password cannot be empty": "Password cannot be empty",
"Password cannot be empty": "パスワードは空にできません",
"Phone already exists": "電話はすでに存在しています",
"Phone cannot be empty": "電話は空っぽにできません",
"Phone number is invalid": "電話番号が無効です",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Please register using the email corresponding to the invitation code": "招待コードに対応するメールアドレスで登録してください",
"Please register using the phone corresponding to the invitation code": "招待コードに対応する電話番号で登録してください",
"Please register using the username corresponding to the invitation code": "招待コードに対応するユーザー名で登録してください",
"Session outdated, please login again": "セッションが期限切れになりました。再度ログインしてください",
"The invitation code has already been used": "The invitation code has already been used",
"The invitation code has already been used": "この招待コードは既に使用されています",
"The password must contain at least one special character": "パスワードには少なくとも1つの特殊文字が必要です",
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "パスワードには少なくとも1つの大文字、1つの小文字、1つの数字が必要です",
"The password must have at least 6 characters": "パスワードは少なくとも6文字必要です",
"The password must have at least 8 characters": "パスワードは少なくとも8文字必要です",
"The password must not contain any repeated characters": "パスワードに繰り返し文字を含めることはできません",
"The user has been deleted and cannot be used to sign in, please contact the administrator": "ユーザーは削除されており、サインインに使用できません。管理者にお問い合わせください",
"The user is forbidden to sign in, please contact the administrator": "ユーザーはサインインできません。管理者に連絡してください",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The user: %s doesn't exist in LDAP server": "ユーザー「%s」は LDAP サーバーに存在しません",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "ユーザー名には英数字、アンダースコア、ハイフンしか含めることができません。連続したハイフンまたはアンダースコアは不可であり、ハイフンまたはアンダースコアで始まるまたは終わることもできません。",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "アカウントフィールド「%s」の値「%s」がアカウント項目の正規表現に一致しません",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "アプリケーション「%s」のサインアップ項目「%s」の値「%s」が正規表現に一致しません",
"Username already exists": "ユーザー名はすでに存在しています",
"Username cannot be an email address": "ユーザー名には電子メールアドレスを使用できません",
"Username cannot contain white spaces": "ユーザ名にはスペースを含めることはできません",
"Username cannot start with a digit": "ユーザー名は数字で始めることはできません",
"Username is too long (maximum is 255 characters).": "ユーザー名が長すぎます最大255文字。",
"Username must have at least 2 characters": "ユーザー名は少なくとも2文字必要です",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "ユーザー名はメール形式もサポートします。ユーザー名は英数字、アンダースコア、またはハイフンのみを含め、連続するハイフンやアンダースコアは使用できません。また、ハイフンまたはアンダースコアで始まったり終わったりすることもできません。メール形式にも注意してください。",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "あなたは間違ったパスワードまたはコードを何度も入力しました。%d 分間待ってから再度お試しください",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your IP address: %s has been banned according to the configuration of: ": "あなたの IP アドレス「%s」は設定によりアクセスが禁止されています: ",
"Your password has expired. Please reset your password by clicking \"Forgot password\"": "パスワードの有効期限が切れています。「パスワードを忘れた方はこちら」をクリックしてリセットしてください",
"Your region is not allow to signup by phone": "あなたの地域は電話でサインアップすることができません",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "パスワードまたはコードが間違っています。あと%d回の試行機会があります",
"password or code is incorrect": "パスワードまたはコードが正しくありません",
"password or code is incorrect, you have %s remaining chances": "パスワードまたはコードが間違っています。あと %s 回の試行機会があります",
"unsupported password type: %s": "サポートされていないパスワードタイプ:%s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
"the adapter: %s is not found": "アダプタ「%s」が見つかりません"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import groups": "グループのインポートに失敗しました",
"Failed to import users": "ユーザーのインポートに失敗しました",
"Insufficient balance: new balance %v would be below credit limit %v": "残高不足:新しい残高 %v がクレジット制限 %v を下回ります",
"Insufficient balance: new organization balance %v would be below credit limit %v": "残高不足:新しい組織残高 %v がクレジット制限 %v を下回ります",
"Missing parameter": "不足しているパラメーター",
"Only admin user can specify user": "Only admin user can specify user",
"Only admin user can specify user": "管理者ユーザーのみがユーザーを指定できます",
"Please login first": "最初にログインしてください",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The LDAP: %s does not exist": "LDAP%s は存在しません",
"The organization: %s should have one application at least": "組織「%s」は少なくとも1つのアプリケーションを持っている必要があります",
"The syncer: %s does not exist": "同期装置:%s は存在しません",
"The user: %s doesn't exist": "そのユーザー:%sは存在しません",
"Wrong userId": "Wrong userId",
"The user: %s is not found": "ユーザー:%s が見つかりません",
"User is required for User category transaction": "ユーザーカテゴリトランザクションにはユーザーが必要です",
"Wrong userId": "無効なユーザーIDです",
"don't support captchaProvider: ": "captchaProviderをサポートしないでください",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
"this operation is not allowed in demo mode": "この操作はデモモードでは許可されていません",
"this operation requires administrator to perform": "この操作は管理者権限が必要です"
},
"invitation": {
"Invitation %s does not exist": "招待 %s は存在しません"
},
"ldap": {
"Ldap server exist": "LDAPサーバーは存在します"
@@ -119,13 +140,19 @@
"Only admin can modify the %s.": "管理者のみが%sを変更できます。",
"The %s is immutable.": "%sは不変です。",
"Unknown modify rule %s.": "未知の変更ルール%s。",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "「built-in」組み込み組織への新しいユーザーの追加は現在無効になっています。注意「built-in」組織のすべてのユーザーは、Casdoor のグローバル管理者です。ドキュメントを参照してくださいhttps://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself。「built-in」組織のユーザーを作成したい場合は、組織の設定ページに移動し、「特権同意を持つ」オプションを有効にしてください。"
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
"The permission: \"%s\" doesn't exist": "権限「%s」は存在しません"
},
"product": {
"Product list cannot be empty": "商品リストは空にできません"
},
"provider": {
"Failed to initialize ID Verification provider": "ID認証プロバイダーの初期化に失敗しました",
"Invalid application id": "アプリケーションIDが無効です",
"No ID Verification provider configured": "ID認証プロバイダーが設定されていません",
"Provider is not an ID Verification provider": "プロバイダーはID認証プロバイダーではありません",
"the provider: %s does not exist": "プロバイダー%sは存在しません"
},
"resource": {
@@ -143,12 +170,18 @@
"Invalid Email receivers: %s": "無効な電子メール受信者:%s",
"Invalid phone receivers: %s": "電話受信者が無効です:%s"
},
"session": {
"session id %s is the current session and cannot be deleted": "セッションID %s は現在のセッションであり、削除できません"
},
"storage": {
"The objectKey: %s is not allowed": "オブジェクトキー %s は許可されていません",
"The provider type: %s is not supported": "プロバイダータイプ:%sはサポートされていません"
},
"subscription": {
"Error": "Error"
"Error": "エラー"
},
"ticket": {
"Ticket not found": "チケットが見つかりません"
},
"token": {
"Grant_type: %s is not supported in this application": "grant_type%sはこのアプリケーションでサポートされていません",
@@ -159,10 +192,15 @@
},
"user": {
"Display name cannot be empty": "表示名は空にできません",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"ID card information and real name are required": "身分証明書の情報と実名が必要です",
"Identity verification failed": "身元確認に失敗しました",
"MFA email is enabled but email is empty": "MFA メールが有効になっていますが、メールアドレスが空です",
"MFA phone is enabled but phone number is empty": "MFA 電話番号が有効になっていますが、電話番号が空です",
"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"
"No application found for user": "ユーザーのアプリケーションが見つかりません",
"The new password must be different from your current password": "新しいパスワードは現在のパスワードと異なる必要があります",
"User is already verified": "ユーザーは既に認証済みです",
"the user's owner and name should not be empty": "ユーザーのオーナーと名前は空にできません"
},
"util": {
"No application is found for userId: %s": "ユーザーIDに対するアプリケーションが見つかりません %s",
@@ -172,19 +210,21 @@
"verification": {
"Invalid captcha provider.": "無効なCAPTCHAプロバイダー。",
"Phone number is invalid in your region %s": "電話番号はあなたの地域で無効です %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"The forgot password feature is disabled": "パスワードを忘れた機能は無効になっています",
"The verification code has already been used!": "この検証コードは既に使用されています!",
"The verification code has not been sent yet!": "検証コードはまだ送信されていません!",
"Turing test failed.": "チューリングテストは失敗しました。",
"Unable to get the email modify rule.": "電子メール変更規則を取得できません。",
"Unable to get the phone modify rule.": "電話の変更ルールを取得できません。",
"Unknown type": "不明なタイプ",
"Wrong verification code!": "誤った検証コードです!",
"You should verify your code in %d min!": "あなたは%d分であなたのコードを確認する必要があります",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"please add a SMS provider to the \"Providers\" list for the application: %s": "アプリケーション「%s」の「Providers」リストに SMS プロバイダを追加してください",
"please add an Email provider to the \"Providers\" list for the application: %s": "アプリケーション「%s」の「Providers」リストにメールプロバイダを追加してください",
"the user does not exist, please sign up first": "ユーザーは存在しません。まず登録してください"
},
"webauthn": {
"Found no credentials for this user": "このユーザーの認証情報が見つかりませんでした",
"Please call WebAuthnSigninBegin first": "最初にWebAuthnSigninBeginを呼び出してください"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "사용자 추가 실패",
"Get init score failed, error: %w": "초기 점수 획득 실패, 오류: %w",
"Please sign out first": "먼저 로그아웃해주세요",
"The application does not allow to sign up new account": "이 응용 프로그램은 새로운 계정 가입을 허용하지 않습니다"
},
"auth": {
"Challenge method should be S256": "도전 방식은 S256이어야 합니다",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "사용자를 만들지 못했습니다. 사용자 정보가 잘못되었습니다: %s",
"Failed to login in: %s": "로그인에 실패했습니다.: %s",
"Invalid token": "유효하지 않은 토큰",
"State expected: %s, but got: %s": "예상한 상태: %s, 실제 상태: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "제공자 계정: %s와 사용자 이름: %s (%s)은(는) 존재하지 않으며 %%s를 통해 새 계정으로 가입하는 것이 허용되지 않습니다. 다른 방법으로 가입하십시오",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "공급자 계정 %s과 사용자 이름 %s (%s)는 존재하지 않으며 새 계정으로 등록할 수 없습니다. IT 지원팀에 문의하십시오",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "공급자 계정 %s과 사용자 이름 %s(%s)는 이미 다른 계정 %s(%s)에 연결되어 있습니다",
"The application: %s does not exist": "해당 애플리케이션(%s)이 존재하지 않습니다",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
"Unauthorized operation": "무단 조작",
"Unknown authentication type (not password or provider), form = %s": "알 수 없는 인증 유형(암호 또는 공급자가 아님), 폼 = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "소속은 비워 둘 수 없습니다",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다",
"DisplayName is not valid real name": "DisplayName는 유효한 실제 이름이 아닙니다",
"Email already exists": "이메일이 이미 존재합니다",
"Email cannot be empty": "이메일은 비어 있을 수 없습니다",
"Email is invalid": "이메일이 유효하지 않습니다",
"Empty username.": "빈 사용자 이름.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "이름은 공백일 수 없습니다",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP 사용자 이름 또는 암호가 잘못되었습니다",
"LastName cannot be blank": "성은 비어 있을 수 없습니다",
"Multiple accounts with same uid, please check your ldap server": "동일한 UID를 가진 여러 계정이 있습니다. LDAP 서버를 확인해주세요",
"Organization does not exist": "조직은 존재하지 않습니다",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "전화기는 이미 존재합니다",
"Phone cannot be empty": "전화는 비워 둘 수 없습니다",
"Phone number is invalid": "전화번호가 유효하지 않습니다",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "세션이 만료되었습니다. 다시 로그인해주세요",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "사용자는 로그인이 금지되어 있습니다. 관리자에게 문의하십시오",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "사용자 이름은 알파벳, 숫자, 밑줄 또는 하이픈만 포함할 수 있으며, 연속된 하이픈 또는 밑줄을 가질 수 없으며, 하이픈 또는 밑줄로 시작하거나 끝날 수 없습니다.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "사용자 이름이 이미 존재합니다",
"Username cannot be an email address": "사용자 이름은 이메일 주소가 될 수 없습니다",
"Username cannot contain white spaces": "사용자 이름에는 공백이 포함될 수 없습니다",
"Username cannot start with a digit": "사용자 이름은 숫자로 시작할 수 없습니다",
"Username is too long (maximum is 255 characters).": "사용자 이름이 너무 깁니다 (최대 255자).",
"Username must have at least 2 characters": "사용자 이름은 적어도 2개의 문자가 있어야 합니다",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "올바르지 않은 비밀번호나 코드를 여러 번 입력했습니다. %d분 동안 기다리신 후 다시 시도해주세요",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "당신의 지역은 전화로 가입할 수 없습니다",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "암호 또는 코드가 올바르지 않습니다. %d번의 기회가 남아 있습니다",
"unsupported password type: %s": "지원되지 않는 암호 유형: %s"
},
"enforcer": {
"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": "먼저 로그인 하십시오",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "사용자 %s는 존재하지 않습니다",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "CaptchaProvider를 지원하지 마세요",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "LDAP 서버가 존재합니다"
},
"link": {
"Please link first": "먼저 링크해주세요",
"This application has no providers": "이 애플리케이션에는 제공자가 없습니다",
"This application has no providers of type": "이 응용 프로그램은 타입의 공급자가 없습니다",
"This provider can't be unlinked": "이 공급자는 연결이 해제될 수 없습니다",
"You are not the global admin, you can't unlink other users": "당신은 전역 관리자가 아니므로 다른 사용자와의 연결을 해제할 수 없습니다",
"You can't unlink yourself, you are not a member of any application": "당신은 어떤 애플리케이션의 회원이 아니기 때문에 스스로 링크를 해제할 수 없습니다"
},
"organization": {
"Only admin can modify the %s.": "관리자만 %s을(를) 수정할 수 있습니다.",
"The %s is immutable.": "%s 는 변경할 수 없습니다.",
"Unknown modify rule %s.": "미확인 수정 규칙 %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "잘못된 애플리케이션 ID입니다",
"the provider: %s does not exist": "제공자 %s가 존재하지 않습니다"
},
"resource": {
"User is nil for tag: avatar": "사용자는 아바타 태그에 대해 nil입니다",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "사용자 이름 또는 전체 파일 경로가 비어 있습니다: 사용자 이름 = %s, 전체 파일 경로 = %s"
},
"saml": {
"Application %s not found": "어플리케이션 %s을(를) 찾을 수 없습니다"
},
"saml_sp": {
"provider %s's category is not SAML": "제공 업체 %s의 카테고리는 SAML이 아닙니다"
},
"service": {
"Empty parameters for emailForm: %v": "이메일 형식의 빈 매개 변수: %v",
"Invalid Email receivers: %s": "잘못된 이메일 수신자: %s",
"Invalid phone receivers: %s": "잘못된 전화 수신자: %s"
},
"storage": {
"The objectKey: %s is not allowed": "객체 키 : %s 는 허용되지 않습니다",
"The provider type: %s is not supported": "제공자 유형: %s은/는 지원되지 않습니다"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "그랜트 유형: %s은(는) 이 어플리케이션에서 지원되지 않습니다",
"Invalid application or wrong clientSecret": "잘못된 어플리케이션 또는 올바르지 않은 클라이언트 시크릿입니다",
"Invalid client_id": "잘못된 클라이언트 ID입니다",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "허용된 Redirect URI 목록에서 %s이(가) 존재하지 않습니다",
"Token not found, invalid accessToken": "토큰을 찾을 수 없습니다. 잘못된 액세스 토큰입니다"
},
"user": {
"Display name cannot be empty": "디스플레이 이름은 비어 있을 수 없습니다",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"util": {
"No application is found for userId: %s": "어플리케이션을 찾을 수 없습니다. userId: %s",
"No provider for category: %s is found for application: %s": "어플리케이션 %s에서 %s 카테고리를 위한 공급자가 찾을 수 없습니다",
"The provider: %s is not found": "제공자: %s를 찾을 수 없습니다"
},
"verification": {
"Invalid captcha provider.": "잘못된 captcha 제공자입니다.",
"Phone number is invalid in your region %s": "전화 번호가 당신의 지역 %s에서 유효하지 않습니다",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "튜링 테스트 실패.",
"Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.",
"Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.",
"Unknown type": "알 수 없는 유형",
"Wrong verification code!": "잘못된 인증 코드입니다!",
"You should verify your code in %d min!": "당신은 %d분 안에 코드를 검증해야 합니다!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "사용자가 존재하지 않습니다. 먼저 회원 가입 해주세요"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "WebAuthnSigninBegin을 먼저 호출해주세요"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -1,190 +0,0 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"enforcer": {
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -1,190 +1,230 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
"Failed to add user": "Nie udało się dodać użytkownika",
"Get init score failed, error: %w": "Pobranie początkowego wyniku nie powiodło się, błąd: %w",
"The application does not allow to sign up new account": "Aplikacja nie pozwala na rejestrację nowego konta"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
"Challenge method should be S256": "Metoda wyzwania powinna być S256",
"DeviceCode Invalid": "Nieprawidłowy kod urządzenia",
"Failed to create user, user information is invalid: %s": "Nie udało się utworzyć użytkownika, dane użytkownika są nieprawidłowe: %s",
"Failed to login in: %s": "Logowanie nie powiodło się: %s",
"Invalid token": "Nieprawidłowy token",
"State expected: %s, but got: %s": "Oczekiwano stanu: %s, ale otrzymano: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %s, please use another way to sign up": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto przez %s, użyj innej metody rejestracji",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) nie istnieje i nie można się zarejestrować jako nowe konto, skontaktuj się z pomocą IT",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Konto dla dostawcy: %s i nazwy użytkownika: %s (%s) jest już powiązane z innym kontem: %s (%s)",
"The application: %s does not exist": "Aplikacja: %s nie istnieje",
"The application: %s has disabled users to signin": "Aplikacja: %s wyłączyła logowanie użytkowników",
"The group: %s does not exist": "Grupa: %s nie istnieje",
"The login method: login with LDAP is not enabled for the application": "Metoda logowania: logowanie przez LDAP nie jest włączone dla aplikacji",
"The login method: login with SMS is not enabled for the application": "Metoda logowania: logowanie przez SMS nie jest włączona dla aplikacji",
"The login method: login with email is not enabled for the application": "Metoda logowania: logowanie przez email nie jest włączona dla aplikacji",
"The login method: login with face is not enabled for the application": "Metoda logowania: logowanie przez twarz nie jest włączona dla aplikacji",
"The login method: login with password is not enabled for the application": "Metoda logowania: logowanie przez hasło nie jest włączone dla aplikacji",
"The order: %s does not exist": "Zamówienie: %s nie istnieje",
"The organization: %s does not exist": "Organizacja: %s nie istnieje",
"The organization: %s has disabled users to signin": "Organizacja: %s wyłączyła logowanie użytkowników",
"The plan: %s does not exist": "Plan: %s nie istnieje",
"The pricing: %s does not exist": "Cennik: %s nie istnieje",
"The pricing: %s does not have plan: %s": "Cennik: %s nie ma planu: %s",
"The provider: %s does not exist": "Dostawca: %s nie istnieje",
"The provider: %s is not enabled for the application": "Dostawca: %s nie jest włączony dla aplikacji",
"Unauthorized operation": "Nieautoryzowana operacja",
"Unknown authentication type (not password or provider), form = %s": "Nieznany typ uwierzytelnienia (nie hasło ani dostawca), formularz = %s",
"User's tag: %s is not listed in the application's tags": "Tag użytkownika: %s nie znajduje się na liście tagów aplikacji",
"UserCode Expired": "Kod użytkownika wygasł",
"UserCode Invalid": "Nieprawidłowy kod użytkownika",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "płatny użytkownik %s nie ma aktywnej lub oczekującej subskrypcji, a aplikacja: %s nie ma domyślnego cennika",
"the application for user %s is not found": "aplikacja dla użytkownika %s nie została znaleziona",
"the organization: %s is not found": "organizacja: %s nie została znaleziona"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
"Service %s and %s do not match": "Usługa %s i %s nie pasują do siebie"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
"%s does not meet the CIDR format requirements: %s": "%s nie spełnia wymagań formatu CIDR: %s",
"Affiliation cannot be blank": "Przynależność nie może być pusta",
"CIDR for IP: %s should not be empty": "CIDR dla IP: %s nie powinno być puste",
"Default code does not match the code's matching rules": "Domyślny kod nie pasuje do reguł dopasowania kodu",
"DisplayName cannot be blank": "Nazwa wyświetlana nie może być pusta",
"DisplayName is not valid real name": "Nazwa wyświetlana nie jest prawdziwym imieniem",
"Email already exists": "Email już istnieje",
"Email cannot be empty": "Email nie może być pusty",
"Email is invalid": "Email jest nieprawidłowy",
"Empty username.": "Pusta nazwa użytkownika.",
"Face data does not exist, cannot log in": "Dane twarzy nie istnieją, nie można się zalogować",
"Face data mismatch": "Niezgodność danych twarzy",
"Failed to parse client IP: %s": "Nie udało się przeanalizować IP klienta: %s",
"FirstName cannot be blank": "Imię nie może być puste",
"Guest users must upgrade their account by setting a username and password before they can sign in directly": "Użytkownicy-goście muszą uaktualnić swoje konto, ustawiając nazwę użytkownika i hasło, zanim będą mogli się zalogować bezpośrednio",
"Invitation code cannot be blank": "Kod zaproszenia nie może być pusty",
"Invitation code exhausted": "Kod zaproszenia został wykorzystany",
"Invitation code is invalid": "Kod zaproszenia jest nieprawidłowy",
"Invitation code suspended": "Kod zaproszenia został zawieszony",
"LastName cannot be blank": "Nazwisko nie może być puste",
"Multiple accounts with same uid, please check your ldap server": "Wiele kont z tym samym uid, sprawdź swój serwer ldap",
"Organization does not exist": "Organizacja nie istnieje",
"Password cannot be empty": "Hasło nie może być puste",
"Phone already exists": "Telefon już istnieje",
"Phone cannot be empty": "Telefon nie może być pusty",
"Phone number is invalid": "Numer telefonu jest nieprawidłowy",
"Please register using the email corresponding to the invitation code": "Zarejestruj się używając emaila odpowiadającego kodowi zaproszenia",
"Please register using the phone corresponding to the invitation code": "Zarejestruj się używając telefonu odpowiadającego kodowi zaproszenia",
"Please register using the username corresponding to the invitation code": "Zarejestruj się używając nazwy użytkownika odpowiadającej kodowi zaproszenia",
"Session outdated, please login again": "Sesja wygasła, zaloguj się ponownie",
"The invitation code has already been used": "Kod zaproszenia został już wykorzystany",
"The password must contain at least one special character": "Hasło musi zawierać co najmniej jeden znak specjalny",
"The password must contain at least one uppercase letter, one lowercase letter and one digit": "Hasło musi zawierać co najmniej jedną wielką literę, jedną małą literę i jedną cyfrę",
"The password must have at least 6 characters": "Hasło musi zawierać co najmniej 6 znaków",
"The password must have at least 8 characters": "Hasło musi zawierać co najmniej 8 znaków",
"The password must not contain any repeated characters": "Hasło nie może zawierać powtarzających się znaków",
"The user has been deleted and cannot be used to sign in, please contact the administrator": "Użytkownik został usunięty i nie może być używany do logowania, skontaktuj się z administratorem",
"The user is forbidden to sign in, please contact the administrator": "Użytkownikowi zabroniono logowania, skontaktuj się z administratorem",
"The user: %s doesn't exist in LDAP server": "Użytkownik: %s nie istnieje w serwerze LDAP",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "Nazwa użytkownika może zawierać tylko znaki alfanumeryczne, podkreślenia lub myślniki, nie może mieć kolejnych myślników lub podkreśleń i nie może zaczynać się ani kończyć myślnikiem lub podkreśleniem.",
"The value \"%s\" for account field \"%s\" doesn't match the account item regex": "Wartość \"%s\" dla pola konta \"%s\" nie pasuje do wyrażenia regularnego elementu konta",
"The value \"%s\" for signup field \"%s\" doesn't match the signup item regex of the application \"%s\"": "Wartość \"%s\" dla pola rejestracji \"%s\" nie pasuje do wyrażenia regularnego elementu rejestracji aplikacji \"%s\"",
"Username already exists": "Nazwa użytkownika już istnieje",
"Username cannot be an email address": "Nazwa użytkownika nie może być adresem email",
"Username cannot contain white spaces": "Nazwa użytkownika nie może zawierać spacji",
"Username cannot start with a digit": "Nazwa użytkownika nie może zaczynać się od cyfry",
"Username is too long (maximum is 255 characters).": "Nazwa użytkownika jest za długa (maksymalnie 255 znaków).",
"Username must have at least 2 characters": "Nazwa użytkownika musi mieć co najmniej 2 znaki",
"Username supports email format. Also The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline. Also pay attention to the email format.": "Nazwa użytkownika obsługuje format email. Również nazwa użytkownika może zawierać tylko znaki alfanumeryczne, podkreślenia lub myślniki, nie może mieć kolejnych myślników lub podkreśleń i nie może zaczynać się ani kończyć myślnikiem lub podkreśleniem. Zwróć też uwagę na format email.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Wprowadziłeś złe hasło lub kod zbyt wiele razy, poczekaj %d minut i spróbuj ponownie",
"Your IP address: %s has been banned according to the configuration of: ": "Twój adres IP: %s został zablokowany zgodnie z konfiguracją: ",
"Your password has expired. Please reset your password by clicking \"Forgot password\"": "Twoje hasło wygasło. Zresetuj hasło klikając \"Zapomniałem hasła\"",
"Your region is not allow to signup by phone": "Twój region nie pozwala na rejestrację przez telefon",
"password or code is incorrect": "hasło lub kod jest nieprawidłowe",
"password or code is incorrect, you have %s remaining chances": "hasło lub kod jest nieprawidłowe, masz jeszcze %s prób",
"unsupported password type: %s": "nieobsługiwany typ hasła: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
"the adapter: %s is not found": "adapter: %s nie został znaleziony"
},
"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",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
"Failed to import groups": "Nie udało się zaimportować grup",
"Failed to import users": "Nie udało się zaimportować użytkowników",
"Insufficient balance: new balance %v would be below credit limit %v": "Niewystarczające saldo: nowe saldo %v byłoby poniżej limitu kredytowego %v",
"Insufficient balance: new organization balance %v would be below credit limit %v": "Niewystarczające saldo: nowe saldo organizacji %v byłoby poniżej limitu kredytowego %v",
"Missing parameter": "Brakujący parametr",
"Only admin user can specify user": "Tylko administrator może wskazać użytkownika",
"Please login first": "Najpierw się zaloguj",
"The LDAP: %s does not exist": "LDAP: %s nie istnieje",
"The organization: %s should have one application at least": "Organizacja: %s powinna mieć co najmniej jedną aplikację",
"The syncer: %s does not exist": "Synchronizer: %s nie istnieje",
"The user: %s doesn't exist": "Użytkownik: %s nie istnieje",
"The user: %s is not found": "Użytkownik: %s nie został znaleziony",
"User is required for User category transaction": "Użytkownik jest wymagany do transakcji kategorii użytkownika",
"Wrong userId": "Nieprawidłowy userId",
"don't support captchaProvider: ": "nie obsługuje captchaProvider: ",
"this operation is not allowed in demo mode": "ta operacja nie jest dozwolona w trybie demo",
"this operation requires administrator to perform": "ta operacja wymaga administratora do wykonania"
},
"invitation": {
"Invitation %s does not exist": "Zaproszenie %s nie istnieje"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
"Ldap server exist": "Serwer LDAP istnieje"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
"Please link first": "Najpierw się połącz",
"This application has no providers": "Ta aplikacja nie ma dostawców",
"This application has no providers of type": "Ta aplikacja nie ma dostawców typu",
"This provider can't be unlinked": "Ten dostawca nie może zostać odłączony",
"You are not the global admin, you can't unlink other users": "Nie jesteś globalnym administratorem, nie możesz odłączyć innych użytkowników",
"You can't unlink yourself, you are not a member of any application": "Nie możesz odłączyć siebie, nie jesteś członkiem żadnej aplikacji"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
"Only admin can modify the %s.": "Tylko administrator może modyfikować %s.",
"The %s is immutable.": "%s jest niezmienny.",
"Unknown modify rule %s.": "Nieznana reguła modyfikacji %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "Dodawanie nowego użytkownika do organizacji „built-in' (wbudowanej) jest obecnie wyłączone. Należy zauważyć, że wszyscy użytkownicy w organizacji „built-in' są globalnymi administratorami w Casdoor. Zobacz dokumentację: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. Jeśli nadal chcesz utworzyć użytkownika dla organizacji „built-in', przejdź do strony ustawień organizacji i włącz opcję „Ma zgodę na uprawnienia'."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
"The permission: \"%s\" doesn't exist": "Uprawnienie: \"%s\" nie istnieje"
},
"product": {
"Product list cannot be empty": "Lista produktów nie może być pusta"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
"Failed to initialize ID Verification provider": "Nie udało się zainicjować dostawcy weryfikacji ID",
"Invalid application id": "Nieprawidłowe id aplikacji",
"No ID Verification provider configured": "Brak skonfigurowanego dostawcy weryfikacji ID",
"Provider is not an ID Verification provider": "Dostawca nie jest dostawcą weryfikacji ID",
"the provider: %s does not exist": "dostawca: %s nie istnieje"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
"User is nil for tag: avatar": "Użytkownik jest nil dla tagu: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Nazwa użytkownika lub pełna ścieżka pliku jest pusta: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
"Application %s not found": "Aplikacja %s nie została znaleziona"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
"provider %s's category is not SAML": "kategoria dostawcy %s nie jest SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
"Empty parameters for emailForm: %v": "Puste parametry dla emailForm: %v",
"Invalid Email receivers: %s": "Nieprawidłowi odbiorcy email: %s",
"Invalid phone receivers: %s": "Nieprawidłowi odbiorcy telefonu: %s"
},
"session": {
"session id %s is the current session and cannot be deleted": "identyfikator sesji %s jest bieżącą sesją i nie może być usunięty"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
"The objectKey: %s is not allowed": "Klucz obiektu: %s jest niedozwolony",
"The provider type: %s is not supported": "Typ dostawcy: %s nie jest obsługiwany"
},
"subscription": {
"Error": "Error"
"Error": "Błąd"
},
"ticket": {
"Ticket not found": "Nie znaleziono biletu"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
"Grant_type: %s is not supported in this application": "Grant_type: %s nie jest obsługiwany w tej aplikacji",
"Invalid application or wrong clientSecret": "Nieprawidłowa aplikacja lub błędny clientSecret",
"Invalid client_id": "Nieprawidłowy client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s nie istnieje na liście dozwolonych Redirect URI",
"Token not found, invalid accessToken": "Token nie znaleziony, nieprawidłowy accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"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"
"Display name cannot be empty": "Nazwa wyświetlana nie może być pusta",
"ID card information and real name are required": "Wymagane są informacje z dowodu osobistego i prawdziwe nazwisko",
"Identity verification failed": "Weryfikacja tożsamości nie powiodła się",
"MFA email is enabled but email is empty": "MFA email jest włączone, ale email jest pusty",
"MFA phone is enabled but phone number is empty": "MFA telefon jest włączony, ale numer telefonu jest pusty",
"New password cannot contain blank space.": "Nowe hasło nie może zawierać spacji.",
"No application found for user": "Nie znaleziono aplikacji dla użytkownika",
"The new password must be different from your current password": "Nowe hasło musi różnić się od obecnego hasła",
"User is already verified": "Użytkownik jest już zweryfikowany",
"the user's owner and name should not be empty": "właściciel i nazwa użytkownika nie powinny być puste"
},
"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",
"The provider: %s is not found": "The provider: %s is not found"
"No application is found for userId: %s": "Nie znaleziono aplikacji dla userId: %s",
"No provider for category: %s is found for application: %s": "Nie znaleziono dostawcy dla kategorii: %s dla aplikacji: %s",
"The provider: %s is not found": "Dostawca: %s nie został znaleziony"
},
"verification": {
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
"Invalid captcha provider.": "Nieprawidłowy dostawca captcha.",
"Phone number is invalid in your region %s": "Numer telefonu jest nieprawidłowy w twoim regionie %s",
"The forgot password feature is disabled": "Funkcja \"Zapomniałem hasła\" jest wyłączona",
"The verification code has already been used!": "Kod weryfikacyjny został już wykorzystany!",
"The verification code has not been sent yet!": "Kod weryfikacyjny nie został jeszcze wysłany!",
"Turing test failed.": "Test Turinga nie powiódł się.",
"Unable to get the email modify rule.": "Nie można pobrać reguły modyfikacji email.",
"Unable to get the phone modify rule.": "Nie można pobrać reguły modyfikacji telefonu.",
"Unknown type": "Nieznany typ",
"Wrong verification code!": "Zły kod weryfikacyjny!",
"You should verify your code in %d min!": "Powinieneś zweryfikować swój kod w ciągu %d min!",
"please add a SMS provider to the \"Providers\" list for the application: %s": "proszę dodać dostawcę SMS do listy \"Providers\" dla aplikacji: %s",
"please add an Email provider to the \"Providers\" list for the application: %s": "proszę dodać dostawcę email do listy \"Providers\" dla aplikacji: %s",
"the user does not exist, please sign up first": "użytkownik nie istnieje, najpierw się zarejestruj"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Found no credentials for this user": "Nie znaleziono danych uwierzytelniających dla tego użytkownika",
"Please call WebAuthnSigninBegin first": "Najpierw wywołaj WebAuthnSigninBegin"
}
}

Some files were not shown because too many files have changed in this diff Show More