|
@@ -787,9 +787,12 @@ func (s *ClientService) DelInboundClientByEmail(inboundSvc *InboundService, inbo
|
|
|
delStat = traffic != nil
|
|
delStat = traffic != nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // The runtime user is scoped to this inbound's tag + email, so the push plan
|
|
|
|
|
+ // is resolved independently of emailShared — a sibling inbound still carrying
|
|
|
|
|
+ // the email must not suppress removing the user from this inbound's Xray.
|
|
|
var rt runtime.Runtime
|
|
var rt runtime.Runtime
|
|
|
var push bool
|
|
var push bool
|
|
|
- if len(email) > 0 && !emailShared && (oldInbound.NodeID != nil || needApiDel) {
|
|
|
|
|
|
|
+ if len(email) > 0 && (oldInbound.NodeID != nil || needApiDel) {
|
|
|
r, p, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
|
|
r, p, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
|
|
|
if perr != nil {
|
|
if perr != nil {
|
|
|
return false, perr
|
|
return false, perr
|
|
@@ -828,8 +831,10 @@ func (s *ClientService) DelInboundClientByEmail(inboundSvc *InboundService, inbo
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Apply the runtime delete after commit — outside the serialized writer so a
|
|
// Apply the runtime delete after commit — outside the serialized writer so a
|
|
|
- // slow node call can't stall traffic accounting.
|
|
|
|
|
- if len(email) > 0 && !emailShared {
|
|
|
|
|
|
|
+ // slow node call can't stall traffic accounting. Independent of emailShared:
|
|
|
|
|
+ // Xray users are keyed by inbound tag, so the user must be removed from this
|
|
|
|
|
+ // inbound's runtime even when the same email survives in another inbound.
|
|
|
|
|
+ if len(email) > 0 {
|
|
|
if oldInbound.NodeID == nil {
|
|
if oldInbound.NodeID == nil {
|
|
|
// Local inbound: a disabled client isn't in the running Xray, so only
|
|
// Local inbound: a disabled client isn't in the running Xray, so only
|
|
|
// a live one (needApiDel) needs an API removal.
|
|
// a live one (needApiDel) needs an API removal.
|