[feature] delete depleted clients

Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
This commit is contained in:
MHSanaei 2023-04-25 18:43:37 +03:30
parent bc06dbab21
commit 379451135d
6 changed files with 132 additions and 7 deletions

View file

@ -39,6 +39,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic) g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
g.POST("/resetAllTraffics", a.resetAllTraffics) g.POST("/resetAllTraffics", a.resetAllTraffics)
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics) 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) err = a.inboundService.AddInboundClient(data)
if err != nil { if err != nil {
jsonMsg(c, "something worng!", err) jsonMsg(c, "Something went wrong!", err)
return return
} }
jsonMsg(c, "Client(s) added", nil) jsonMsg(c, "Client(s) added", nil)
@ -189,7 +190,7 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
err = a.inboundService.DelInboundClient(id, clientId) err = a.inboundService.DelInboundClient(id, clientId)
if err != nil { if err != nil {
jsonMsg(c, "something worng!", err) jsonMsg(c, "Something went wrong!", err)
return return
} }
jsonMsg(c, "Client deleted", nil) jsonMsg(c, "Client deleted", nil)
@ -210,7 +211,7 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
err = a.inboundService.UpdateInboundClient(inbound, clientId) err = a.inboundService.UpdateInboundClient(inbound, clientId)
if err != nil { if err != nil {
jsonMsg(c, "something worng!", err) jsonMsg(c, "Something went wrong!", err)
return return
} }
jsonMsg(c, "Client updated", nil) jsonMsg(c, "Client updated", nil)
@ -229,7 +230,7 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
err = a.inboundService.ResetClientTraffic(id, email) err = a.inboundService.ResetClientTraffic(id, email)
if err != nil { if err != nil {
jsonMsg(c, "something worng!", err) jsonMsg(c, "Something went wrong!", err)
return return
} }
jsonMsg(c, "traffic reseted", nil) jsonMsg(c, "traffic reseted", nil)
@ -241,7 +242,7 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
func (a *InboundController) resetAllTraffics(c *gin.Context) { func (a *InboundController) resetAllTraffics(c *gin.Context) {
err := a.inboundService.ResetAllTraffics() err := a.inboundService.ResetAllTraffics()
if err != nil { if err != nil {
jsonMsg(c, "something worng!", err) jsonMsg(c, "Something went wrong!", err)
return return
} }
jsonMsg(c, "All traffics reseted", nil) jsonMsg(c, "All traffics reseted", nil)
@ -256,8 +257,22 @@ func (a *InboundController) resetAllClientTraffics(c *gin.Context) {
err = a.inboundService.ResetAllClientTraffics(id) err = a.inboundService.ResetAllClientTraffics(id)
if err != nil { if err != nil {
jsonMsg(c, "something worng!", err) jsonMsg(c, "Something went wrong!", err)
return return
} }
jsonMsg(c, "All traffics of client reseted", nil) 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)
}

View file

@ -82,6 +82,10 @@
<a-icon type="file-done"></a-icon> <a-icon type="file-done"></a-icon>
{{ i18n "pages.inbounds.resetAllClientTraffics" }} {{ i18n "pages.inbounds.resetAllClientTraffics" }}
</a-menu-item> </a-menu-item>
<a-menu-item key="delDepletedClients">
<a-icon type="rest"></a-icon>
{{ i18n "pages.inbounds.delDepletedClients" }}
</a-menu-item>
</a-menu> </a-menu>
</a-dropdown> </a-dropdown>
</div> </div>
@ -122,6 +126,10 @@
<a-icon type="export"></a-icon> <a-icon type="export"></a-icon>
{{ i18n "pages.inbounds.export"}} {{ i18n "pages.inbounds.export"}}
</a-menu-item> </a-menu-item>
<a-menu-item key="delDepletedClients">
<a-icon type="rest"></a-icon>
{{ i18n "pages.inbounds.delDepletedClients" }}
</a-menu-item>
</template> </template>
<template v-else> <template v-else>
<a-menu-item key="showInfo"> <a-menu-item key="showInfo">
@ -416,7 +424,8 @@
case "resetClients": case "resetClients":
this.resetAllClientTraffics(-1); this.resetAllClientTraffics(-1);
break; break;
case "": case "delDepletedClients":
this.delDepletedClients(-1)
break; break;
} }
}, },
@ -452,6 +461,9 @@
case "delete": case "delete":
this.delInbound(dbInbound.id); this.delInbound(dbInbound.id);
break; break;
case "delDepletedClients":
this.delDepletedClients(dbInbound.id)
break;
} }
}, },
openCloneInbound(dbInbound) { openCloneInbound(dbInbound) {
@ -730,6 +742,16 @@
onOk: () => this.submit('/xui/inbound/resetAllClientTraffics/' + dbInboundId), 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) { isExpiry(dbInbound, index) {
return dbInbound.toInbound().isExpiry(index) return dbInbound.toInbound().isExpiry(index)
}, },

View file

@ -3,6 +3,7 @@ package service
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"time" "time"
"x-ui/database" "x-ui/database"
"x-ui/database/model" "x-ui/database/model"
@ -715,6 +716,84 @@ func (s *InboundService) ResetAllTraffics() error {
return nil 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) { func (s *InboundService) GetClientTrafficTgBot(tguname string) ([]*xray.ClientTraffic, error) {
db := database.GetDB() db := database.GetDB()
var inbounds []*model.Inbound var inbounds []*model.Inbound

View file

@ -150,6 +150,9 @@
"resetAllClientTraffics" = "Reset All Clients Traffic" "resetAllClientTraffics" = "Reset All Clients Traffic"
"resetAllClientTrafficTitle" = "Reset all clients traffic" "resetAllClientTrafficTitle" = "Reset all clients traffic"
"resetAllClientTrafficContent" = "Are you sure to reset all traffics of all clients ?" "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" "Email" = "Email"
"EmailDesc" = "Please provide a unique email address" "EmailDesc" = "Please provide a unique email address"
"IPLimitlog" = "IP Log" "IPLimitlog" = "IP Log"

View file

@ -146,6 +146,9 @@
"resetAllClientTraffics" = "ریست ترافیک کاربران" "resetAllClientTraffics" = "ریست ترافیک کاربران"
"resetAllClientTrafficTitle" = "ریست ترافیک کل کاربران" "resetAllClientTrafficTitle" = "ریست ترافیک کل کاربران"
"resetAllClientTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک کاربران را ریست کنید؟" "resetAllClientTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک کاربران را ریست کنید؟"
"delDepletedClients" = "حذف کاربران منقضی"
"delDepletedClientsTitle" = "حذف کاربران منقضی"
"delDepletedClientsContent" = "آیا مطمئن هستید مه میخواهید تمامی کاربران منقضی شده را حذف کنید؟"
"IPLimit" = "محدودیت ای پی" "IPLimit" = "محدودیت ای پی"
"IPLimitDesc" = "غیرفعال کردن ورودی در صورت بیش از تعداد وارد شده (0 برای غیرفعال کردن محدودیت ای پی )" "IPLimitDesc" = "غیرفعال کردن ورودی در صورت بیش از تعداد وارد شده (0 برای غیرفعال کردن محدودیت ای پی )"
"Email" = "ایمیل" "Email" = "ایمیل"

View file

@ -146,6 +146,9 @@
"resetAllClientTraffics" = "重置所有客户端流量" "resetAllClientTraffics" = "重置所有客户端流量"
"resetAllClientTrafficTitle" = "重置所有客户端流量" "resetAllClientTrafficTitle" = "重置所有客户端流量"
"resetAllClientTrafficContent" = "你确定要重置所有客户端的所有流量吗?" "resetAllClientTrafficContent" = "你确定要重置所有客户端的所有流量吗?"
"delDepletedClients" = "删除耗尽的客户端"
"delDepletedClientsTitle" = "删除耗尽的客户"
"delDepletedClientsContent" = "你确定要删除所有耗尽的客户端吗?"
"IPLimit" = "IP限制" "IPLimit" = "IP限制"
"IPLimitDesc" = "如果超过输入的计数则禁用入站0 表示禁用限制 ip" "IPLimitDesc" = "如果超过输入的计数则禁用入站0 表示禁用限制 ip"
"Email" = "电子邮件" "Email" = "电子邮件"