diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index 904e88a1..a86c21e8 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -35,6 +35,8 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
g.POST("/delClient/:email", a.delInboundClient)
g.POST("/updateClient/:index", a.updateInboundClient)
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
+ g.POST("/resetAllTraffics", a.resetAllTraffics)
+ g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
}
@@ -208,3 +210,27 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
a.xrayService.SetToNeedRestart()
}
}
+
+func (a *InboundController) resetAllTraffics(c *gin.Context) {
+ err := a.inboundService.ResetAllTraffics()
+ if err != nil {
+ jsonMsg(c, "something worng!", err)
+ return
+ }
+ jsonMsg(c, "All traffics reseted", nil)
+}
+
+func (a *InboundController) resetAllClientTraffics(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.ResetAllClientTraffics(id)
+ if err != nil {
+ jsonMsg(c, "something worng!", err)
+ return
+ }
+ jsonMsg(c, "All traffics of client reseted", nil)
+}
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index 906c824b..05efb470 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -68,6 +68,7 @@
{{ i18n "pages.inbounds.addInbound" }}
{{ i18n "pages.inbounds.export" }}
+
{{ i18n "pages.inbounds.resetAllTraffic" }}
-
+
{{ i18n "pages.client.add"}}
-
+
{{ i18n "pages.client.bulk"}}
+
+
+ {{ i18n "pages.inbounds.resetAllClientTraffics"}}
+
{{ i18n "pages.inbounds.export"}}
@@ -111,6 +116,9 @@
{{ i18n "pages.inbounds.resetTraffic" }}
+
+ {{ i18n "pages.inbounds.Clone"}}
+
{{ i18n "delete"}}
@@ -399,6 +407,12 @@
case "resetTraffic":
this.resetTraffic(dbInbound.id);
break;
+ case "resetClients":
+ this.resetAllClientTraffics(dbInbound.id);
+ break;
+ case "clone":
+ this.openCloneInbound(dbInbound);
+ break;
case "delete":
this.delInbound(dbInbound.id);
break;
@@ -433,6 +447,39 @@
},
isEdit: true
});
+ },
+ openCloneInbound(dbInbound) {
+ this.$confirm({
+ title: '{{ i18n "pages.inbounds.cloneInbound"}} ' + dbInbound.remark,
+ content: '{{ i18n "pages.inbounds.cloneInboundContent"}}',
+ okText: '{{ i18n "pages.inbounds.revise"}}',
+ cancelText: '{{ i18n "cancel" }}',
+ onOk: () => {
+ const baseInbound = dbInbound.toInbound();
+ dbInbound.up = 0;
+ dbInbound.down = 0;
+ this.cloneInbound(baseInbound, dbInbound);
+ },
+ });
+ },
+ async cloneInbound(baseInbound, dbInbound) {
+ const inbound = new Inbound();
+ const data = {
+ up: dbInbound.up,
+ down: dbInbound.down,
+ total: dbInbound.total,
+ remark: dbInbound.remark + " - Cloned",
+ enable: dbInbound.enable,
+ expiryTime: dbInbound.expiryTime,
+
+ listen: inbound.listen,
+ port: inbound.port,
+ protocol: baseInbound.protocol,
+ settings: inbound.settings.toString(),
+ streamSettings: baseInbound.stream.toString(),
+ sniffing: baseInbound.canSniffing() ? baseInbound.sniffing.toString() : '{}',
+ };
+ await this.submit('/xui/inbound/add', data, inModal);
},
async addInbound(inbound, dbInbound) {
const data = {
@@ -634,6 +681,26 @@
onOk: () => this.submit('/xui/inbound/' + dbInboundId + '/resetClientTraffic/'+ client.email),
})
},
+ resetAllTraffic() {
+ this.$confirm({
+ title: '{{ i18n "pages.inbounds.resetAllTrafficTitle"}}',
+ content: '{{ i18n "pages.inbounds.resetAllTrafficContent"}}',
+ class: siderDrawer.isDarkTheme ? darkClass : '',
+ okText: '{{ i18n "reset"}}',
+ cancelText: '{{ i18n "cancel"}}',
+ onOk: () => this.submit('/xui/inbound/resetAllTraffics'),
+ });
+ },
+ resetAllClientTraffics(dbInboundId) {
+ this.$confirm({
+ title: '{{ i18n "pages.inbounds.resetAllClientTrafficTitle"}}',
+ content: '{{ i18n "pages.inbounds.resetAllClientTrafficContent"}}',
+ class: siderDrawer.isDarkTheme ? darkClass : '',
+ okText: '{{ i18n "reset"}}',
+ cancelText: '{{ i18n "cancel"}}',
+ onOk: () => this.submit('/xui/inbound/resetAllClientTraffics/' + dbInboundId),
+ })
+ },
isExpiry(dbInbound, index) {
return dbInbound.toInbound().isExpiry(index)
},
diff --git a/web/service/inbound.go b/web/service/inbound.go
index c48900f7..53a42cf4 100644
--- a/web/service/inbound.go
+++ b/web/service/inbound.go
@@ -534,6 +534,36 @@ func (s *InboundService) ResetClientTraffic(id int, clientEmail string) error {
}
return nil
}
+
+func (s *InboundService) ResetAllClientTraffics(id int) error {
+ db := database.GetDB()
+
+ result := db.Model(xray.ClientTraffic{}).
+ Where("inbound_id = ?", id).
+ Updates(map[string]interface{}{"enable": true, "up": 0, "down": 0})
+
+ err := result.Error
+
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (s *InboundService) ResetAllTraffics() error {
+ db := database.GetDB()
+
+ result := db.Model(model.Inbound{}).
+ Updates(map[string]interface{}{"up": 0, "down": 0})
+
+ err := result.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 1c829e75..0adf5440 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -131,7 +131,16 @@
"keyContent" = "Key content"
"clickOnQRcode" = "Click on QR Code to Copy"
"client" = "Client"
-"export" = "Export links"
+"export" = "Export Links"
+"Clone" = "Clone"
+"cloneInbound" = "Create"
+"cloneInboundContent" = "All items of this inbound except Port, Listening IP, Clients will be applied to the clone"
+"resetAllTraffic" = "Reset All Inbounds Traffic"
+"resetAllTrafficTitle" = "Reset all inbounds traffic"
+"resetAllTrafficContent" = "Are you sure to reset all inbounds traffic ?"
+"resetAllClientTraffics" = "Reset Clients Traffic"
+"resetAllClientTrafficTitle" = "Reset all clients traffic"
+"resetAllClientTrafficContent" = "Are you sure to reset all traffics of this inbound's clients ?"
[pages.client]
"add" = "Add client"
diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml
index 0499b980..0afb9bd3 100644
--- a/web/translation/translate.fa_IR.toml
+++ b/web/translation/translate.fa_IR.toml
@@ -132,6 +132,15 @@
"clickOnQRcode" = "برای کپی بر روی کد تصویری کلیک کنید"
"client" = "کاربر"
"export" = "استخراج لینکها"
+"Clone" = "کلون"
+"cloneInbound" = "ایجاد"
+"cloneInboundContent" = "همه موارد این سرویس بجز پورت ، ای پی و کلاینت ها روی کلون اعمال خواهند شد"
+"resetAllTraffic" = "ریست ترافیک کل سرویس ها"
+"resetAllTrafficTitle" = "ریست ترافیک کل سرویس ها"
+"resetAllTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک سرویس ها را ریست کنید؟"
+"resetAllClientTraffics" = "ریست ترافیک کاربران"
+"resetAllClientTrafficTitle" = "ریست ترافیک کل کاربران"
+"resetAllClientTrafficContent" = "آیا مطمئن هستید که میخواهید تمام ترافیک کاربران این سرویس را ریست کنید؟"
[pages.client]
"add" = "کاربر جدید"
diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml
index 3a771181..e15ea131 100644
--- a/web/translation/translate.zh_Hans.toml
+++ b/web/translation/translate.zh_Hans.toml
@@ -132,6 +132,15 @@
"clickOnQRcode" = "点击二维码复制"
"client" = "客户"
"export" = "导出链接"
+"Clone" = "克隆"
+"cloneInbound" = "创造"
+"cloneInboundContent" = "此入站的所有项目除 Port、Listening IP、Clients 将应用于克隆"
+"resetAllTraffic" = "重置所有入站流量"
+"resetAllTrafficTitle" = "重置所有入站流量"
+"resetAllTrafficContent" = "您确定要重置所有入站流量吗?"
+"resetAllClientTraffics" = "重置客户端流量"
+"resetAllClientTrafficTitle" = "重置所有客户端流量"
+"resetAllClientTrafficContent" = "您确定要重置此入站客户端的所有流量吗?"
[pages.client]
"add" = "添加客户端"