Skip to content

Commit

Permalink
Add user/organization code search
Browse files Browse the repository at this point in the history
  • Loading branch information
lafriks committed Oct 10, 2022
1 parent 083ac16 commit c000ab4
Show file tree
Hide file tree
Showing 17 changed files with 253 additions and 78 deletions.
30 changes: 20 additions & 10 deletions models/repo/repo_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,16 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
return sess, count, nil
}

// SearchRepositoryIDsByCondition search repository IDs by given condition.
func SearchRepositoryIDsByCondition(ctx context.Context, cond builder.Cond) ([]int64, error) {
repoIDs := make([]int64, 0, 10)
return repoIDs, db.GetEngine(ctx).
Table("repository").
Cols("id").
Where(cond).
Find(&repoIDs)
}

// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) builder.Cond {
cond := builder.NewCond()
Expand Down Expand Up @@ -680,16 +690,16 @@ func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder {
}

// FindUserCodeAccessibleRepoIDs finds all at Code level accessible repositories' ID by the user's id
func FindUserCodeAccessibleRepoIDs(user *user_model.User) ([]int64, error) {
repoIDs := make([]int64, 0, 10)
if err := db.GetEngine(db.DefaultContext).
Table("repository").
Cols("id").
Where(AccessibleRepositoryCondition(user, unit.TypeCode)).
Find(&repoIDs); err != nil {
return nil, fmt.Errorf("FindUserCodeAccesibleRepoIDs: %v", err)
}
return repoIDs, nil
func FindUserCodeAccessibleRepoIDs(ctx context.Context, user *user_model.User) ([]int64, error) {
return SearchRepositoryIDsByCondition(ctx, AccessibleRepositoryCondition(user, unit.TypeCode))
}

// FindUserCodeAccessibleOwnerRepoIDs finds all repository IDs for the given owner whose code the user can see.
func FindUserCodeAccessibleOwnerRepoIDs(ctx context.Context, ownerID int64, user *user_model.User) ([]int64, error) {
return SearchRepositoryIDsByCondition(ctx, builder.NewCond().And(
builder.Eq{"owner_id": ownerID},
AccessibleRepositoryCondition(user, unit.TypeCode),
))
}

// GetUserRepositories returns a list of repositories of given user.
Expand Down
1 change: 1 addition & 0 deletions modules/context/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["IsPublicMember"] = func(uid int64) bool {
is, _ := organization.IsPublicMembership(ctx.Org.Organization.ID, uid)
return is
Expand Down
2 changes: 2 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ activity = Public Activity
followers = Followers
starred = Starred Repositories
watched = Watched Repositories
code = Code
projects = Projects
following = Following
follow = Follow
Expand Down Expand Up @@ -2310,6 +2311,7 @@ create_org = Create Organization
repo_updated = Updated
people = People
teams = Teams
code = Code
lower_members = members
lower_repositories = repositories
create_new_team = New Team
Expand Down
4 changes: 2 additions & 2 deletions routers/web/explore/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ func Code(ctx *context.Context) {

// guest user or non-admin user
if ctx.Doer == nil || !isAdmin {
repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx.Doer)
repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx, ctx.Doer)
if err != nil {
ctx.ServerError("SearchResults", err)
ctx.ServerError("FindUserCodeAccessibleRepoIDs", err)
return
}
}
Expand Down
114 changes: 114 additions & 0 deletions routers/web/user/code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2022 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 user

import (
"net/http"

repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
code_indexer "code.gitea.io/gitea/modules/indexer/code"
"code.gitea.io/gitea/modules/setting"
)

const (
tplUserCode base.TplName = "user/code"
)

// CodeSearch render user/organization code search page
func CodeSearch(ctx *context.Context) {
if !setting.Indexer.RepoIndexerEnabled {
ctx.Redirect(ctx.ContextUser.HomeLink())
return
}

ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["Title"] = ctx.Tr("code.title")
ctx.Data["ContextUser"] = ctx.ContextUser

language := ctx.FormTrim("l")
keyword := ctx.FormTrim("q")

queryType := ctx.FormTrim("t")
isMatch := queryType == "match"

ctx.Data["Keyword"] = keyword
ctx.Data["Language"] = language
ctx.Data["queryType"] = queryType
ctx.Data["IsCodePage"] = true

if keyword == "" {
ctx.HTML(http.StatusOK, tplUserCode)
return
}

var (
repoIDs []int64
err error
)

page := ctx.FormInt("page")
if page <= 0 {
page = 1
}

repoIDs, err = repo_model.FindUserCodeAccessibleOwnerRepoIDs(ctx, ctx.ContextUser.ID, ctx.Doer)
if err != nil {
ctx.ServerError("FindUserCodeAccessibleOwnerRepoIDs", err)
return
}

var (
total int
searchResults []*code_indexer.Result
searchResultLanguages []*code_indexer.SearchResultLanguages
)

if len(repoIDs) > 0 {
total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
if err != nil {
if code_indexer.IsAvailable() {
ctx.ServerError("SearchResults", err)
return
}
ctx.Data["CodeIndexerUnavailable"] = true
} else {
ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
}

loadRepoIDs := make([]int64, 0, len(searchResults))
for _, result := range searchResults {
var find bool
for _, id := range loadRepoIDs {
if id == result.RepoID {
find = true
break
}
}
if !find {
loadRepoIDs = append(loadRepoIDs, result.RepoID)
}
}

repoMaps, err := repo_model.GetRepositoriesMapByIDs(loadRepoIDs)
if err != nil {
ctx.ServerError("GetRepositoriesMapByIDs", err)
return
}

ctx.Data["RepoMaps"] = repoMaps
}
ctx.Data["SearchResults"] = searchResults
ctx.Data["SearchResultLanguages"] = searchResultLanguages

pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "l", "Language")
ctx.Data["Page"] = pager

ctx.HTML(http.StatusOK, tplUserCode)
}
4 changes: 4 additions & 0 deletions routers/web/user/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func ListPackages(ctx *context.Context) {

ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["IsPackagesPage"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["Query"] = query
ctx.Data["PackageType"] = packageType
Expand Down Expand Up @@ -157,6 +158,7 @@ func ViewPackageVersion(ctx *context.Context) {

ctx.Data["Title"] = pd.Package.Name
ctx.Data["IsPackagesPage"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["PackageDescriptor"] = pd

Expand Down Expand Up @@ -234,6 +236,7 @@ func ListPackageVersions(ctx *context.Context) {

ctx.Data["Title"] = ctx.Tr("packages.title")
ctx.Data["IsPackagesPage"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["PackageDescriptor"] = &packages_model.PackageDescriptor{
Package: p,
Expand Down Expand Up @@ -305,6 +308,7 @@ func PackageSettings(ctx *context.Context) {

ctx.Data["Title"] = pd.Package.Name
ctx.Data["IsPackagesPage"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["PackageDescriptor"] = pd

Expand Down
1 change: 1 addition & 0 deletions routers/web/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ func Profile(ctx *context.Context) {
}
ctx.Data["Page"] = pager
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled

ctx.Data["ShowUserEmail"] = len(ctx.ContextUser.Email) > 0 && ctx.IsSigned && (!ctx.ContextUser.KeepEmailPrivate || ctx.ContextUser.ID == ctx.Doer.ID)

Expand Down
1 change: 1 addition & 0 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ func RegisterRoutes(m *web.Route) {
})
}, ignSignIn, context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
}
m.Get("/code", user.CodeSearch)
}, context_service.UserAssignmentWeb())

// ***** Release Attachment Download without Signin
Expand Down
14 changes: 14 additions & 0 deletions templates/code/searchform.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<form class="ui form ignore-dirty" style="max-width: 100%">
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable }} disabled{{end}} placeholder="{{.locale.Tr "explore.search"}}" autofocus>
<div class="ui dropdown selection{{if .CodeIndexerUnavailable }} disabled{{end}}">
<input name="t" type="hidden" value="{{.queryType}}"{{if .CodeIndexerUnavailable }} disabled{{end}}>{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="text">{{.locale.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
<div class="item" data-value="">{{.locale.Tr "explore.search.fuzzy"}}</div>
<div class="item" data-value="match">{{.locale.Tr "explore.search.match"}}</div>
</div>
</div>
<button class="ui primary button"{{if .CodeIndexerUnavailable }} disabled{{end}}>{{.locale.Tr "explore.search"}}</button>
</div>
</form>
43 changes: 43 additions & 0 deletions templates/code/searchresults.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<div class="df ac fw">
{{range $term := .SearchResultLanguages}}
<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}{{if $.ContextUser}}/{{$.ContextUser.Name}}/-/code{{else}}/explore/code{{end}}?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
<i class="color-icon mr-3" style="background-color: {{$term.Color}}"></i>
{{$term.Language}}
<div class="detail">{{$term.Count}}</div>
</a>
{{end}}
</div>
<div class="repository search">
{{range $result := .SearchResults}}
{{$repo := (index $.RepoMaps .RepoID)}}
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
<h4 class="ui top attached normal header">
<span class="file">
<a rel="nofollow" href="{{$repo.HTMLURL}}">{{$repo.FullName}}</a>
{{if $repo.IsArchived}}
<span class="ui basic label">{{$.locale.Tr "repo.desc.archived"}}</span>
{{end}}
- {{.Filename}}
</span>
<a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.Tr "repo.diff.view_file"}}</a>
</h4>
<div class="ui attached table segment">
<div class="file-body file-code code-view">
<table>
<tbody>
<tr>
<td class="lines-num">
{{range .LineNumbers}}
<a href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
{{end}}
</td>
<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td>
</tr>
</tbody>
</table>
</div>
</div>
{{template "shared/searchbottom" dict "root" $ "result" .}}
</div>
{{end}}
</div>
61 changes: 3 additions & 58 deletions templates/explore/code.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,7 @@
<div class="page-content explore users">
{{template "explore/navbar" .}}
<div class="ui container">
<form class="ui form ignore-dirty" style="max-width: 100%">
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable}} disabled{{end}} placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
<div class="ui dropdown selection{{if .CodeIndexerUnavailable}} disabled{{end}}">
<input name="t" type="hidden" value="{{.queryType}}"{{if .CodeIndexerUnavailable}} disabled{{end}}>{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="text">{{.locale.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
<div class="item" data-value="">{{.locale.Tr "explore.search.fuzzy"}}</div>
<div class="item" data-value="match">{{.locale.Tr "explore.search.match"}}</div>
</div>
</div>
<button class="ui primary button"{{if .CodeIndexerUnavailable}} disabled{{end}}>{{.locale.Tr "explore.search"}}</button>
</div>
</form>
{{template "code/searchform" .}}
<div class="ui divider"></div>
<div class="ui user list">
{{if .CodeIndexerUnavailable}}
Expand All @@ -26,50 +13,8 @@
<h3>
{{.locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html}}
</h3>
<div class="df ac fw">
{{range $term := .SearchResultLanguages}}
<a class="ui text-label df ac mr-1 my-1 {{if eq $.Language $term.Language}}primary {{end}}basic label" href="{{AppSubUrl}}/explore/code?q={{$.Keyword}}{{if ne $.Language $term.Language}}&l={{$term.Language}}{{end}}{{if ne $.queryType ""}}&t={{$.queryType}}{{end}}">
<i class="color-icon mr-3" style="background-color: {{$term.Color}}"></i>
{{$term.Language}}
<div class="detail">{{$term.Count}}</div>
</a>
{{end}}
</div>
<div class="repository search">
{{range $result := .SearchResults}}
{{$repo := (index $.RepoMaps .RepoID)}}
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
<h4 class="ui top attached normal header">
<span class="file">
<a rel="nofollow" href="{{$repo.HTMLURL}}">{{$repo.FullName}}</a>
{{if $repo.IsArchived}}
<span class="ui basic label">{{$.locale.Tr "repo.desc.archived"}}</span>
{{end}}
- {{.Filename}}
</span>
<a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.Tr "repo.diff.view_file"}}</a>
</h4>
<div class="ui attached table segment">
<div class="file-body file-code code-view">
<table>
<tbody>
<tr>
<td class="lines-num">
{{range .LineNumbers}}
<a href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
{{end}}
</td>
<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td>
</tr>
</tbody>
</table>
</div>
</div>
{{template "shared/searchbottom" dict "root" $ "result" .}}
</div>
{{end}}
</div>
{{else}}
{{template "code/searchresults" .}}
{{else if .Keyword}}
<div>{{$.locale.Tr "explore.code_no_results"}}</div>
{{end}}
</div>
Expand Down
2 changes: 1 addition & 1 deletion templates/explore/repo_search.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<input type="hidden" name="sort" value="{{$.SortType}}">
<input type="hidden" name="language" value="{{$.Language}}">
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}" autofocus>
<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
</div>
</form>
Expand Down
2 changes: 1 addition & 1 deletion templates/explore/search.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</div>
<form class="ui form ignore-dirty" style="max-width: 90%">
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}" autofocus>
<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
</div>
</form>
Expand Down
Loading

0 comments on commit c000ab4

Please sign in to comment.