@@ -0,0 +1,4 @@ | |||
- | |||
id: 1 | |||
user_id: 4 | |||
follow_id: 2 |
@@ -26,6 +26,7 @@ | |||
avatar_email: user2@example.com | |||
num_repos: 2 | |||
num_stars: 2 | |||
num_followers: 1 | |||
- | |||
id: 3 | |||
@@ -56,6 +57,7 @@ | |||
avatar: avatar4 | |||
avatar_email: user4@example.com | |||
num_repos: 0 | |||
num_following: 1 | |||
- | |||
id: 5 | |||
@@ -72,6 +74,7 @@ | |||
num_repos: 1 | |||
allow_create_organization: false | |||
is_active: true | |||
num_following: 0 | |||
- | |||
id: 6 |
@@ -1292,78 +1292,6 @@ func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error) | |||
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 | |||
func GetStarredRepos(userID int64, private bool) ([]*Repository, error) { | |||
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{}) | |||
} |