* 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 linttags/v1.21.12.1
| @@ -273,7 +273,6 @@ func runWeb(ctx *cli.Context) error { | |||
| m.Get("", user.Profile) | |||
| m.Get("/followers", user.Followers) | |||
| m.Get("/following", user.Following) | |||
| m.Get("/stars", user.Stars) | |||
| }) | |||
| m.Get("/attachments/:uuid", func(ctx *context.Context) { | |||
| @@ -2146,66 +2146,6 @@ func NotifyWatchers(act *Action) error { | |||
| 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) | |||
| } | |||
| // ___________ __ | |||
| // \_ _____/__________| | __ | |||
| // | __)/ _ \_ __ \ |/ / | |||
| @@ -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 | |||
| settings = Settings | |||
| your_profile = Your Profile | |||
| your_starred = Your starred | |||
| your_settings = Your Settings | |||
| activities = Activities | |||
| @@ -95,6 +95,14 @@ func Profile(ctx *context.Context) { | |||
| if ctx.Written() { | |||
| 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: | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| @@ -138,11 +146,6 @@ func Following(ctx *context.Context) { | |||
| 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 | |||
| func Action(ctx *context.Context) { | |||
| u := GetUserByParams(ctx) | |||
| @@ -116,6 +116,10 @@ | |||
| <i class="octicon octicon-person"></i> | |||
| {{.i18n.Tr "your_profile"}}<!-- Your profile --> | |||
| </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"> | |||
| <i class="octicon octicon-settings"></i> | |||
| {{.i18n.Tr "your_settings"}}<!-- Your settings --> | |||
| @@ -75,23 +75,28 @@ | |||
| </div> | |||
| <div class="ui eleven wide column"> | |||
| <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"}} | |||
| </a> | |||
| <a class="item"> | |||
| <a class="{{if eq .TabName "activity"}}active{{end}} item" href="{{.Owner.HomeLink}}?tab=activity"> | |||
| <i class="octicon octicon-rss"></i> {{.i18n.Tr "user.activity"}} | |||
| </a> | |||
| <a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity"> | |||
| <i class="octicon octicon-rss"></i> {{.i18n.Tr "user.activity"}} | |||
| </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> | |||
| </div> | |||
| {{if ne .TabName "activity"}} | |||
| {{template "explore/repo_list" .}} | |||
| {{template "base/paginate" .}} | |||
| {{else}} | |||
| <br> | |||
| {{if eq .TabName "activity"}} | |||
| <div class="feeds"> | |||
| {{template "user/dashboard/feeds" .}} | |||
| </div> | |||
| {{else if eq .TabName "stars"}} | |||
| <div class="stars"> | |||
| {{template "explore/repo_list" .}} | |||
| </div> | |||
| {{else}} | |||
| {{template "explore/repo_list" .}} | |||
| {{template "base/paginate" .}} | |||
| {{end}} | |||
| </div> | |||
| </div> | |||