mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-12 00:37:51 +08:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
386b673446 | ||
![]() |
6abd46fe81 | ||
![]() |
49d734d249 | ||
![]() |
f5b4cd7fab |
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -187,6 +188,11 @@ func (c *ApiController) DeleteResource() {
|
||||
}
|
||||
_, resource.Name = refineFullFilePath(resource.Name)
|
||||
|
||||
tag := c.Input().Get("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())
|
||||
|
@@ -16,6 +16,7 @@ package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
@@ -209,7 +210,7 @@ func GetPolicies(id string) ([]*xormadapter.CasbinRule, error) {
|
||||
// Filter represents filter criteria with optional policy type
|
||||
type Filter struct {
|
||||
Ptype string `json:"ptype,omitempty"`
|
||||
FieldIndex int `json:"fieldIndex"`
|
||||
FieldIndex *int `json:"fieldIndex,omitempty"`
|
||||
FieldValues []string `json:"fieldValues"`
|
||||
}
|
||||
|
||||
@@ -262,24 +263,29 @@ func GetFilteredPoliciesMulti(id string, filters []Filter) ([]*xormadapter.Casbi
|
||||
for _, policy := range allPolicies {
|
||||
matchesAllFilters := true
|
||||
for _, filter := range filters {
|
||||
// If no policy type is specified, set it to the default policy type
|
||||
// Default policy type if unspecified
|
||||
if filter.Ptype == "" {
|
||||
filter.Ptype = "p"
|
||||
}
|
||||
// Check policy type
|
||||
// Always check policy type
|
||||
if policy.Ptype != filter.Ptype {
|
||||
matchesAllFilters = false
|
||||
break
|
||||
}
|
||||
|
||||
// Check if field index is valid (0-5 for V0-V5)
|
||||
if filter.FieldIndex < 0 || filter.FieldIndex > 5 {
|
||||
matchesAllFilters = false
|
||||
break
|
||||
// If FieldIndex is nil, only filter via ptype (skip field-value checks)
|
||||
if filter.FieldIndex == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldValue := ""
|
||||
switch filter.FieldIndex {
|
||||
fieldIndex := *filter.FieldIndex
|
||||
// If FieldIndex is out of range, also only filter via ptype
|
||||
if fieldIndex < 0 || fieldIndex > 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
var fieldValue string
|
||||
switch fieldIndex {
|
||||
case 0:
|
||||
fieldValue = policy.V0
|
||||
case 1:
|
||||
@@ -294,15 +300,8 @@ func GetFilteredPoliciesMulti(id string, filters []Filter) ([]*xormadapter.Casbi
|
||||
fieldValue = policy.V5
|
||||
}
|
||||
|
||||
found := false
|
||||
// Check if field value is in the list of expected values
|
||||
for _, expectedValue := range filter.FieldValues {
|
||||
if fieldValue == expectedValue {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
// When FieldIndex is provided and valid, enforce FieldValues (if any)
|
||||
if len(filter.FieldValues) > 0 && !slices.Contains(filter.FieldValues, fieldValue) {
|
||||
matchesAllFilters = false
|
||||
break
|
||||
}
|
||||
|
@@ -31,9 +31,11 @@ func GetDirectResources(owner string, user string, provider *Provider, prefix st
|
||||
fullPathPrefix := util.UrlJoin(provider.PathPrefix, prefix)
|
||||
objects, err := storageProvider.List(fullPathPrefix)
|
||||
for _, obj := range objects {
|
||||
name := strings.TrimPrefix(obj.Path, "/")
|
||||
name = strings.TrimPrefix(name, provider.PathPrefix+"/")
|
||||
resource := &Resource{
|
||||
Owner: owner,
|
||||
Name: strings.TrimPrefix(obj.Path, "/"),
|
||||
Name: name,
|
||||
CreatedTime: obj.LastModified.Local().Format(time.RFC3339),
|
||||
User: user,
|
||||
Provider: "",
|
||||
|
@@ -1296,6 +1296,9 @@ export function renderSignupLink(application, text) {
|
||||
} else {
|
||||
if (application.signupUrl === "") {
|
||||
url = `/signup/${application.name}`;
|
||||
if (application.isShared) {
|
||||
url = `/signup/${application.name}-org-${application.organization}`;
|
||||
}
|
||||
} else {
|
||||
url = application.signupUrl;
|
||||
}
|
||||
|
@@ -648,6 +648,9 @@ class LoginPage extends React.Component {
|
||||
)
|
||||
;
|
||||
} else if (signinItem.name === "Username") {
|
||||
if (this.state.loginMethod === "wechat") {
|
||||
return (<WeChatLoginPanel application={application} loginMethod={this.state.loginMethod} />);
|
||||
}
|
||||
return (
|
||||
<div key={resultItemKey}>
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.customCss?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
@@ -750,6 +753,9 @@ class LoginPage extends React.Component {
|
||||
} else if (signinItem.name === "Agreement") {
|
||||
return AgreementModal.isAgreementRequired(application) ? AgreementModal.renderAgreementFormItem(application, true, {}, this) : null;
|
||||
} else if (signinItem.name === "Login button") {
|
||||
if (this.state.loginMethod === "wechat") {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Form.Item key={resultItemKey} className="login-button-box">
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.customCss?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
@@ -896,10 +902,6 @@ class LoginPage extends React.Component {
|
||||
loginWidth += 10;
|
||||
}
|
||||
|
||||
if (this.state.loginMethod === "wechat") {
|
||||
return (<WeChatLoginPanel application={application} renderFormItem={this.renderFormItem.bind(this)} loginMethod={this.state.loginMethod} loginWidth={loginWidth} renderMethodChoiceBox={this.renderMethodChoiceBox.bind(this)} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="normal_login"
|
||||
@@ -1239,6 +1241,7 @@ class LoginPage extends React.Component {
|
||||
[generateItemKey("WebAuthn", "None"), {label: i18next.t("login:WebAuthn"), key: "webAuthn"}],
|
||||
[generateItemKey("LDAP", "None"), {label: i18next.t("login:LDAP"), key: "ldap"}],
|
||||
[generateItemKey("Face ID", "None"), {label: i18next.t("login:Face ID"), key: "faceId"}],
|
||||
[generateItemKey("WeChat", "Tab"), {label: i18next.t("login:WeChat"), key: "wechat"}],
|
||||
[generateItemKey("WeChat", "None"), {label: i18next.t("login:WeChat"), key: "wechat"}],
|
||||
]);
|
||||
|
||||
@@ -1403,6 +1406,8 @@ class LoginPage extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const wechatSigninMethods = application.signinMethods?.filter(method => method.name === "WeChat" && method.rule === "Login page");
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CustomGithubCorner />
|
||||
@@ -1420,6 +1425,15 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
wechatSigninMethods?.length > 0 ? (<div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
|
||||
<div>
|
||||
<h3 style={{textAlign: "center", width: 320}}>{i18next.t("provider:Please use WeChat to scan the QR code and follow the official account for sign in")}</h3>
|
||||
<WeChatLoginPanel application={application} loginMethod={this.state.loginMethod} />
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
@@ -78,13 +78,10 @@ class WeChatLoginPanel extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {application, loginWidth = 320} = this.props;
|
||||
const {loginWidth = 320} = this.props;
|
||||
const {status, qrCode} = this.state;
|
||||
return (
|
||||
<div style={{width: loginWidth, margin: "0 auto", textAlign: "center", marginTop: 16}}>
|
||||
{application.signinItems?.filter(item => item.name === "Logo").map(signinItem => this.props.renderFormItem(application, signinItem))}
|
||||
{this.props.renderMethodChoiceBox()}
|
||||
{application.signinItems?.filter(item => item.name === "Languages").map(signinItem => this.props.renderFormItem(application, signinItem))}
|
||||
<div style={{marginTop: 2}}>
|
||||
<QRCode style={{margin: "auto", marginTop: "20px", marginBottom: "20px"}} bordered={false} status={status} value={qrCode ?? " "} size={230} />
|
||||
<div style={{marginTop: 8}}>
|
||||
|
@@ -96,6 +96,8 @@ class SigninMethodTable extends React.Component {
|
||||
this.updateField(table, index, "displayName", value);
|
||||
if (value === "Verification code" || value === "Password") {
|
||||
this.updateField(table, index, "rule", "All");
|
||||
} else if (value === "WeChat") {
|
||||
this.updateField(table, index, "rule", "Tab");
|
||||
} else {
|
||||
this.updateField(table, index, "rule", "None");
|
||||
}
|
||||
@@ -139,6 +141,11 @@ class SigninMethodTable extends React.Component {
|
||||
{id: "Non-LDAP", name: i18next.t("general:Non-LDAP")},
|
||||
{id: "Hide password", name: i18next.t("general:Hide password")},
|
||||
];
|
||||
} else if (record.name === "WeChat") {
|
||||
options = [
|
||||
{id: "Tab", name: i18next.t("general:Tab")},
|
||||
{id: "Login page", name: i18next.t("general:Login page")},
|
||||
];
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
|
Reference in New Issue
Block a user