Browse Source

Show user OpenID URIs in their profile (#1314)

Sandro Santilli 2 years ago
parent
commit
9182a35f18

+ 1 - 0
cmd/web.go

@@ -248,6 +248,7 @@ func runWeb(ctx *cli.Context) error {
248 248
 				m.Combo("").Get(user.SettingsOpenID).
249 249
 					Post(bindIgnErr(auth.AddOpenIDForm{}), user.SettingsOpenIDPost)
250 250
 				m.Post("/delete", user.DeleteOpenID)
251
+				m.Post("/toggle_visibility", user.ToggleOpenIDVisibility)
251 252
 			})
252 253
 		}
253 254
 

+ 17 - 0
models/fixtures/user_open_id.yml

@@ -0,0 +1,17 @@
1
+-
2
+  id: 1
3
+  uid: 1
4
+  uri: https://user1.domain1.tld/
5
+  show: false
6
+
7
+-
8
+  id: 2
9
+  uid: 1
10
+  uri: http://user1.domain2.tld/
11
+  show: true
12
+
13
+-
14
+  id: 3
15
+  uid: 2
16
+  uri: https://domain1.tld/user2/
17
+  show: true

+ 2 - 0
models/migrations/migrations.go

@@ -98,6 +98,8 @@ var migrations = []Migration{
98 98
 	NewMigration("add user openid table", addUserOpenID),
99 99
 	// v24 -> v25
100 100
 	NewMigration("change the key_id and primary_key_id type", changeGPGKeysColumns),
101
+	// v25 -> v26
102
+	NewMigration("add show field in user openid table", addUserOpenIDShow),
101 103
 }
102 104
 
103 105
 // Migrate database to current version

+ 18 - 0
models/migrations/v25.go

@@ -0,0 +1,18 @@
1
+// Copyright 2017 Gitea. All rights reserved.
2
+// Use of this source code is governed by a MIT-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package migrations
6
+
7
+import (
8
+	"fmt"
9
+
10
+	"github.com/go-xorm/xorm"
11
+)
12
+
13
+func addUserOpenIDShow(x *xorm.Engine) error {
14
+	if err := x.Sync2(new(UserOpenID)); err != nil {
15
+		return fmt.Errorf("Sync2: %v", err)
16
+	}
17
+	return nil
18
+}

+ 8 - 0
models/user_openid.go

@@ -21,6 +21,7 @@ type UserOpenID struct {
21 21
 	ID          int64  `xorm:"pk autoincr"`
22 22
 	UID         int64  `xorm:"INDEX NOT NULL"`
23 23
 	URI         string `xorm:"UNIQUE NOT NULL"`
24
+	Show        bool   `xorm:"DEFAULT false"`
24 25
 }
25 26
 
26 27
 // GetUserOpenIDs returns all openid addresses that belongs to given user.
