Skip to content

Commit 03af3b8

Browse files
move helper funcs
1 parent 2a49d34 commit 03af3b8

File tree

5 files changed

+118
-45
lines changed

5 files changed

+118
-45
lines changed

models/user/setting.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"code.gitea.io/gitea/modules/util"
1515

1616
"xorm.io/builder"
17+
"xorm.io/xorm"
1718
)
1819

1920
// Setting is a key value store of user settings
@@ -210,3 +211,17 @@ func upsertUserSettingValue(ctx context.Context, userID int64, key, value string
210211
return err
211212
})
212213
}
214+
215+
// BuildSignupIPQuery builds a query to find users by their signup IP addresses
216+
func BuildSignupIPQuery(ctx context.Context, keyword string) *xorm.Session {
217+
query := db.GetEngine(ctx).
218+
Table("user_setting").
219+
Join("INNER", "user", "user.id = user_setting.user_id").
220+
Where("user_setting.setting_key = ?", SignupIP)
221+
222+
if len(keyword) > 0 {
223+
query = query.And("(user.lower_name LIKE ? OR user.full_name LIKE ? OR user_setting.setting_value LIKE ?)",
224+
"%"+strings.ToLower(keyword)+"%", "%"+keyword+"%", "%"+keyword+"%")
225+
}
226+
return query
227+
}

modules/util/network.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package util
5+
6+
import (
7+
"strings"
8+
)
9+
10+
// TrimPortFromIP removes the client port from an IP address
11+
// Handles both IPv4 and IPv6 addresses with ports
12+
func TrimPortFromIP(ip string) string {
13+
// Handle IPv6 with brackets: [IPv6]:port
14+
if strings.HasPrefix(ip, "[") {
15+
// If there's no port, return as is
16+
if !strings.Contains(ip, "]:") {
17+
return ip
18+
}
19+
// Remove the port part after ]:
20+
return strings.Split(ip, "]:")[0] + "]"
21+
}
22+
23+
// Count colons to differentiate between IPv4 and IPv6
24+
colonCount := strings.Count(ip, ":")
25+
26+
// Handle IPv4 with port (single colon)
27+
if colonCount == 1 {
28+
return strings.Split(ip, ":")[0]
29+
}
30+
31+
return ip
32+
}

modules/util/network_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package util
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestTrimPortFromIP(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
input string
16+
expected string
17+
}{
18+
{
19+
name: "IPv4 without port",
20+
input: "192.168.1.1",
21+
expected: "192.168.1.1",
22+
},
23+
{
24+
name: "IPv4 with port",
25+
input: "192.168.1.1:8080",
26+
expected: "192.168.1.1",
27+
},
28+
{
29+
name: "IPv6 without port",
30+
input: "2001:db8::1",
31+
expected: "2001:db8::1",
32+
},
33+
{
34+
name: "IPv6 with brackets, without port",
35+
input: "[2001:db8::1]",
36+
expected: "[2001:db8::1]",
37+
},
38+
{
39+
name: "IPv6 with brackets and port",
40+
input: "[2001:db8::1]:8080",
41+
expected: "[2001:db8::1]",
42+
},
43+
{
44+
name: "localhost with port",
45+
input: "localhost:8080",
46+
expected: "localhost",
47+
},
48+
{
49+
name: "Empty string",
50+
input: "",
51+
expected: "",
52+
},
53+
{
54+
name: "Not an IP address",
55+
input: "abc123",
56+
expected: "abc123",
57+
},
58+
}
59+
60+
for _, tt := range tests {
61+
t.Run(tt.name, func(t *testing.T) {
62+
result := TrimPortFromIP(tt.input)
63+
assert.Equal(t, tt.expected, result)
64+
})
65+
}
66+
}

routers/web/admin/ips.go

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,18 @@ package admin
55

