diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-11-17 17:58:31 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-17 17:58:31 +0800 |
commit | 95d3266bee797cbeb7228d361fe32531737906d2 (patch) | |
tree | 68d90e7ef3e890c1ac311cf79f08cbe12a0dafca /models/user | |
parent | adda27668b9764f97822e56e0591a6eb22165a83 (diff) | |
download | gitea-95d3266bee797cbeb7228d361fe32531737906d2.tar.gz gitea-95d3266bee797cbeb7228d361fe32531737906d2.zip |
Move user follow and openid into models/user/ (#17613)
* Move UserRedirect into models/user/
* Fix lint & test
* Fix lint
* Fix lint
* remove nolint comment
* Fix lint
* Move user follow and openid into models/user
* Ignore the lint
* Ignore the lint
* Fix test
* ignore stutters lint on UserOpenID
Diffstat (limited to 'models/user')
-rw-r--r-- | models/user/follow.go | 80 | ||||
-rw-r--r-- | models/user/follow_test.go | 22 | ||||
-rw-r--r-- | models/user/main_test.go | 2 | ||||
-rw-r--r-- | models/user/openid.go | 112 | ||||
-rw-r--r-- | models/user/openid_test.go | 63 |
5 files changed, 279 insertions, 0 deletions
diff --git a/models/user/follow.go b/models/user/follow.go new file mode 100644 index 0000000000..89675b5078 --- /dev/null +++ b/models/user/follow.go @@ -0,0 +1,80 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package user + +import ( + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/timeutil" +) + +// Follow represents relations of user and his/her followers. +type Follow struct { + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"UNIQUE(follow)"` + FollowID int64 `xorm:"UNIQUE(follow)"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` +} + +func init() { + db.RegisterModel(new(Follow)) +} + +// IsFollowing returns true if user is following followID. +func IsFollowing(userID, followID int64) bool { + has, _ := db.GetEngine(db.DefaultContext).Get(&Follow{UserID: userID, FollowID: followID}) + return has +} + +// FollowUser marks someone be another's follower. +func FollowUser(userID, followID int64) (err error) { + if userID == followID || IsFollowing(userID, followID) { + return nil + } + + sess := db.NewSession(db.DefaultContext) + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Insert(&Follow{UserID: userID, FollowID: followID}); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?", followID); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `user` SET num_following = num_following + 1 WHERE id = ?", userID); err != nil { + return err + } + return sess.Commit() +} + +// UnfollowUser unmarks someone as another's follower. +func UnfollowUser(userID, followID int64) (err error) { + if userID == followID || !IsFollowing(userID, followID) { + return nil + } + + sess := db.NewSession(db.DefaultContext) + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Delete(&Follow{UserID: userID, FollowID: followID}); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?", followID); err != nil { + return err + } + + if _, err = sess.Exec("UPDATE `user` SET num_following = num_following - 1 WHERE id = ?", userID); err != nil { + return err + } + return sess.Commit() +} diff --git a/models/user/follow_test.go b/models/user/follow_test.go new file mode 100644 index 0000000000..538c7b18a2 --- /dev/null +++ b/models/user/follow_test.go @@ -0,0 +1,22 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package user + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestIsFollowing(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + assert.True(t, IsFollowing(4, 2)) + assert.False(t, IsFollowing(2, 4)) + assert.False(t, IsFollowing(5, unittest.NonexistentID)) + assert.False(t, IsFollowing(unittest.NonexistentID, 5)) + assert.False(t, IsFollowing(unittest.NonexistentID, unittest.NonexistentID)) +} diff --git a/models/user/main_test.go b/models/user/main_test.go index 1dd9fb2781..7862556a03 100644 --- a/models/user/main_test.go +++ b/models/user/main_test.go @@ -15,5 +15,7 @@ func TestMain(m *testing.M) { unittest.MainTest(m, filepath.Join("..", ".."), "email_address.yml", "user_redirect.yml", + "follow.yml", + "user_open_id.yml", ) } diff --git a/models/user/openid.go b/models/user/openid.go new file mode 100644 index 0000000000..8ca3c7f2c8 --- /dev/null +++ b/models/user/openid.go @@ -0,0 +1,112 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package user + +import ( + "errors" + "fmt" + + "code.gitea.io/gitea/models/db" +) + +// ErrOpenIDNotExist openid is not known +var ErrOpenIDNotExist = errors.New("OpenID is unknown") + +// UserOpenID is the list of all OpenID identities of a user. +// Since this is a middle table, name it OpenID is not suitable, so we ignore the lint here +type UserOpenID struct { //revive:disable-line:exported + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"INDEX NOT NULL"` + URI string `xorm:"UNIQUE NOT NULL"` + Show bool `xorm:"DEFAULT false"` +} + +func init() { + db.RegisterModel(new(UserOpenID)) +} + +// GetUserOpenIDs returns all openid addresses that belongs to given user. +func GetUserOpenIDs(uid int64) ([]*UserOpenID, error) { + openids := make([]*UserOpenID, 0, 5) + if err := db.GetEngine(db.DefaultContext). + Where("uid=?", uid). + Asc("id"). + Find(&openids); err != nil { + return nil, err + } + + return openids, nil +} + +// isOpenIDUsed returns true if the openid has been used. +func isOpenIDUsed(e db.Engine, uri string) (bool, error) { + if len(uri) == 0 { + return true, nil + } + + return e.Get(&UserOpenID{URI: uri}) +} + +// ErrOpenIDAlreadyUsed represents a "OpenIDAlreadyUsed" kind of error. +type ErrOpenIDAlreadyUsed struct { + OpenID string +} + +// IsErrOpenIDAlreadyUsed checks if an error is a ErrOpenIDAlreadyUsed. +func IsErrOpenIDAlreadyUsed(err error) bool { + _, ok := err.(ErrOpenIDAlreadyUsed) + return ok +} + +func (err ErrOpenIDAlreadyUsed) Error() string { + return fmt.Sprintf("OpenID already in use [oid: %s]", err.OpenID) +} + +// NOTE: make sure openid.URI is normalized already +func addUserOpenID(e db.Engine, openid *UserOpenID) error { + used, err := isOpenIDUsed(e, openid.URI) + if err != nil { + return err + } else if used { + return ErrOpenIDAlreadyUsed{openid.URI} + } + + _, err = e.Insert(openid) + return err +} + +// AddUserOpenID adds an pre-verified/normalized OpenID URI to given user. +func AddUserOpenID(openid *UserOpenID) error { + return addUserOpenID(db.GetEngine(db.DefaultContext), openid) +} + +// DeleteUserOpenID deletes an openid address of given user. +func DeleteUserOpenID(openid *UserOpenID) (err error) { + var deleted int64 + // ask to check UID + address := UserOpenID{ + UID: openid.UID, + } + if openid.ID > 0 { + deleted, err = db.GetEngine(db.DefaultContext).ID(openid.ID).Delete(&address) + } else { + deleted, err = db.GetEngine(db.DefaultContext). + Where("openid=?", openid.URI). + Delete(&address) + } + + if err != nil { + return err + } else if deleted != 1 { + return ErrOpenIDNotExist + } + return nil +} + +// ToggleUserOpenIDVisibility toggles visibility of an openid address of given user. +func ToggleUserOpenIDVisibility(id int64) (err error) { + _, err = db.GetEngine(db.DefaultContext).Exec("update `user_open_id` set `show` = not `show` where `id` = ?", id) + return err +} diff --git a/models/user/openid_test.go b/models/user/openid_test.go new file mode 100644 index 0000000000..ba678ef864 --- /dev/null +++ b/models/user/openid_test.go @@ -0,0 +1,63 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package user + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestGetUserOpenIDs(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + oids, err := GetUserOpenIDs(int64(1)) + if assert.NoError(t, err) && assert.Len(t, oids, 2) { + assert.Equal(t, "https://user1.domain1.tld/", oids[0].URI) + assert.False(t, oids[0].Show) + assert.Equal(t, "http://user1.domain2.tld/", oids[1].URI) + assert.True(t, oids[1].Show) + } + + oids, err = GetUserOpenIDs(int64(2)) + if assert.NoError(t, err) && assert.Len(t, oids, 1) { + assert.Equal(t, "https://domain1.tld/user2/", oids[0].URI) + assert.True(t, oids[0].Show) + } +} + +func TestToggleUserOpenIDVisibility(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + oids, err := GetUserOpenIDs(int64(2)) + if !assert.NoError(t, err) || !assert.Len(t, oids, 1) { + return + } + assert.True(t, oids[0].Show) + + err = ToggleUserOpenIDVisibility(oids[0].ID) + if !assert.NoError(t, err) { + return + } + + oids, err = GetUserOpenIDs(int64(2)) + if !assert.NoError(t, err) || !assert.Len(t, oids, 1) { + return + } + assert.False(t, oids[0].Show) + err = ToggleUserOpenIDVisibility(oids[0].ID) + if !assert.NoError(t, err) { + return + } + + oids, err = GetUserOpenIDs(int64(2)) + if !assert.NoError(t, err) { + return + } + if assert.Len(t, oids, 1) { + assert.True(t, oids[0].Show) + } +} |