Skip to content

Commit

Permalink
Merge pull request go-gitea#104 from phillip-hopper/feature/GogsIssue85
Browse files Browse the repository at this point in the history
Issue 85: Make a page to list all tags
  • Loading branch information
richmahn authored Dec 6, 2016
2 parents d8c2ef7 + 6e32dc3 commit 85e3b4c
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ _test

# IntelliJ
.idea
*.iml

# Architecture specific extensions/prefixes
*.[568vq]
Expand Down
14 changes: 14 additions & 0 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,20 @@ func runWeb(ctx *cli.Context) error {
Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
}, reqSignIn)

// Check for hashtag requests in UBN repositories.
// => repo name must contain `-ubn-` or end with `-ubn`.
m.Group("/:username/:reponame(.+-ubn-.+|.+-ubn$)", func() {
m.Get("/hashtags", repo.Hashtags)
m.Get("/hashtags/:hashtag", repo.HashtagDisambiguation)
}, ignSignIn, context.RepoAssignment(), context.RepoRef())

// Redirect hashtag requests for ineligible repositories
m.Group("/:username/:reponame", func() {
m.Get("/hashtags/*.*", func(ctx *macaron.Context) {
ctx.Redirect(setting.AppSubUrl + "/" + ctx.Params(":username")+ "/" + ctx.Params(":reponame"), 301)
})
}, ignSignIn)

