修复IPv6插件的逻辑错误
This commit is contained in:
@@ -292937,7 +292937,11 @@ function c5t() {
|
||||
},
|
||||
[v, l],
|
||||
),
|
||||
E = () => {
|
||||
E = (e) => {
|
||||
if (e) {
|
||||
o(!0);
|
||||
return;
|
||||
}
|
||||
(o(!1), a(null), v.reset(i));
|
||||
};
|
||||
return Q.jsxs(Jet, {
|
||||
@@ -294416,7 +294420,8 @@ function T5t({ node: e, refetch: t, t: n }) {
|
||||
children: [
|
||||
Q.jsx(Rot, {
|
||||
className: "cursor-pointer",
|
||||
onClick: () => {
|
||||
onSelect: (t) => {
|
||||
t.preventDefault();
|
||||
(o(e.type), r(e), i(!0));
|
||||
},
|
||||
children: Q.jsxs("div", {
|
||||
@@ -305860,7 +305865,7 @@ function codexNativeIPv6Table() {
|
||||
[r, o] = H.useState({}),
|
||||
[s, a] = H.useState({}),
|
||||
[l, c] = H.useState({ pageIndex: 0, pageSize: 20 }),
|
||||
[d, u] = H.useState("0"),
|
||||
[d, u] = H.useState({ open: !1, user: null, planId: "0" }),
|
||||
[h, g] = H.useState(!1),
|
||||
{
|
||||
refetch: p,
|
||||
@@ -305873,16 +305878,30 @@ function codexNativeIPv6Table() {
|
||||
params: { page: l.pageIndex + 1, per_page: l.pageSize, keyword: n },
|
||||
}),
|
||||
}),
|
||||
{ data: _, refetch: v } = gC({
|
||||
{ data: _ } = gC({
|
||||
queryKey: ["codexNativeIPv6Config"],
|
||||
queryFn: () => TL(`${RL()}/user-add-ipv6-subscription/config`),
|
||||
}),
|
||||
{ data: b } = gC({
|
||||
{ data: v } = gC({
|
||||
queryKey: ["codexNativeIPv6Plans"],
|
||||
queryFn: () => DD(),
|
||||
}),
|
||||
y = H.useMemo(() => (Array.isArray(b?.data) ? b.data : []), [b]),
|
||||
x = H.useMemo(
|
||||
b = H.useMemo(() => (Array.isArray(v?.data) ? v.data : []), [v]),
|
||||
y = H.useMemo(() => {
|
||||
const e = _?.data?.ipv6_plan_id;
|
||||
return e && e > 0 ? String(e) : "0";
|
||||
}, [_]),
|
||||
x = H.useCallback(
|
||||
(e) => {
|
||||
const t = e?.plan_id && e.plan_id > 0 ? String(e.plan_id) : y;
|
||||
u({ open: !0, user: e, planId: t });
|
||||
},
|
||||
[y],
|
||||
),
|
||||
w = H.useCallback(() => {
|
||||
u({ open: !1, user: null, planId: y });
|
||||
}, [y]),
|
||||
C = H.useMemo(
|
||||
() => [
|
||||
JKt.display({
|
||||
id: "relation",
|
||||
@@ -305896,16 +305915,10 @@ function codexNativeIPv6Table() {
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "max-w-[240px] truncate", children: e.getValue("email") || "-" }),
|
||||
},
|
||||
{
|
||||
accessorKey: "ipv6_email",
|
||||
header: () => "IPv6 account",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "font-mono text-xs", children: e.getValue("ipv6_email") || "-" }),
|
||||
},
|
||||
{
|
||||
accessorKey: "plan_name",
|
||||
header: () => "IPv6 plan",
|
||||
cell: ({ row: e }) => e.getValue("plan_name") || "-",
|
||||
cell: ({ row: e }) => e.getValue("plan_name") || "",
|
||||
},
|
||||
JKt.display({
|
||||
id: "status",
|
||||
@@ -305915,40 +305928,53 @@ function codexNativeIPv6Table() {
|
||||
JKt.display({
|
||||
id: "actions",
|
||||
header: () => "Actions",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsxs("div", {
|
||||
cell: ({ row: e }) => {
|
||||
const t = e.original.is_active || "active" === e.original.status,
|
||||
n = "disabled" === e.original.status,
|
||||
i = t ? "Set plan" : n ? "Re-enable" : "Enable";
|
||||
return Q.jsxs("div", {
|
||||
className: "flex flex-wrap items-center gap-2",
|
||||
children: [
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/enable/${e.original.id}`, {});
|
||||
hN.success("IPv6 account enabled and synced");
|
||||
p();
|
||||
},
|
||||
children: "Enable and sync",
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
variant: "outline",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/sync-password/${e.original.id}`, {});
|
||||
hN.success("Password synced");
|
||||
p();
|
||||
},
|
||||
children: "Sync password",
|
||||
onClick: () => x(e.original),
|
||||
children: i,
|
||||
}),
|
||||
t &&
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
variant: "outline",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/disable/${e.original.id}`, {});
|
||||
hN.success("IPv6 account disabled");
|
||||
p();
|
||||
},
|
||||
children: "Disable",
|
||||
}),
|
||||
t &&
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
variant: "outline",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/sync-password/${e.original.id}`, {});
|
||||
hN.success("Password synced");
|
||||
p();
|
||||
},
|
||||
children: "Sync password",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
},
|
||||
}),
|
||||
],
|
||||
[p],
|
||||
[x, p],
|
||||
),
|
||||
w = PKt({
|
||||
S = PKt({
|
||||
data: f?.data?.list ?? [],
|
||||
columns: x,
|
||||
columns: C,
|
||||
state: { columnVisibility: r, rowSelection: s, pagination: l },
|
||||
getRowId: (e) => String(e.id),
|
||||
rowCount: f?.data?.pagination?.total ?? 0,
|
||||
@@ -305960,82 +305986,108 @@ function codexNativeIPv6Table() {
|
||||
getCoreRowModel: LKt(),
|
||||
getPaginationRowModel: OKt(),
|
||||
});
|
||||
return (
|
||||
H.useEffect(() => {
|
||||
const e = _?.data?.ipv6_plan_id;
|
||||
u(e && e > 0 ? String(e) : "0");
|
||||
}, [_]),
|
||||
Q.jsxs("div", {
|
||||
className: "space-y-4",
|
||||
children: [
|
||||
Q.jsx(codexNativeSearchToolbar, {
|
||||
keyword: e,
|
||||
setKeyword: t,
|
||||
onSearch: () => {
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
i(e.trim());
|
||||
},
|
||||
onReset: () => {
|
||||
t("");
|
||||
i("");
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
},
|
||||
refetch: p,
|
||||
actions: Q.jsxs("div", {
|
||||
className: "flex flex-wrap items-center gap-2",
|
||||
children: [
|
||||
Q.jsx("span", { className: "text-sm text-muted-foreground", children: "IPv6Only plan" }),
|
||||
Q.jsxs("div", {
|
||||
className: "relative",
|
||||
children: [
|
||||
Q.jsxs("select", {
|
||||
className:
|
||||
"flex h-8 min-w-[180px] appearance-none rounded-md border border-input bg-transparent px-3 pr-8 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
value: d,
|
||||
onChange: (e) => u(e.target.value),
|
||||
children: [
|
||||
Q.jsx("option", { value: "0", children: "Not set" }),
|
||||
y.map((e) =>
|
||||
Q.jsx("option", { value: String(e.id), children: e.name || `Plan ${e.id}` }, e.id),
|
||||
),
|
||||
],
|
||||
}),
|
||||
Q.jsx(m7e, {
|
||||
className:
|
||||
"pointer-events-none absolute right-2 top-2 h-4 w-4 text-muted-foreground/70",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
className: "h-8",
|
||||
loading: h,
|
||||
onClick: async () => {
|
||||
g(!0);
|
||||
try {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/config`, {
|
||||
ipv6_plan_id: Number(d) || 0,
|
||||
});
|
||||
hN.success("IPv6Only plan saved");
|
||||
await Promise.all([v(), p()]);
|
||||
} finally {
|
||||
g(!1);
|
||||
}
|
||||
},
|
||||
children: "Save plan",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
return Q.jsxs("div", {
|
||||
className: "space-y-4",
|
||||
children: [
|
||||
Q.jsx(codexNativeSearchToolbar, {
|
||||
keyword: e,
|
||||
setKeyword: t,
|
||||
onSearch: () => {
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
i(e.trim());
|
||||
},
|
||||
onReset: () => {
|
||||
t("");
|
||||
i("");
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
},
|
||||
refetch: p,
|
||||
}),
|
||||
Q.jsx(QKt, {
|
||||
table: S,
|
||||
isLoading: m,
|
||||
showPagination: !0,
|
||||
mobilePrimaryField: "email",
|
||||
mobileGridFields: ["plan_name", "status"],
|
||||
}),
|
||||
Q.jsx(Jet, {
|
||||
open: d.open,
|
||||
onOpenChange: (e) => {
|
||||
e ? u((e) => ({ ...e, open: !0 })) : w();
|
||||
},
|
||||
children: Q.jsxs(ttt, {
|
||||
className: "sm:max-w-md",
|
||||
children: [
|
||||
Q.jsxs(ntt, {
|
||||
children: [
|
||||
Q.jsx(rtt, { children: "Set IPv6 plan" }),
|
||||
Q.jsx(ott, {
|
||||
children: d.user ? `User: ${d.user.email || d.user.id}` : "Choose the plan for this IPv6 account.",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Q.jsxs("div", {
|
||||
className: "space-y-4 p-6",
|
||||
children: [
|
||||
Q.jsxs("div", {
|
||||
className: "space-y-2",
|
||||
children: [
|
||||
Q.jsx("label", { className: "text-sm font-medium text-foreground", children: "IPv6 plan" }),
|
||||
Q.jsxs("div", {
|
||||
className: "relative",
|
||||
children: [
|
||||
Q.jsxs("select", {
|
||||
className:
|
||||
"flex h-10 w-full appearance-none rounded-md border border-input bg-transparent px-3 pr-8 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
value: d.planId,
|
||||
onChange: (e) => u((t) => ({ ...t, planId: e.target.value })),
|
||||
children: [
|
||||
Q.jsx("option", { value: "0", children: "Use default plan" }),
|
||||
b.map((e) =>
|
||||
Q.jsx("option", { value: String(e.id), children: e.name || `Plan ${e.id}` }, e.id),
|
||||
),
|
||||
],
|
||||
}),
|
||||
Q.jsx(m7e, {
|
||||
className:
|
||||
"pointer-events-none absolute right-3 top-3.5 h-4 w-4 text-muted-foreground/70",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Q.jsxs("div", {
|
||||
className: "flex justify-end gap-2",
|
||||
children: [
|
||||
Q.jsx(Nm, { type: "button", variant: "outline", onClick: w, children: "Cancel" }),
|
||||
Q.jsx(Nm, {
|
||||
type: "button",
|
||||
loading: h,
|
||||
onClick: async () => {
|
||||
if (!d.user) return;
|
||||
g(!0);
|
||||
try {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/enable/${d.user.id}`, {
|
||||
plan_id: Number(d.planId) || 0,
|
||||
});
|
||||
hN.success("IPv6 account updated");
|
||||
w();
|
||||
await p();
|
||||
} finally {
|
||||
g(!1);
|
||||
}
|
||||
},
|
||||
children: "Save",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Q.jsx(QKt, {
|
||||
table: w,
|
||||
isLoading: m,
|
||||
showPagination: !0,
|
||||
mobilePrimaryField: "email",
|
||||
mobileGridFields: ["ipv6_email", "plan_name", "status"],
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeIPv6Page() {
|
||||
return codexNativePageLayout(
|
||||
|
||||
@@ -1069,12 +1069,17 @@
|
||||
saveToken(payload.auth_data);
|
||||
state.authToken = getStoredToken();
|
||||
|
||||
// Try IPv6 login/register if email/password available
|
||||
if (data.email && data.password) {
|
||||
var ipv6Email = data.email.replace("@", "-ipv6@");
|
||||
var ipv6Action = formType === "register" ? "/api/v1/passport/auth/register" : "/api/v1/passport/auth/login";
|
||||
showMessage(formType === "register" ? "Account created" : "Signed in", "success");
|
||||
return loadDashboard(true).then(function () {
|
||||
if (formType !== "login" || !data.email || !data.password || state.ipv6AuthToken) {
|
||||
return null;
|
||||
}
|
||||
if (!(state.ipv6Eligibility && state.ipv6Eligibility.is_active)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
fetchJson(ipv6Action, {
|
||||
var ipv6Email = data.email.replace("@", "-ipv6@");
|
||||
return fetchJson("/api/v1/passport/auth/login", {
|
||||
method: "POST",
|
||||
auth: false,
|
||||
body: Object.assign({}, data, { email: ipv6Email })
|
||||
@@ -1085,14 +1090,11 @@
|
||||
state.ipv6AuthToken = getStoredIpv6Token();
|
||||
}
|
||||
}).catch(function () {
|
||||
// Ignore IPv6 errors as it might not be enabled yet or fail
|
||||
}).finally(function() {
|
||||
loadDashboard(true).then(render);
|
||||
return null;
|
||||
}).then(function () {
|
||||
return loadDashboard(true);
|
||||
});
|
||||
}
|
||||
|
||||
showMessage(formType === "register" ? "Account created" : "Signed in", "success");
|
||||
return loadDashboard(true);
|
||||
});
|
||||
}).then(render).catch(function (error) {
|
||||
showMessage(error.message || "Unable to continue", "error");
|
||||
render();
|
||||
|
||||
@@ -183,29 +183,39 @@ func AdminIPv6SubscriptionUsers(c *gin.Context) {
|
||||
}
|
||||
|
||||
subscriptionByUserID := make(map[int]model.UserIPv6Subscription, len(userIDs))
|
||||
shadowUserIDs := make([]int, 0, len(userIDs))
|
||||
if len(userIDs) > 0 {
|
||||
var rows []model.UserIPv6Subscription
|
||||
if err := database.DB.Where("user_id IN ?", userIDs).Find(&rows).Error; err == nil {
|
||||
for _, row := range rows {
|
||||
subscriptionByUserID[row.UserID] = row
|
||||
if row.ShadowUserID != nil && *row.ShadowUserID > 0 {
|
||||
shadowUserIDs = append(shadowUserIDs, *row.ShadowUserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shadowByParentID := make(map[int]model.User, len(userIDs))
|
||||
shadowByID := make(map[int]model.User, len(shadowUserIDs))
|
||||
shadowByEmail := make(map[string]model.User, len(userIDs))
|
||||
if len(userIDs) > 0 {
|
||||
var shadowUsers []model.User
|
||||
if err := database.DB.Preload("Plan").Where("parent_id IN ?", userIDs).Find(&shadowUsers).Error; err == nil {
|
||||
query := database.DB.Preload("Plan")
|
||||
if len(shadowUserIDs) > 0 {
|
||||
query = query.Where("parent_id IN ? OR id IN ?", userIDs, shadowUserIDs)
|
||||
} else {
|
||||
query = query.Where("parent_id IN ?", userIDs)
|
||||
}
|
||||
if err := query.Find(&shadowUsers).Error; err == nil {
|
||||
for _, shadow := range shadowUsers {
|
||||
shadowByID[shadow.ID] = shadow
|
||||
shadowByEmail[strings.ToLower(shadow.Email)] = shadow
|
||||
if shadow.ParentID != nil {
|
||||
shadowByParentID[*shadow.ParentID] = shadow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shadowPlanID := parsePositiveInt(
|
||||
service.GetPluginConfigString(service.PluginUserAddIPv6, "ipv6_plan_id", "0"),
|
||||
0,
|
||||
)
|
||||
planNames := make(map[int]string)
|
||||
var plans []model.Plan
|
||||
if err := database.DB.Select("id", "name").Find(&plans).Error; err == nil {
|
||||
@@ -218,6 +228,12 @@ func AdminIPv6SubscriptionUsers(c *gin.Context) {
|
||||
for _, user := range users {
|
||||
subscription, hasSubscription := subscriptionByUserID[user.ID]
|
||||
shadowUser, hasShadowUser := shadowByParentID[user.ID]
|
||||
if !hasShadowUser && hasSubscription && subscription.ShadowUserID != nil {
|
||||
shadowUser, hasShadowUser = shadowByID[*subscription.ShadowUserID]
|
||||
}
|
||||
if !hasShadowUser {
|
||||
shadowUser, hasShadowUser = shadowByEmail[strings.ToLower(service.IPv6ShadowEmail(user.Email))]
|
||||
}
|
||||
if !hasSubscription && hasShadowUser {
|
||||
subscription = model.UserIPv6Subscription{
|
||||
UserID: user.ID,
|
||||
@@ -229,10 +245,9 @@ func AdminIPv6SubscriptionUsers(c *gin.Context) {
|
||||
}
|
||||
hasSubscription = true
|
||||
}
|
||||
allowed := service.PluginUserAllowed(&user, user.Plan)
|
||||
status := "not_allowed"
|
||||
planID := shadowPlanID
|
||||
planNameValue := planNames[shadowPlanID]
|
||||
status := "eligible"
|
||||
planID := 0
|
||||
planNameValue := ""
|
||||
if hasShadowUser {
|
||||
planID = intFromPointer(shadowUser.PlanID)
|
||||
planNameValue = firstString(planName(shadowUser.Plan), planNames[planID])
|
||||
@@ -246,14 +261,14 @@ func AdminIPv6SubscriptionUsers(c *gin.Context) {
|
||||
}
|
||||
shadowUpdatedAt = subscription.UpdatedAt
|
||||
}
|
||||
effectiveAllowed := allowed || hasSubscription && subscription.Allowed
|
||||
effectiveAllowed := true
|
||||
status, statusLabel, _ := ipv6StatusPresentation(status, effectiveAllowed)
|
||||
|
||||
list = append(list, gin.H{
|
||||
"id": user.ID,
|
||||
"email": user.Email,
|
||||
"plan_id": planID,
|
||||
"plan_name": firstString(planNameValue, "-"),
|
||||
"plan_name": planNameValue,
|
||||
"allowed": effectiveAllowed,
|
||||
"is_active": hasSubscription && subscription.Status == "active",
|
||||
"status": status,
|
||||
@@ -463,22 +478,13 @@ func PluginUserAddIPv6Check(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var plan *model.Plan
|
||||
if user.PlanID != nil {
|
||||
var loadedPlan model.Plan
|
||||
if err := database.DB.First(&loadedPlan, *user.PlanID).Error; err == nil {
|
||||
plan = &loadedPlan
|
||||
}
|
||||
}
|
||||
|
||||
var subscription model.UserIPv6Subscription
|
||||
hasSubscription := database.DB.Where("user_id = ?", user.ID).First(&subscription).Error == nil
|
||||
allowed := service.PluginUserAllowed(user, plan)
|
||||
status := "not_allowed"
|
||||
status := "eligible"
|
||||
if hasSubscription {
|
||||
status = firstString(subscription.Status, "active")
|
||||
}
|
||||
effectiveAllowed := allowed || hasSubscription && subscription.Allowed
|
||||
effectiveAllowed := true
|
||||
status, statusLabel, reason := ipv6StatusPresentation(status, effectiveAllowed)
|
||||
|
||||
Success(c, gin.H{
|
||||
|
||||
@@ -105,6 +105,7 @@ func SyncIPv6ShadowAccountWithPlan(user *model.User, overridePlanID int) bool {
|
||||
|
||||
ipv6User.Email = ipv6Email
|
||||
ipv6User.Password = user.Password
|
||||
ipv6User.ParentID = &user.ID
|
||||
ipv6User.U = 0
|
||||
ipv6User.D = 0
|
||||
ipv6User.T = 0
|
||||
@@ -116,6 +117,8 @@ func SyncIPv6ShadowAccountWithPlan(user *model.User, overridePlanID int) bool {
|
||||
ipv6User.PlanID = &overridePlanID
|
||||
} else if planID := parsePluginPositiveInt(GetPluginConfigString(PluginUserAddIPv6, "ipv6_plan_id", "0"), 0); planID > 0 {
|
||||
ipv6User.PlanID = &planID
|
||||
} else if ipv6User.PlanID == nil && user.PlanID != nil {
|
||||
ipv6User.PlanID = user.PlanID
|
||||
}
|
||||
if groupID := parsePluginPositiveInt(GetPluginConfigString(PluginUserAddIPv6, "ipv6_group_id", "0"), 0); groupID > 0 {
|
||||
ipv6User.GroupID = &groupID
|
||||
@@ -142,7 +145,15 @@ func DisableIPv6ShadowAccount(user *model.User) bool {
|
||||
|
||||
ipv6Email := IPv6ShadowEmail(user.Email)
|
||||
var ipv6User model.User
|
||||
if err := database.DB.Where("email = ? AND parent_id = ?", ipv6Email, user.ID).First(&ipv6User).Error; err != nil {
|
||||
|
||||
var subscription model.UserIPv6Subscription
|
||||
if err := database.DB.Where("user_id = ?", user.ID).First(&subscription).Error; err == nil && subscription.ShadowUserID != nil {
|
||||
_ = database.DB.First(&ipv6User, *subscription.ShadowUserID).Error
|
||||
}
|
||||
if ipv6User.ID == 0 {
|
||||
_ = database.DB.Where("email = ?", ipv6Email).First(&ipv6User).Error
|
||||
}
|
||||
if ipv6User.ID == 0 {
|
||||
// No shadow user found, just update subscription record
|
||||
syncIPv6SubscriptionRecord(user, nil, false, "disabled")
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user