summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven <soud@protonmail.com>2015-10-01 15:17:27 +0200
committerSteven <soud@protonmail.com>2015-10-01 15:51:46 +0200
commitc8aa9c6cb1ed79398b825c6110b5a6a7002d1a35 (patch)
tree3da97bdcac380cb5af2f43a063b8466b58f63313
parente0a099ec112e2746ec1f6dcd3276d19e14e50b06 (diff)
downloadgitea-c8aa9c6cb1ed79398b825c6110b5a6a7002d1a35.tar.gz
gitea-c8aa9c6cb1ed79398b825c6110b5a6a7002d1a35.zip
implemented #1721: see users who forked/starred/watched a repository
-rw-r--r--cmd/web.go3
-rw-r--r--models/repo.go30
-rw-r--r--public/ng/css/gogs.css88
-rw-r--r--public/ng/less/gogs/repository.less81
-rw-r--r--routers/repo/forks.go37
-rw-r--r--routers/repo/stars.go44
-rw-r--r--routers/repo/watchers.go44
-rw-r--r--templates/repo/forks.tmpl27
-rw-r--r--templates/repo/stars.tmpl61
-rw-r--r--templates/repo/watchers.tmpl61
10 files changed, 476 insertions, 0 deletions
diff --git a/cmd/web.go b/cmd/web.go
index e78cb13a37..126a86a35f 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -514,6 +514,9 @@ func runWeb(ctx *cli.Context) {
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
m.Get("/milestones", repo.Milestones)
m.Get("/branches", repo.Branches)
+ m.Get("/stars/?:index", middleware.RepoRef(), repo.Stars)
+ m.Get("/watchers/?:index", middleware.RepoRef(), repo.Watchers)
+ m.Get("/forks", middleware.RepoRef(), repo.Forks)
m.Get("/archive/*", repo.Download)
m.Group("/pulls/:index", func() {
diff --git a/models/repo.go b/models/repo.go
index f3a32d6877..fc155fa5f5 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -46,6 +46,9 @@ var (
var (
Gitignores, Licenses, Readmes []string
+
+ // Maximum items per page in forks, watchers and stars of a repo
+ ItemsPerPage = 3
)
func LoadRepoConfig() {
@@ -1612,6 +1615,16 @@ func GetWatchers(rid int64) ([]*Watch, error) {
return getWatchers(x, rid)
}
+// Repository.GetWatchers returns all users watching given repository.
+func (repo *Repository) GetWatchers(offset int) ([]*User, error) {
+ users := make([]*User, 0, 10)
+ offset = (offset - 1) * ItemsPerPage
+
+ err := x.Limit(ItemsPerPage, offset).Where("repo_id=?", repo.ID).Join("LEFT", "watch", "user.id=watch.user_id").Find(&users)
+
+ return users, err
+}
+
func notifyWatchers(e Engine, act *Action) error {
// Add feeds for user self and all watchers.
watches, err := getWatchers(e, act.RepoID)
@@ -1689,6 +1702,15 @@ func IsStaring(uid, repoId int64) bool {
return has
}
+func (repo *Repository) GetStars(offset int) ([]*User, error) {
+ users := make([]*User, 0, 10)
+ offset = (offset - 1) * ItemsPerPage
+
+ err := x.Limit(ItemsPerPage, offset).Where("repo_id=?", repo.ID).Join("LEFT", "star", "user.id=star.uid").Find(&users)
+
+ return users, err
+}
+
// ___________ __
// \_ _____/__________| | __
// | __)/ _ \_ __ \ |/ /
@@ -1756,3 +1778,11 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
return repo, sess.Commit()
}
+
+func (repo *Repository) GetForks() ([]*Repository, error) {
+ forks := make([]*Repository, 0, 10)
+
+ err := x.Find(&forks, &Repository{ForkID: repo.ID})
+
+ return forks, err
+}
diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css
index 73273d4f7e..caecfe2579 100644
--- a/public/ng/css/gogs.css
+++ b/public/ng/css/gogs.css
@@ -1947,6 +1947,94 @@ The register and sign-in page style
#release #release-new-form {
padding-top: 15px;
}
+#stars h4,
+#watchers h4,
+#forks h4 {
+ font-size: 18px;
+ padding-bottom: 20px;
+ text-transform: capitalize;
+ border-bottom: 1px solid #DDD;
+}
+#stars h3,
+#watchers h3,
+#forks h3 {
+ margin: -4px 0 0 0;
+ padding: 0;
+}
+#stars .avatar,
+#watchers .avatar,
+#forks .avatar {
+ width: 75px;
+ height: 75px;
+ float: left;
+ display: block;
+ margin-right: 10px;
+}
+#stars .avatar-small,
+#watchers .avatar-small,
+#forks .avatar-small {
+ width: 24px;
+ height: 24px;
+ float: left;
+ display: block;
+ margin-right: 10px;
+}
+#stars ol,
+#watchers ol,
+#forks ol {
+ margin-top: 10px;
+ list-style: none;
+ width: 100%;
+ overflow: hidden;
+}
+#stars li,
+#watchers li,
+#forks li {
+ width: 32.25%;
+ margin: 10px 10px 10px 0;
+ border-bottom: 1px solid #DDD;
+ float: left;
+ padding-bottom: 10px;
+}
+#stars .pagination,
+#watchers .pagination,
+#forks .pagination {
+ width: 100%;
+ text-align: center;
+ text-transform: capitalize;
+}
+#stars .pagination a,
+#watchers .pagination a,
+#forks .pagination a {
+ border-radius: 3px;
+ border: 1px solid #399ADE;
+ padding: 8px;
+ margin: 0;
+}
+#stars .pagination .active,
+#watchers .pagination .active,
+#forks .pagination .active {
+ border-radius: 3px;
+ border: 1px solid #399ADE;
+ background: #399ADE;
+ cursor: default;
+ padding: 8px;
+ margin: 0;
+ color: #FFFFFF;
+}
+#stars .pagination .disabled,
+#watchers .pagination .disabled,
+#forks .pagination .disabled {
+ border-radius: 3px;
+ border: 1px solid #DDD;
+ color: #D3D3D3;
+ cursor: default;
+ padding: 8px;
+ margin: 0;
+}
+#forks p {
+ padding: 5px 0;
+}
#admin-wrapper,
#setting-wrapper {
padding-bottom: 100px;
diff --git a/public/ng/less/gogs/repository.less b/public/ng/less/gogs/repository.less
index 6b0a927e8f..c403b51fec 100644
--- a/public/ng/less/gogs/repository.less
+++ b/public/ng/less/gogs/repository.less
@@ -795,3 +795,84 @@
padding-top: 15px;
}
}
+
+#stars, #watchers, #forks {
+ h4 {
+ font-size: 18px;
+ padding-bottom: 20px;
+ text-transform: capitalize;
+ border-bottom: 1px solid #DDD;
+ }
+
+ h3 {
+ margin: -4px 0 0 0;
+ padding: 0;
+ }
+
+ .avatar {
+ width: 75px;
+ height: 75px;
+ float: left;
+ display: block;
+ margin-right: 10px;
+ }
+
+ .avatar-small {
+ width: 24px;
+ height: 24px;
+ float: left;
+ display: block;
+ margin-right: 10px;
+ }
+
+ ol {
+ margin-top: 10px;
+ list-style: none;
+ width: 100%;
+ overflow: hidden;
+ }
+
+ li {
+ width: 32.25%;
+ margin: 10px 10px 10px 0;
+ border-bottom: 1px solid #DDD;
+ float: left;
+ padding-bottom: 10px;
+ }
+
+ .pagination {
+ width: 100%;
+ text-align: center;
+ text-transform: capitalize;
+
+ a {
+ border-radius: 3px;
+ border: 1px solid #399ADE;
+ padding: 8px;
+ margin: 0;
+ }
+
+ .active {
+ border-radius: 3px;
+ border: 1px solid #399ADE;
+ background: #399ADE;
+ cursor: default;
+ padding: 8px;
+ margin: 0;
+ color: #FFFFFF;
+ }
+
+ .disabled {
+ border-radius: 3px;
+ border: 1px solid #DDD;
+ color: #D3D3D3;
+ cursor: default;
+ padding: 8px;
+ margin: 0;
+ }
+ }
+}
+
+#forks p {
+ padding: 5px 0;
+}
diff --git a/routers/repo/forks.go b/routers/repo/forks.go
new file mode 100644
index 0000000000..099f0cc4f6
--- /dev/null
+++ b/routers/repo/forks.go
@@ -0,0 +1,37 @@
+// Copyright 2014 The Gogs 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 repo
+
+import (
+ "fmt"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+const (
+ FORKS base.TplName = "repo/forks"
+)
+
+func Forks(ctx *middleware.Context) {
+ ctx.Data["Title"] = ctx.Tr("repos.forks")
+
+ forks, err := ctx.Repo.Repository.GetForks()
+
+ if err != nil {
+ ctx.Handle(500, "GetForks", err)
+ return
+ }
+
+ for _, fork := range forks {
+ if err = fork.GetOwner(); err != nil {
+ ctx.Handle(500, "GetOwner", fmt.Errorf("%d: %v", fork.ID, err))
+ return
+ }
+ }
+
+ ctx.Data["Forks"] = forks
+
+ ctx.HTML(200, FORKS)
+}
diff --git a/routers/repo/stars.go b/routers/repo/stars.go
new file mode 100644
index 0000000000..ffccd1765b
--- /dev/null
+++ b/routers/repo/stars.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Gogs 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 repo
+
+import (
+ "github.com/Unknwon/paginater"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+const (
+ STARS base.TplName = "repo/stars"
+)
+
+func Stars(ctx *middleware.Context) {
+ ctx.Data["Title"] = ctx.Tr("repos.stars")
+
+ page := ctx.ParamsInt(":index")
+ if page <= 0 {
+ page = 1
+ }
+
+ ctx.Data["Page"] = paginater.New(ctx.Repo.Repository.NumStars, models.ItemsPerPage, page, 5)
+
+ stars, err := ctx.Repo.Repository.GetStars(ctx.ParamsInt(":index"))
+
+ if err != nil {
+ ctx.Handle(500, "GetStars", err)
+ return
+ }
+
+ if (ctx.ParamsInt(":index")-1)*models.ItemsPerPage > ctx.Repo.Repository.NumStars {
+ ctx.Handle(404, "ctx.Repo.Repository.NumStars", nil)
+ return
+ }
+
+ ctx.Data["Stars"] = stars
+
+ ctx.HTML(200, STARS)
+}
diff --git a/routers/repo/watchers.go b/routers/repo/watchers.go
new file mode 100644
index 0000000000..8765b18376
--- /dev/null
+++ b/routers/repo/watchers.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Gogs 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 repo
+
+import (
+ "github.com/Unknwon/paginater"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+const (
+ WATCHERS base.TplName = "repo/watchers"
+)
+
+func Watchers(ctx *middleware.Context) {
+ ctx.Data["Title"] = ctx.Tr("repos.watches")
+
+ page := ctx.ParamsInt(":index")
+ if page <= 0 {
+ page = 1
+ }
+
+ ctx.Data["Page"] = paginater.New(ctx.Repo.Repository.NumWatches, models.ItemsPerPage, page, 5)
+
+ watchers, err := ctx.Repo.Repository.GetWatchers(ctx.ParamsInt(":index"))
+
+ if err != nil {
+ ctx.Handle(500, "GetWatchers", err)
+ return
+ }
+
+ if (ctx.ParamsInt(":index")-1)*models.ItemsPerPage > ctx.Repo.Repository.NumWatches {
+ ctx.Handle(404, "ctx.Repo.Repository.NumWatches", nil)
+ return
+ }
+
+ ctx.Data["Watchers"] = watchers
+
+ ctx.HTML(200, WATCHERS)
+}
diff --git a/templates/repo/forks.tmpl b/templates/repo/forks.tmpl
new file mode 100644
index 0000000000..d1fd0320c0
--- /dev/null
+++ b/templates/repo/forks.tmpl
@@ -0,0 +1,27 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+<div id="repo-wrapper">
+ {{template "repo/header_old" .}}
+ <div id="repo-content" class="clear container">
+ <div id="repo-main" class="left grid-5-6">
+ <div id="forks">
+ <h4>
+ <strong>{{.i18n.Tr "repos.forks"}}</strong>
+ </h4>
+
+ <ol>
+ {{range .Forks}}
+ <p>
+ <img class="avatar-small" src="{{.Owner.AvatarLink}}">
+ <a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a>
+ /
+ <a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a>
+ </p>
+ {{end}}
+ </div>
+ </div>
+
+ {{template "repo/sidebar" .}}
+ </div>
+</div>
+{{template "ng/base/footer" .}}
diff --git a/templates/repo/stars.tmpl b/templates/repo/stars.tmpl
new file mode 100644
index 0000000000..afdb55d332
--- /dev/null
+++ b/templates/repo/stars.tmpl
@@ -0,0 +1,61 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+<div id="repo-wrapper">
+ {{template "repo/header_old" .}}
+ <div id="repo-content" class="clear container">
+ <div id="repo-main" class="left grid-5-6">
+ <div id="stars">
+ <h4>
+ <strong>{{.i18n.Tr "repos.stars"}}</strong>
+ </h4>
+
+ <ol>
+ {{range .Stars}}
+ <li>
+ <a href="{{AppSubUrl}}/{{.Name}}">
+ <img class="avatar" src="{{.AvatarLink}}" title="{{.Name}}"/>
+
+ <h3>{{.Name}}</h3>
+ </a>
+
+ <p>
+ {{if .Website}}
+ <span class="octicon octicon-link"></span> <a href="{{.Website}}" target="_blank">{{.Website}}</a>
+ {{else if .Location}}
+ <span class="octicon octicon-location"></span> {{.Location}}
+ {{else}}
+ <span class="octicon octicon-clock"></span> {{$.i18n.Tr "user.join_on"}} {{DateFmtShort .Created}}
+ {{end}}
+ </p>
+ </li>
+ {{end}}
+ </ol>
+
+ {{with .Page}}
+ {{if gt .TotalPages 1}}
+ <div class="pagination">
+ {{if .HasPrevious}}
+ <a href="{{$.RepoLink}}/stars/{{.Previous}}">{{$.i18n.Tr "issues.previous"}}</a>
+ {{end}}
+
+ {{range .Pages}}
+ {{if eq .Num -1}}
+ <a class="disabled item">...</a>
+ {{else}}
+ <a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.RepoLink}}/stars/{{.Num}}"{{end}}>{{.Num}}</a>
+ {{end}}
+ {{end}}
+
+ {{if .HasNext}}
+ <a href="{{$.RepoLink}}/stars/{{.Next}}">{{$.i18n.Tr "issues.next"}}</a>
+ {{end}}
+ </div>
+ {{end}}
+ {{end}}
+ </div>
+ </div>
+
+ {{template "repo/sidebar" .}}
+ </div>
+</div>
+{{template "ng/base/footer" .}}
diff --git a/templates/repo/watchers.tmpl b/templates/repo/watchers.tmpl
new file mode 100644
index 0000000000..3e5db820ca
--- /dev/null
+++ b/templates/repo/watchers.tmpl
@@ -0,0 +1,61 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+<div id="repo-wrapper">
+ {{template "repo/header_old" .}}
+ <div id="repo-content" class="clear container">
+ <div id="repo-main" class="left grid-5-6">
+ <div id="stars">
+ <h4>
+ <strong>{{.i18n.Tr "repos.watches"}}</strong>
+ </h4>
+
+ <ol>
+ {{range .Watchers}}
+ <li>
+ <a href="{{AppSubUrl}}/{{.Name}}">
+ <img class="avatar" src="{{.AvatarLink}}" title="{{.Name}}"/>
+
+ <h3>{{.Name}}</h3>
+ </a>
+
+ <p>
+ {{if .Website}}
+ <span class="octicon octicon-link"></span> <a href="{{.Website}}" target="_blank">{{.Website}}</a>
+ {{else if .Location}}
+ <span class="octicon octicon-location"></span> {{.Location}}
+ {{else}}
+ <span class="octicon octicon-clock"></span> {{$.i18n.Tr "user.join_on"}} {{DateFmtShort .Created}}
+ {{end}}
+ </p>
+ </li>
+ {{end}}
+ </ol>
+
+ {{with .Page}}
+ {{if gt .TotalPages 1}}
+ <div class="pagination">
+ {{if .HasPrevious}}
+ <a href="{{$.RepoLink}}/watchers/{{.Previous}}">{{$.i18n.Tr "issues.previous"}}</a>
+ {{end}}
+
+ {{range .Pages}}
+ {{if eq .Num -1}}
+ <a class="disabled item">...</a>
+ {{else}}
+ <a class="{{if .IsCurrent}}active{{end}} item" {{if not .IsCurrent}}href="{{$.RepoLink}}/watchers/{{.Num}}"{{end}}>{{.Num}}</a>
+ {{end}}
+ {{end}}
+
+ {{if .HasNext}}
+ <a href="{{$.RepoLink}}/watchers/{{.Next}}">{{$.i18n.Tr "issues.next"}}</a>
+ {{end}}
+ </div>
+ {{end}}
+ {{end}}
+ </div>
+ </div>
+
+ {{template "repo/sidebar" .}}
+ </div>
+</div>
+{{template "ng/base/footer" .}}