m.Group("/:username/:reponame", func() {
m.Group("/settings", func() {
m.Combo("").Get(repo.Settings).
Expand Down
36 changes: 35 additions & 1 deletion models/hashtag.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ package models

import (
"time"
"github.com/go-xorm/xorm"
)

// Webhook represents a web hook object.
// Hashtag represents a hashtag object.
type Hashtag struct {
ID int64 `xorm:"pk autoincr"`
UserID int64
Expand All @@ -20,6 +21,39 @@ type Hashtag struct {
UpdatedUnix int64
}

// GetHashtagSummary gets a summary of the hashtags for repositories with the specified prefix.
func GetHashtagSummary(repoPrefix string) ([]map[string]string, error) {
return getHashtagSummary(x, repoPrefix)
}

func getHashtagSummary(engine *xorm.Engine, repoPrefix string) ([]map[string]string, error) {

sql := `SELECT h.tag_name, COUNT(*) AS count_of_occurrences
FROM repository AS r INNER JOIN hashtag AS h ON r.id = h.repo_id
WHERE r.name LIKE ?
GROUP BY h.tag_name
ORDER BY LOWER(h.tag_name)`

// get the requested list of tags
results, err := engine.Query(sql, repoPrefix + "%")

if err != nil {
return nil, err
}

// convert the byte arrays returned by the Query function into regular strings
returnVal := make([]map[string]string, len(results))
for idx, row := range results {
values := make(map[string]string)
for key, value := range row {
values[key] = string(value)
}
returnVal[idx] = values
}

return returnVal, nil
}

func (h *Hashtag) BeforeInsert() {
h.CreatedUnix = time.Now().Unix()
h.UpdatedUnix = h.CreatedUnix
Expand Down
100 changes: 100 additions & 0 deletions models/hashtag_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package models

import (
"testing"
. "github.com/smartystreets/goconvey/convey"
_ "github.com/mattn/go-sqlite3"
"github.com/go-xorm/xorm"
"io/ioutil"
"os"
"path"
"fmt"
"github.com/go-xorm/core"
)

func TestHashtag(t *testing.T) {

userSql := `INSERT INTO user (id, lower_name, name, full_name, email, passwd, login_type, login_source, login_name, type, location, website, rands, salt, created_unix, updated_unix, last_login_unix, last_repo_visibility, max_repo_creation, is_active, is_admin, allow_git_hook, allow_import_local, prohibit_login, avatar, avatar_email, use_custom_avatar, num_followers, num_following, num_stars, num_repos, description, num_teams, num_members, diff_view_style)
VALUES ('1', 'phil', 'phil', '', 'phillip_hopper@wycliffeassociates.org', 'c024408767b2b15755e65c6799154c38ea9975c4a0d4642f47981c7169e76ca6cc507b4b8587efa2e656e0afd65017951bbd', '0', '0', '', '0', '', '', 'nekqlODpS1', 'fjsVRQvR0M', '1479588664', '1480428210', '1480428191', 'false', '-1', 'true', 'true', 'false', 'false', 'false', 'c1f199e0525420aceca0859cd4c9f990', 'phillip_hopper@wycliffeassociates.org', 'false', '0', '0', '0', '1', '', '0', '0', '')`

repoSql := `INSERT INTO repository (id, owner_id, lower_name, name, description, website, default_branch, num_watches, num_stars, num_forks, num_issues, num_closed_issues, num_pulls, num_closed_pulls, num_milestones, num_closed_milestones, is_private, is_bare, is_mirror, enable_wiki, enable_external_wiki, external_wiki_url, enable_issues, enable_external_tracker, external_tracker_url, external_tracker_format, external_tracker_style, enable_pulls, is_fork, fork_id, created_unix, updated_unix)
VALUES ('1', '1', 'en-ubn-tags', 'en-ubn-tags', '', '', 'master', '1', '0', '0', '0', '0', '0', '0', '0', '0', 'false', 'false', 'false', 'true', 'false', '', 'true', 'false', '', '', 'numeric', 'true', 'false', '0', '1479589835', '1479731504'),
('2', '1', 'en-ubn', 'en-ubn', '', '', 'master', '1', '0', '0', '0', '0', '0', '0', '0', '0', 'false', 'false', 'false', 'true', 'false', '', 'true', 'false', '', '', 'numeric', 'true', 'false', '0', '1480426137', '1480426138'),
('3', '1', 'en-tw', 'en-tw', '', '', 'master', '1', '0', '0', '0', '0', '0', '0', '0', '0', 'false', 'false', 'false', 'true', 'false', '', 'true', 'false', '', '', 'numeric', 'true', 'false', '0', '1480426161', '1480426161'),
('4', '1', 'en-ubnn', 'en-ubnn', '', '', 'master', '1', '0', '0', '0', '0', '0', '0', '0', '0', 'false', 'false', 'false', 'true', 'false', '', 'true', 'false', '', '', 'numeric', 'true', 'false', '0', '1480426633', '1480426633'),
('5', '1', 'en-ub-test', 'en-ub-test', '', '', 'master', '1', '0', '0', '0', '0', '0', '0', '0', '0', 'false', 'false', 'false', 'true', 'false', '', 'true', 'false', '', '', 'numeric', 'true', 'false', '0', '1480428210', '1480428210')`

hashtagSql := `INSERT INTO hashtag (id, user_id, repo_id, lang, tag_name, file_path, created_unix, updated_unix)
VALUES ('1','1','1','en','amill','article1.md','1480336882','1480336882'),
('2','1','2','en','amill','article2.md','1480336882','1480336882'),
('3','1','2','en','amill','article3.md','1480336882','1480336882'),
('4','1','1','en','salv','article1.md','1480336882','1480336882'),
('5','1','2','en','salv','article3.md','1480336882','1480336882'),
('6','1','2','en','m-asiaminor','article2.md','1480336882','1480336882'),
('7','1','2','en','m-endofearth','article3.md','1480336882','1480336882'),
('8','1','1','en','m-galilee','article1.md','1480336882','1480336882'),
('9','1','2','en','m-greece','article3.md','1480336882','1480336882'),
('10','1','2','en','xq-gen12:3','article2.md','1480336882','1480336882'),
('11','1','2','en','xa-isa40:3','article3.md','1480336882','1480336882'),
('12','1','1','en','xa-jer12:1','article1.md','1480336882','1480336882'),
('13','1','2','en','A1933','article3.md','1480336882','1480336882'),
('14','1','2','en','G58','article3.md','1480336882','1480336882'),
('15','1','2','en','H305','article3.md','1480336882','1480336882'),
('16','1','2','en','da-hsbaptism','article2.md','1480336882','1480336882'),
('17','1','2','en','da-kingdomofgod','article3.md','1480336882','1480336882'),
('18','1','1','en','da-modeofbaptism','article1.md','1480336882','1480336882'),
('19','1','2','en','da-ntuseofot','article3.md','1480336882','1480336882'),
('20','1','2','en','da-spiritualgifts','article3.md','1480336882','1480336882'),
('21','1','2','en','da-waterbaptism','article3.md','1480336882','1480336882'),
('22','1','2','en','dg-brother','article2.md','1480336882','1480336882'),
('23','1','2','en','dg-pentecost','article3.md','1480336882','1480336882'),
('24','1','1','en','bapt','article1.md','1480336882','1480336882'),
('25','1','2','en','episangl','article3.md','1480336882','1480336882'),
('26','1','2','en','jew','article3.md','1480336882','1480336882'),
('27','1','2','en','luth','article3.md','1480336882','1480336882')`

statements := []string{userSql, repoSql, hashtagSql}

// **** setting up the testing sqlite database ****
var testEngine *xorm.Engine

// 1. create temp directory
tempDir, err := ioutil.TempDir(os.TempDir(), "_hashtag_test_")
if err != nil {
print(fmt.Sprintf("Temp dir error: %v", err))
}
dbFile := path.Join(tempDir, "hashtag_test.sql")
os.MkdirAll(path.Dir(dbFile), os.ModePerm)

// 2. start the engine
testEngine, err2 := xorm.NewEngine("sqlite3", dbFile)
if err2 != nil {
print(fmt.Sprintf("Engine error: %v", err2) + "\n")
}
testEngine.SetMapper(core.GonicMapper{})
testEngine.StoreEngine("InnoDB").Sync2(tables...)

// 3. insert test data
for _, sql := range statements {
_, err = testEngine.Exec(sql)
if err != nil {
print(fmt.Sprintf("Temp dir error: %v", err))
}
}

// **** remove the temp directory when the class is disposed ****
defer os.RemoveAll(tempDir)

Convey("Test Hashtag.GetHashtagSummary()", t, func() {
results, err := getHashtagSummary(testEngine, "en-ubn")
So(err, ShouldBeNil)

//print("Hashtags found: " + strconv.Itoa(len(results)) + "\n")
So(len(results), ShouldEqual, 24)

for _, hashtag := range results {
//print(fmt.Sprintf("%v: %v", hashtag["tag_name"], hashtag["count_of_occurrences"]) + "\n")
So(hashtag["tag_name"], ShouldNotBeEmpty)
}
})
}
2 changes: 2 additions & 0 deletions modules/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
"net/url"
)

func NewFuncMap() []template.FuncMap {
Expand Down Expand Up @@ -99,6 +100,7 @@ func NewFuncMap() []template.FuncMap {
"EscapePound": func(str string) string {
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
},
"QueryEscape": url.QueryEscape,
"RenderCommitMessage": RenderCommitMessage,
"ThemeColorMetaTag": func() string {
return setting.UI.ThemeColorMetaTag
Expand Down
49 changes: 49 additions & 0 deletions routers/repo/hashtag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package repo

import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/base"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"net/http"
)

const (
HASHTAGS base.TplName = "repo/hashtag/list"
)

// Hashtags produces a page listing all hashtags for this language, with counts
func Hashtags(ctx *context.Context) {

// get the LANG-ubn repository name prefix
var repo_prefix string
if strings.HasSuffix(ctx.Repo.Repository.Name, "-ubn") {
repo_prefix = ctx.Repo.Repository.Name
} else {
char_index := strings.LastIndex(ctx.Repo.Repository.Name, "-ubn-")
repo_prefix = ctx.Repo.Repository.Name[0:char_index + 4]
}

ctx.Data["username"] = ctx.Repo.Repository.Owner.Name
ctx.Data["reponame"] = ctx.Repo.Repository.Name
ctx.Data["RepoLink"] = ctx.Repo.Repository.Link()
ctx.Data["Title"] = ctx.Tr("repo.hashtag.all_hashtags", ctx.Repo.Repository.Owner.Name + "/" + repo_prefix)
results, err := models.GetHashtagSummary(repo_prefix)

if err != nil {
log.Error(4, "Hashtags: %v", err)
ctx.Handle(http.StatusInternalServerError, "GetHashtagSummary", err)
return
}
ctx.Data["Tags"] = results

ctx.HTML(200, HASHTAGS)
}

// HashtagDisambiguation produces a disambiguation page
func HashtagDisambiguation(ctx *context.Context) {

hashtag := ctx.Params(":hashtag")
print(hashtag)
}
12 changes: 12 additions & 0 deletions templates/repo/hashtag/list.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{template "base/head" .}}
<div class="repository hashtags">
<div class="ui container">
<h1>{{ .Title }}</h1>
<ul>
{{ range .Tags }}
<li><a href="{{ AppSubUrl }}{{ $.RepoLink }}/hashtags/{{ .tag_name|QueryEscape }}">{{ .tag_name }}</a> [{{ .count_of_occurrences }}]</li>
{{end}}
</ul>
</div>
</div>
{{template "base/footer" .}}

0 comments on commit 85e3b4c

Please sign in to comment.