@@ -28,6 +29,7 @@ func GetUserOpenIDs(uid int64) ([]*UserOpenID, error) {
28 29
 	openids := make([]*UserOpenID, 0, 5)
29 30
 	if err := x.
30 31
 		Where("uid=?", uid).
32
+		Asc("id").
31 33
 		Find(&openids); err != nil {
32 34
 		return nil, err
33 35
 	}
@@ -89,6 +91,12 @@ func DeleteUserOpenID(openid *UserOpenID) (err error) {
89 91
 	return nil
90 92
 }
91 93
 
94
+// ToggleUserOpenIDVisibility toggles visibility of an openid address of given user.
95
+func ToggleUserOpenIDVisibility(id int64) (err error) {
96
+	_, err = x.Exec("update user_open_id set show = not show where id = ?", id)
97
+	return err
98
+}
99
+
92 100
 // GetUserByOpenID returns the user object by given OpenID if exists.
93 101
 func GetUserByOpenID(uri string) (*User, error) {
94 102
 	if len(uri) == 0 {

+ 82 - 0
models/user_openid_test.go

@@ -0,0 +1,82 @@
1
+// Copyright 2017 The Gitea Authors. All rights reserved.
2
+// Use of this source code is governed by a MIT-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package models
6
+
7
+import (
8
+	"testing"
9
+
10
+	"github.com/stretchr/testify/assert"
11
+)
12
+
13
+func TestGetUserOpenIDs(t *testing.T) {
14
+	assert.NoError(t, PrepareTestDatabase())
15
+
16
+	oids, err := GetUserOpenIDs(int64(1))
17
+	if assert.NoError(t, err) {
18
+		assert.Len(t, oids, 2)
19
+		assert.Equal(t, oids[0].URI, "https://user1.domain1.tld/")
20
+		assert.False(t, oids[0].Show)
21
+		assert.Equal(t, oids[1].URI, "http://user1.domain2.tld/")
22
+		assert.True(t, oids[1].Show)
23
+	}
24
+
25
+	oids, err = GetUserOpenIDs(int64(2))
26
+	if assert.NoError(t, err) {
27
+		assert.Len(t, oids, 1)
28
+		assert.Equal(t, oids[0].URI, "https://domain1.tld/user2/")
29
+		assert.True(t, oids[0].Show)
30
+	}
31
+}
32
+
33
+func TestGetUserByOpenID(t *testing.T) {
34
+	assert.NoError(t, PrepareTestDatabase())
35
+
36
+	user, err := GetUserByOpenID("https://unknown")
37
+	if assert.Error(t, err) {
38
+		assert.True(t, IsErrUserNotExist(err))
39
+	}
40
+
41
+	user, err = GetUserByOpenID("https://user1.domain1.tld")
42
+	if assert.NoError(t, err) {
43
+		assert.Equal(t, user.ID, int64(1))
44
+	}
45
+
46
+	user, err = GetUserByOpenID("https://domain1.tld/user2/")
47
+	if assert.NoError(t, err) {
48
+		assert.Equal(t, user.ID, int64(2))
49
+	}
50
+}
51
+
52
+func TestToggleUserOpenIDVisibility(t *testing.T) {
53
+	assert.NoError(t, PrepareTestDatabase())
54
+	oids, err := GetUserOpenIDs(int64(2))
55
+	if ! assert.NoError(t, err) {
56
+		return
57
+	}
58
+	assert.Len(t, oids, 1)
59
+	assert.True(t, oids[0].Show)
60
+
61
+	err = ToggleUserOpenIDVisibility(oids[0].ID)
62
+	if ! assert.NoError(t, err) {
63
+		return
64
+	}
65
+
66
+	oids, err = GetUserOpenIDs(int64(2))
67
+	if assert.NoError(t, err) {
68
+		assert.Len(t, oids, 1)
69
+		assert.False(t, oids[0].Show)
70
+	}
71
+	err = ToggleUserOpenIDVisibility(oids[0].ID)
72
+	if ! assert.NoError(t, err) {
73
+		return
74
+	}
75
+
76
+	oids, err = GetUserOpenIDs(int64(2))
77
+	if ! assert.NoError(t, err) {
78
+		return
79
+	}
80
+	assert.Len(t, oids, 1)
81
+	assert.True(t, oids[0].Show)
82
+}

+ 2 - 0
options/locale/locale_en-US.ini

@@ -365,6 +365,8 @@ last_used = Last used on
365 365
 no_activity = No recent activity
366 366
 key_state_desc = This key is used in last 7 days
367 367
 token_state_desc = This token is used in last 7 days
368
+show_openid = Show on profile
369
+hide_openid = Hide from profile
368 370
 
369 371
 manage_social = Manage Associated Social Accounts
370 372
 social_desc = This is a list of associated social accounts. For security reasons, please make sure you recognize all of these entries, as they can be used to log in to your account.

+ 8 - 0
routers/user/profile.go

@@ -75,9 +75,17 @@ func Profile(ctx *context.Context) {
75 75
 		return
76 76
 	}
77 77
 
78
+	// Show OpenID URIs
79
+	openIDs, err := models.GetUserOpenIDs(ctxUser.ID)
80
+	if err != nil {
81
+		ctx.Handle(500, "GetUserOpenIDs", err)
82
+		return
83
+	}
84
+
78 85
 	ctx.Data["Title"] = ctxUser.DisplayName()
79 86
 	ctx.Data["PageIsUserProfile"] = true
80 87
 	ctx.Data["Owner"] = ctxUser
88
+	ctx.Data["OpenIDs"] = openIDs
81 89
 	showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
82 90
 
83 91
 	orgs, err := models.GetOrgsByUserID(ctxUser.ID, showPrivate)

+ 16 - 0
routers/user/setting_openid.go

@@ -45,6 +45,12 @@ func SettingsOpenIDPost(ctx *context.Context, form auth.AddOpenIDForm) {
45 45
 	ctx.Data["PageIsSettingsOpenID"] = true
46 46
 
47 47
 	if ctx.HasError() {
48
+		openid, err := models.GetUserOpenIDs(ctx.User.ID)
49
+		if err != nil {
50
+			ctx.Handle(500, "GetUserOpenIDs", err)
51
+			return
52
+		}
53
+		ctx.Data["OpenIDs"] = openid
48 54
 		ctx.HTML(200, tplSettingsOpenID)
49 55
 		return
50 56
 	}
@@ -140,3 +146,13 @@ func DeleteOpenID(ctx *context.Context) {
140 146
 	})
141 147
 }
142 148
 
149
+// ToggleOpenIDVisibility response for toggle visibility of user's openid
150
+func ToggleOpenIDVisibility(ctx *context.Context) {
151
+	if err := models.ToggleUserOpenIDVisibility(ctx.QueryInt64("id")); err != nil {
152
+		ctx.Handle(500, "ToggleUserOpenIDVisibility", err)
153
+		return
154
+	}
155
+
156
+	ctx.Redirect(setting.AppSubURL + "/user/settings/openid")
157
+}
158
+

+ 8 - 0
templates/user/profile.tmpl

@@ -34,6 +34,14 @@
34 34
 									<a target="_blank" rel="noopener" href="{{.Owner.Website}}">{{.Owner.Website}}</a>
35 35
 								</li>
36 36
 							{{end}}
37
+							{{range .OpenIDs}}
38
+								{{if .Show}}
39
+									<li>
40
+										<i class="fa fa-openid"></i>
41
+										<a target="_blank" rel="noopener" href="{{.URI}}">{{.URI}}</a>
42
+									</li>
43
+								{{end}}
44
+							{{end}}
37 45
 							<li><i class="octicon octicon-clock"></i> {{.i18n.Tr "user.join_on"}} {{DateFmtShort .Owner.Created}}</li>
38 46
 							<li>
39 47
 								<i class="octicon octicon-person"></i>

+ 18 - 0
templates/user/settings/openid.tmpl

@@ -20,6 +20,24 @@
20 20
 									{{$.i18n.Tr "settings.delete_key"}}
21 21
 								</button>
22 22
 							</div>
23
+							<div class="ui right">
24
+								<form action="{{$.Link}}/toggle_visibility" method="post">
25
+								{{$.CsrfTokenHtml}}
26
+								<input name="id" type="hidden" value="{{.ID}}">
27
+								{{if .Show}}
28
+									<button class="ui tiny button">
29
+									<i class="icon fa-eye"></i>
30
+									{{$.i18n.Tr "settings.hide_openid"}}
31
+									</button>
32
+								{{else}}
33
+									<button class="ui tiny button">
34
+									<i class="icon fa-eye-slash"></i>
35
+									{{$.i18n.Tr "settings.show_openid"}}
36
+									</button>
37
+								{{end}}
38
+								</button>
39
+								</form>
40
+							</div>
23 41
 						</div>
24 42
 					</div>
25 43
 				{{end}}