| @@ -0,0 +1,4 @@ | |||||
| - | |||||
| id: 1 | |||||
| user_id: 4 | |||||
| follow_id: 2 | |||||
| @@ -26,6 +26,7 @@ | |||||
| avatar_email: user2@example.com | avatar_email: user2@example.com | ||||
| num_repos: 2 | num_repos: 2 | ||||
| num_stars: 2 | num_stars: 2 | ||||
| num_followers: 1 | |||||
| - | - | ||||
| id: 3 | id: 3 | ||||
| @@ -56,6 +57,7 @@ | |||||
| avatar: avatar4 | avatar: avatar4 | ||||
| avatar_email: user4@example.com | avatar_email: user4@example.com | ||||
| num_repos: 0 | num_repos: 0 | ||||
| num_following: 1 | |||||
| - | - | ||||
| id: 5 | id: 5 | ||||
| @@ -72,6 +74,7 @@ | |||||
| num_repos: 1 | num_repos: 1 | ||||
| allow_create_organization: false | allow_create_organization: false | ||||
| is_active: true | is_active: true | ||||
| num_following: 0 | |||||
| - | - | ||||
| id: 6 | id: 6 | ||||
| @@ -1292,78 +1292,6 @@ func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error) | |||||
| return users, count, sess.Find(&users) | return users, count, sess.Find(&users) | ||||
| } | } | ||||
| // ___________ .__ .__ | |||||
| // \_ _____/___ | | | | ______ _ __ | |||||
| // | __)/ _ \| | | | / _ \ \/ \/ / | |||||
| // | \( <_> ) |_| |_( <_> ) / | |||||
| // \___ / \____/|____/____/\____/ \/\_/ | |||||
| // \/ | |||||
| // 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)"` | |||||
| } | |||||
| // IsFollowing returns true if user is following followID. | |||||
| func IsFollowing(userID, followID int64) bool { | |||||
| has, _ := x.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 := x.NewSession() | |||||
| defer sessionRelease(sess) | |||||
| 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 := x.NewSession() | |||||
| defer sessionRelease(sess) | |||||
| 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() | |||||
| } | |||||
| // GetStarredRepos returns the repos starred by a particular user | // GetStarredRepos returns the repos starred by a particular user | ||||
| func GetStarredRepos(userID int64, private bool) ([]*Repository, error) { | func GetStarredRepos(userID int64, private bool) ([]*Repository, error) { | ||||
| sess := x.Where("star.uid=?", userID). | sess := x.Where("star.uid=?", userID). | ||||
| @@ -0,0 +1,71 @@ | |||||
| // 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 models | |||||
| // 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)"` | |||||
| } | |||||
| // IsFollowing returns true if user is following followID. | |||||
| func IsFollowing(userID, followID int64) bool { | |||||
| has, _ := x.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 := x.NewSession() | |||||
| defer sessionRelease(sess) | |||||
| 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 := x.NewSession() | |||||
| defer sessionRelease(sess) | |||||
| 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() | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| package models | |||||
| import ( | |||||
| "testing" | |||||
| "github.com/stretchr/testify/assert" | |||||
| ) | |||||
| func TestIsFollowing(t *testing.T) { | |||||
| assert.NoError(t, PrepareTestDatabase()) | |||||
| assert.True(t, IsFollowing(4, 2)) | |||||
| assert.False(t, IsFollowing(2, 4)) | |||||
| assert.False(t, IsFollowing(5, NonexistentID)) | |||||
| assert.False(t, IsFollowing(NonexistentID, 5)) | |||||
| assert.False(t, IsFollowing(NonexistentID, NonexistentID)) | |||||
| } | |||||
| func TestFollowUser(t *testing.T) { | |||||
| assert.NoError(t, PrepareTestDatabase()) | |||||
| testSuccess := func(followerID, followedID int64) { | |||||
| assert.NoError(t, FollowUser(followerID, followedID)) | |||||
| AssertExistsAndLoadBean(t, &Follow{UserID: followerID, FollowID: followedID}) | |||||
| } | |||||
| testSuccess(4, 2) | |||||
| testSuccess(5, 2) | |||||
| assert.NoError(t, FollowUser(2, 2)) | |||||
| CheckConsistencyFor(t, &User{}) | |||||
| } | |||||
| func TestUnfollowUser(t *testing.T) { | |||||
| assert.NoError(t, PrepareTestDatabase()) | |||||
| testSuccess := func(followerID, followedID int64) { | |||||
| assert.NoError(t, UnfollowUser(followerID, followedID)) | |||||
| AssertNotExistsBean(t, &Follow{UserID: followerID, FollowID: followedID}) | |||||
| } | |||||
| testSuccess(4, 2) | |||||
| testSuccess(5, 2) | |||||
| testSuccess(2, 2) | |||||
| CheckConsistencyFor(t, &User{}) | |||||
| } | |||||