diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index 7b86e2b47..4559f2a2c 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -39,6 +39,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
g.POST("/resetAllTraffics", a.resetAllTraffics)
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
+ g.POST("/delDepletedClients/:id", a.delDepletedClients)
}
@@ -170,7 +171,7 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
err = a.inboundService.AddInboundClient(data)
if err != nil {
- jsonMsg(c, "something worng!", err)
+ jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client(s) added", nil)
@@ -189,7 +190,7 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
err = a.inboundService.DelInboundClient(id, clientId)
if err != nil {
- jsonMsg(c, "something worng!", err)
+ jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client deleted", nil)
@@ -210,7 +211,7 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
err = a.inboundService.UpdateInboundClient(inbound, clientId)
if err != nil {
- jsonMsg(c, "something worng!", err)
+ jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client updated", nil)
@@ -229,7 +230,7 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
err = a.inboundService.ResetClientTraffic(id, email)
if err != nil {
- jsonMsg(c, "something worng!", err)
+ jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "traffic reseted", nil)
@@ -241,7 +242,7 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
func (a *InboundController) resetAllTraffics(c *gin.Context) {
err := a.inboundService.ResetAllTraffics()
if err != nil {
- jsonMsg(c, "something worng!", err)
+ jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "All traffics reseted", nil)
@@ -256,8 +257,22 @@ func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
err = a.inboundService.ResetAllClientTraffics(id)
if err != nil {
- jsonMsg(c, "something worng!", err)
+ jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "All traffics of client reseted", nil)
}
+
+func (a *InboundController) delDepletedClients(c *gin.Context) {
+ id, err := strconv.Atoi(c.Param("id"))
+ if err != nil {
+ jsonMsg(c, I18n(c, "pages.inbounds.revise"), err)
+ return
+ }
+ err = a.inboundService.DelDepletedClients(id)
+ if err != nil {
+ jsonMsg(c, "Something went wrong!", err)
+ return
+ }
+ jsonMsg(c, "All delpeted clients are deleted", nil)
+}
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index 483b0030c..275b1468d 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -82,6 +82,10 @@
{{ i18n "pages.inbounds.resetAllClientTraffics" }}
+
+
+ {{ i18n "pages.inbounds.delDepletedClients" }}
+
@@ -122,6 +126,10 @@
{{ i18n "pages.inbounds.export"}}
+
+
+ {{ i18n "pages.inbounds.delDepletedClients" }}
+
@@ -416,7 +424,8 @@
case "resetClients":
this.resetAllClientTraffics(-1);
break;
- case "":
+ case "delDepletedClients":
+ this.delDepletedClients(-1)
break;
}
},
@@ -452,6 +461,9 @@
case "delete":
this.delInbound(dbInbound.id);
break;
+ case "delDepletedClients":
+ this.delDepletedClients(dbInbound.id)
+ break;
}
},
openCloneInbound(dbInbound) {
@@ -730,6 +742,16 @@
onOk: () => this.submit('/xui/inbound/resetAllClientTraffics/' + dbInboundId),
})
},
+ delDepletedClients(dbInboundId) {
+ this.$confirm({
+ title: '{{ i18n "pages.inbounds.delDepletedClientsTitle"}}',
+ content: '{{ i18n "pages.inbounds.delDepletedClientsContent"}}',
+ class: siderDrawer.isDarkTheme ? darkClass : '',
+ okText: '{{ i18n "reset"}}',
+ cancelText: '{{ i18n "cancel"}}',
+ onOk: () => this.submit('/xui/inbound/delDepletedClients/' + dbInboundId),
+ })
+ },
isExpiry(dbInbound, index) {
return dbInbound.toInbound().isExpiry(index)
},
diff --git a/web/service/inbound.go b/web/service/inbound.go
index ab2ceb669..db0e6aaf1 100644
--- a/web/service/inbound.go
+++ b/web/service/inbound.go
@@ -3,6 +3,7 @@ package service
import (
"encoding/json"
"fmt"
+ "strings"
"time"
"x-ui/database"
"x-ui/database/model"
@@ -715,6 +716,84 @@ func (s *InboundService) ResetAllTraffics() error {
return nil
}
+func (s *InboundService) DelDepletedClients(id int) (err error) {
+ db := database.GetDB()
+ tx := db.Begin()
+ defer func() {
+ if err == nil {
+ tx.Commit()
+ } else {
+ tx.Rollback()
+ }
+ }()
+
+ whereText := "inbound_id "
+ if id < 0 {
+ whereText += "> ?"
+ } else {
+ whereText += "= ?"
+ }
+
+ depletedClients := []xray.ClientTraffic{}
+ err = db.Model(xray.ClientTraffic{}).Where(whereText+" and enable = ?", id, false).Select("inbound_id, GROUP_CONCAT(email) as email").Group("inbound_id").Find(&depletedClients).Error
+ if err != nil {
+ return err
+ }
+
+ for _, depletedClient := range depletedClients {
+ emails := strings.Split(depletedClient.Email, ",")
+ oldInbound, err := s.GetInbound(depletedClient.InboundId)
+ if err != nil {
+ return err
+ }
+ var oldSettings map[string]interface{}
+ err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
+ if err != nil {
+ return err
+ }
+
+ oldClients := oldSettings["clients"].([]interface{})
+ var newClients []interface{}
+ for _, client := range oldClients {
+ deplete := false
+ c := client.(map[string]interface{})
+ for _, email := range emails {
+ if email == c["email"].(string) {
+ deplete = true
+ break
+ }
+ }
+ if !deplete {
+ newClients = append(newClients, client)
+ }
+ }
+ if len(newClients) > 0 {
+ oldSettings["clients"] = newClients
+
+ newSettings, err := json.MarshalIndent(oldSettings, "", " ")
+ if err != nil {
+ return err
+ }
+
+ oldInbound.Settings = string(newSettings)
+ err = tx.Save(oldInbound).Error
+ if err != nil {
+ return err
+ }
+ } else {
+ // Delete inbound if no client remains
+ s.DelInbound(depletedClient.InboundId)
+ }
+ }
+
+ err = tx.Where(whereText+" and enable = ?", id, false).Delete(xray.ClientTraffic{}).Error
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
func (s *InboundService) GetClientTrafficTgBot(tguname string) ([]*xray.ClientTraffic, error) {
db := database.GetDB()
var inbounds []*model.Inbound
diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml
index 2d2936db9..0577b708b 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -150,6 +150,9 @@
"resetAllClientTraffics" = "Reset All Clients Traffic"
"resetAllClientTrafficTitle" = "Reset all clients traffic"
"resetAllClientTrafficContent" = "Are you sure to reset all traffics of all clients ?"
+"delDepletedClients" = "Delete depleted clients"
+"delDepletedClientsTitle" = "Delete depleted clients"
+"delDepletedClientsContent" = "Are you sure to delete all depleted clients ?"
"Email" = "Email"
"EmailDesc" = "Please provide a unique email address"
"IPLimitlog" = "IP Log"
diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml
index 12fb7f2bf..a00ced7e4 100644
--- a/web/translation/translate.fa_IR.toml
+++ b/web/translation/translate.fa_IR.toml
@@ -146,6 +146,9 @@
"resetAllClientTraffics" = "ریست ترافیک کاربران"
"resetAllClientTrafficTitle" = "ریست ترافیک کل کاربران"
"resetAllClientTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک کاربران را ریست کنید؟"
+"delDepletedClients" = "حذف کاربران منقضی"
+"delDepletedClientsTitle" = "حذف کاربران منقضی"
+"delDepletedClientsContent" = "آیا مطمئن هستید مه میخواهید تمامی کاربران منقضی شده را حذف کنید؟"
"IPLimit" = "محدودیت ای پی"
"IPLimitDesc" = "غیرفعال کردن ورودی در صورت بیش از تعداد وارد شده (0 برای غیرفعال کردن محدودیت ای پی )"
"Email" = "ایمیل"
diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml
index 1d0a34666..3e189324a 100644
--- a/web/translation/translate.zh_Hans.toml
+++ b/web/translation/translate.zh_Hans.toml
@@ -146,6 +146,9 @@
"resetAllClientTraffics" = "重置所有客户端流量"
"resetAllClientTrafficTitle" = "重置所有客户端流量"
"resetAllClientTrafficContent" = "你确定要重置所有客户端的所有流量吗?"
+"delDepletedClients" = "删除耗尽的客户端"
+"delDepletedClientsTitle" = "删除耗尽的客户"
+"delDepletedClientsContent" = "你确定要删除所有耗尽的客户端吗?"
"IPLimit" = "IP限制"
"IPLimitDesc" = "如果超过输入的计数则禁用入站(0 表示禁用限制 ip)"
"Email" = "电子邮件"