66
import (
77
"net/http"
8-
"strings"
98

10-
"code.gitea.io/gitea/models/db"
119
user_model "code.gitea.io/gitea/models/user"
1210
"code.gitea.io/gitea/modules/setting"
1311
"code.gitea.io/gitea/modules/templates"
12+
"code.gitea.io/gitea/modules/util"
1413
"code.gitea.io/gitea/services/context"
15-
16-
"xorm.io/xorm"
1714
)
1815

1916
const (
2017
tplIPs templates.TplName = "admin/ips/list"
2118
)
2219

23-
// trimPortFromIP removes the client port from an IP address
24-
// Handles both IPv4 and IPv6 addresses with ports
25-
func trimPortFromIP(ip string) string {
26-
// Handle IPv6 with brackets: [IPv6]:port
27-
if strings.HasPrefix(ip, "[") {
28-
// If there's no port, return as is
29-
if !strings.Contains(ip, "]:") {
30-
return ip
31-
}
32-
// Remove the port part after ]:
33-
return strings.Split(ip, "]:")[0] + "]"
34-
}
35-
36-
// Count colons to differentiate between IPv4 and IPv6
37-
colonCount := strings.Count(ip, ":")
38-
39-
// Handle IPv4 with port (single colon)
40-
if colonCount == 1 {
41-
return strings.Split(ip, ":")[0]
42-
}
43-
44-
return ip
45-
}
46-
47-
func buildIPQuery(ctx *context.Context, keyword string) *xorm.Session {
48-
query := db.GetEngine(ctx).
49-
Table("user_setting").
50-
Join("INNER", "user", "user.id = user_setting.user_id").
51-
Where("user_setting.setting_key = ?", user_model.SignupIP)
52-
53-
if len(keyword) > 0 {
54-
query = query.And("(user.lower_name LIKE ? OR user.full_name LIKE ? OR user_setting.setting_value LIKE ?)",
55-
"%"+strings.ToLower(keyword)+"%", "%"+keyword+"%", "%"+keyword+"%")
56-
}
57-
return query
58-
}
59-
6020
// IPs show all user signup IPs
6121
func IPs(ctx *context.Context) {
6222
ctx.Data["Title"] = ctx.Tr("admin.ips.ip")
@@ -107,15 +67,15 @@ func IPs(ctx *context.Context) {
10767
}
10868

10969
// Get the count and user IPs for pagination
110-
query := buildIPQuery(ctx, keyword)
70+
query := user_model.BuildSignupIPQuery(ctx, keyword)
11171

11272
count, err = query.Count(new(user_model.Setting))
11373
if err != nil {
11474
ctx.ServerError("Count", err)
11575
return
11676
}
11777

118-
err = buildIPQuery(ctx, keyword).
78+
err = user_model.BuildSignupIPQuery(ctx, keyword).
11979
Select("user.id as uid, user.name, user.full_name, user_setting.setting_value as ip").
12080
OrderBy(orderBy).
12181
Limit(setting.UI.Admin.UserPagingNum, (page-1)*setting.UI.Admin.UserPagingNum).
@@ -128,7 +88,7 @@ func IPs(ctx *context.Context) {
12888
for i := range userIPs {
12989
// Trim the port from the IP
13090
// FIXME: Maybe have a different helper for this?
131-
userIPs[i].IP = trimPortFromIP(userIPs[i].IP)
91+
userIPs[i].IP = util.TrimPortFromIP(userIPs[i].IP)
13292
}
13393

13494
ctx.Data["UserIPs"] = userIPs

routers/web/admin/users.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func ViewUser(ctx *context.Context) {
298298
signupIP, err := user_model.GetUserSetting(ctx, u.ID, user_model.SignupIP)
299299
if err == nil && len(signupIP) > 0 {
300300
ctx.Data["HasSignupIP"] = true
301-
ctx.Data["SignupIP"] = trimPortFromIP(signupIP)
301+
ctx.Data["SignupIP"] = util.TrimPortFromIP(signupIP)
302302
} else {
303303
ctx.Data["HasSignupIP"] = false
304304
}

0 commit comments

Comments
 (0)