mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-21 23:02:41 +01:00
Tab on user profile to show starred repos (#519)
* Tab on user profile to show starred repos * Make golint happy and use transactions on StarRepo function * x -> sess * Use sess.Close() instead of sess.Rollback() * Add copyright * Fix lint
This commit is contained in:
parent
2d1a1fce93
commit
b992858883
7 changed files with 115 additions and 76 deletions
|
@ -273,7 +273,6 @@ func runWeb(ctx *cli.Context) error {
|
||||||
m.Get("", user.Profile)
|
m.Get("", user.Profile)
|
||||||
m.Get("/followers", user.Followers)
|
m.Get("/followers", user.Followers)
|
||||||
m.Get("/following", user.Following)
|
m.Get("/following", user.Following)
|
||||||
m.Get("/stars", user.Stars)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Get("/attachments/:uuid", func(ctx *context.Context) {
|
m.Get("/attachments/:uuid", func(ctx *context.Context) {
|
||||||
|
|
|
@ -2146,66 +2146,6 @@ func NotifyWatchers(act *Action) error {
|
||||||
return notifyWatchers(x, act)
|
return notifyWatchers(x, act)
|
||||||
}
|
}
|
||||||
|
|
||||||
// _________ __
|
|
||||||
// / _____// |______ _______
|
|
||||||
// \_____ \\ __\__ \\_ __ \
|
|
||||||
// / \| | / __ \| | \/
|
|
||||||
// /_______ /|__| (____ /__|
|
|
||||||
// \/ \/
|
|
||||||
|
|
||||||
// Star contains the star information
|
|
||||||
type Star struct {
|
|
||||||
ID int64 `xorm:"pk autoincr"`
|
|
||||||
UID int64 `xorm:"UNIQUE(s)"`
|
|
||||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// StarRepo star or unstar repository.
|
|
||||||
func StarRepo(userID, repoID int64, star bool) (err error) {
|
|
||||||
if star {
|
|
||||||
if IsStaring(userID, repoID) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, err = x.Insert(&Star{UID: userID, RepoID: repoID}); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", userID)
|
|
||||||
} else {
|
|
||||||
if !IsStaring(userID, repoID) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, err = x.Delete(&Star{0, userID, repoID}); err != nil {
|
|
||||||
return err
|
|
||||||
} else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = x.Exec("UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", userID)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsStaring checks if user has starred given repository.
|
|
||||||
func IsStaring(userID, repoID int64) bool {
|
|
||||||
has, _ := x.Get(&Star{0, userID, repoID})
|
|
||||||
return has
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStargazers returns the users who gave stars to this repository
|
|
||||||
func (repo *Repository) GetStargazers(page int) ([]*User, error) {
|
|
||||||
users := make([]*User, 0, ItemsPerPage)
|
|
||||||
sess := x.
|
|
||||||
Limit(ItemsPerPage, (page-1)*ItemsPerPage).
|
|
||||||
Where("star.repo_id=?", repo.ID)
|
|
||||||
if setting.UsePostgreSQL {
|
|
||||||
sess = sess.Join("LEFT", "star", `"user".id=star.uid`)
|
|
||||||
} else {
|
|
||||||
sess = sess.Join("LEFT", "star", "user.id=star.uid")
|
|
||||||
}
|
|
||||||
return users, sess.Find(&users)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________ __
|
// ___________ __
|
||||||
// \_ _____/__________| | __
|
// \_ _____/__________| | __
|
||||||
// | __)/ _ \_ __ \ |/ /
|
// | __)/ _ \_ __ \ |/ /
|
||||||
|
|
87
models/star.go
Normal file
87
models/star.go
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2016 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
|
||||||
|
|
||||||
|
// Star represents a starred repo by an user.
|
||||||
|
type Star struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
UID int64 `xorm:"UNIQUE(s)"`
|
||||||
|
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StarRepo or unstar repository.
|
||||||
|
func StarRepo(userID, repoID int64, star bool) error {
|
||||||
|
sess := x.NewSession()
|
||||||
|
|
||||||
|
defer sess.Close()
|
||||||
|
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if star {
|
||||||
|
if IsStaring(userID, repoID) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := sess.Insert(&Star{UID: userID, RepoID: repoID}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := sess.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := sess.Exec("UPDATE `user` SET num_stars = num_stars + 1 WHERE id = ?", userID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !IsStaring(userID, repoID) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := sess.Delete(&Star{0, userID, repoID}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := sess.Exec("UPDATE `repository` SET num_stars = num_stars - 1 WHERE id = ?", repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := sess.Exec("UPDATE `user` SET num_stars = num_stars - 1 WHERE id = ?", userID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStaring checks if user has starred given repository.
|
||||||
|
func IsStaring(userID, repoID int64) bool {
|
||||||
|
has, _ := x.Get(&Star{0, userID, repoID})
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStargazers returns the users that starred the repo.
|
||||||
|
func (repo *Repository) GetStargazers(page int) ([]*User, error) {
|
||||||
|
users := make([]*User, 0, ItemsPerPage)
|
||||||
|
err := x.
|
||||||
|
Limit(ItemsPerPage, (page-1)*ItemsPerPage).
|
||||||
|
Where("star.repo_id = ?", repo.ID).
|
||||||
|
Join("LEFT", "star", "`user`.id = star.uid").
|
||||||
|
Find(&users)
|
||||||
|
return users, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStarredRepos returns the repos the user starred.
|
||||||
|
func (u *User) GetStarredRepos(private bool) (repos []*Repository, err error) {
|
||||||
|
sess := x.
|
||||||
|
Join("INNER", "star", "star.repo_id = repository.id").
|
||||||
|
Where("star.uid = ?", u.ID)
|
||||||
|
|
||||||
|
if !private {
|
||||||
|
sess = sess.And("is_private = ?", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sess.
|
||||||
|
Find(&repos)
|
||||||
|
return
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ admin_panel = Admin Panel
|
||||||
account_settings = Account Settings
|
account_settings = Account Settings
|
||||||
settings = Settings
|
settings = Settings
|
||||||
your_profile = Your Profile
|
your_profile = Your Profile
|
||||||
|
your_starred = Your starred
|
||||||
your_settings = Your Settings
|
your_settings = Your Settings
|
||||||
|
|
||||||
activities = Activities
|
activities = Activities
|
||||||
|
|
|
@ -95,6 +95,14 @@ func Profile(ctx *context.Context) {
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case "stars":
|
||||||
|
showPrivateRepos := ctx.IsSigned && ctx.User.ID == ctxUser.ID
|
||||||
|
starredRepos, err := ctxUser.GetStarredRepos(showPrivateRepos)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetStarredRepos", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data["Repos"] = starredRepos
|
||||||
default:
|
default:
|
||||||
page := ctx.QueryInt("page")
|
page := ctx.QueryInt("page")
|
||||||
if page <= 0 {
|
if page <= 0 {
|
||||||
|
@ -138,11 +146,6 @@ func Following(ctx *context.Context) {
|
||||||
repo.RenderUserCards(ctx, u.NumFollowing, u.GetFollowing, tplFollowers)
|
repo.RenderUserCards(ctx, u.NumFollowing, u.GetFollowing, tplFollowers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stars show repositories user starred
|
|
||||||
func Stars(ctx *context.Context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Action response for follow/unfollow user request
|
// Action response for follow/unfollow user request
|
||||||
func Action(ctx *context.Context) {
|
func Action(ctx *context.Context) {
|
||||||
u := GetUserByParams(ctx)
|
u := GetUserByParams(ctx)
|
||||||
|
|
|
@ -116,6 +116,10 @@
|
||||||
<i class="octicon octicon-person"></i>
|
<i class="octicon octicon-person"></i>
|
||||||
{{.i18n.Tr "your_profile"}}<!-- Your profile -->
|
{{.i18n.Tr "your_profile"}}<!-- Your profile -->
|
||||||
</a>
|
</a>
|
||||||
|
<a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}?tab=stars">
|
||||||
|
<i class="octicon octicon-star"></i>
|
||||||
|
{{.i18n.Tr "your_starred"}}
|
||||||
|
</a>
|
||||||
<a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings">
|
<a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings">
|
||||||
<i class="octicon octicon-settings"></i>
|
<i class="octicon octicon-settings"></i>
|
||||||
{{.i18n.Tr "your_settings"}}<!-- Your settings -->
|
{{.i18n.Tr "your_settings"}}<!-- Your settings -->
|
||||||
|
|
|
@ -75,23 +75,28 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="ui eleven wide column">
|
<div class="ui eleven wide column">
|
||||||
<div class="ui secondary pointing menu">
|
<div class="ui secondary pointing menu">
|
||||||
<a class="{{if ne .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeLink}}">
|
<a class='{{if and (ne .TabName "activity") (ne .TabName "stars")}}active{{end}} item' href="{{.Owner.HomeLink}}">
|
||||||
<i class="octicon octicon-repo"></i> {{.i18n.Tr "user.repositories"}}
|
<i class="octicon octicon-repo"></i> {{.i18n.Tr "user.repositories"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="item">
|
<a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity">
|
||||||
<a class="{{if eq .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeLink}}?tab=activity">
|
<i class="octicon octicon-rss"></i> {{.i18n.Tr "user.activity"}}
|
||||||
<i class="octicon octicon-rss"></i> {{.i18n.Tr "user.activity"}}
|
</a>
|
||||||
</a>
|
<a class='{{if eq .TabName "stars"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=stars">
|
||||||
|
<i class="octicon octicon-star"></i> {{.i18n.Tr "user.starred"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{if ne .TabName "activity"}}
|
|
||||||
{{template "explore/repo_list" .}}
|
{{if eq .TabName "activity"}}
|
||||||
{{template "base/paginate" .}}
|
|
||||||
{{else}}
|
|
||||||
<br>
|
|
||||||
<div class="feeds">
|
<div class="feeds">
|
||||||
{{template "user/dashboard/feeds" .}}
|
{{template "user/dashboard/feeds" .}}
|
||||||
</div>
|
</div>
|
||||||
|
{{else if eq .TabName "stars"}}
|
||||||
|
<div class="stars">
|
||||||
|
{{template "explore/repo_list" .}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{template "explore/repo_list" .}}
|
||||||
|
{{template "base/paginate" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue