浏览代码

New style search request for gin-dex

- Search function collects IDs for repositories the user can read
- Does not add unlisted repositories
- Submits the repository ID list to the indexing service with the search
request
- The request data are encrypted with a shared key
Achilleas Koutsou 6 年之前
父节点
当前提交
4fa21fa037
共有 4 个文件被更改,包括 95 次插入17 次删除
  1. 1 0
      pkg/setting/setting.go
  2. 2 2
      routes/api/v1/search/general.go
  3. 7 5
      routes/api/v1/search/suggest.go
  4. 85 10
      routes/search.go

+ 1 - 0
pkg/setting/setting.go

@@ -333,6 +333,7 @@ var (
 	Search struct {
 		IndexURL  string `ini:"INDEX_URL"`
 		SearchURL string `ini:"SEARCH_URL"`
+		Key       string `ini:"SEARCH_KEY"`
 	}
 
 	DOI struct {

+ 2 - 2
routes/api/v1/search/general.go

@@ -12,6 +12,7 @@ import (
 )
 
 func Search(c *context.APIContext) {
+	// TODO: API calls shouldn't use cookie (see https://github.com/G-Node/gin-dex/issues/2)
 	if !c.IsLogged {
 		c.Status(http.StatusUnauthorized)
 		return
@@ -20,8 +21,7 @@ func Search(c *context.APIContext) {
 		c.Status(http.StatusNotImplemented)
 		return
 	}
-	ireq := libgin.SearchRequest{Token: c.GetCookie(setting.SessionConfig.CookieName), UserID: c.User.ID,
-		Query: c.Params("query"), CsrfT: c.GetCookie(setting.CSRFCookieName)}
+	ireq := libgin.SearchRequest{}
 	data, err := json.Marshal(ireq)
 	if err != nil {
 		c.Status(http.StatusInternalServerError)

+ 7 - 5
routes/api/v1/search/suggest.go

@@ -12,15 +12,17 @@ import (
 )
 
 func Suggest(c *context.APIContext) {
+	// TODO: API calls shouldn't use cookie (see https://github.com/G-Node/gin-dex/issues/2)
 	if setting.Search.SearchURL == "" {
 		c.Status(http.StatusNotImplemented)
 		return
 	}
-	ireq := libgin.SearchRequest{Token: c.GetCookie(setting.SessionConfig.CookieName),
-		Query: c.Params("query"), CsrfT: c.GetCookie(setting.CSRFCookieName), SType: libgin.SEARCH_SUGGEST}
-	if c.IsLogged {
-		ireq.UserID = c.User.ID
-	}
+	ireq := libgin.SearchRequest{}
+	// ireq := libgin.SearchRequest{Token: c.GetCookie(setting.SessionConfig.CookieName),
+	// 	Query: c.Params("query"), CsrfT: c.GetCookie(setting.CSRFCookieName), SType: libgin.SEARCH_SUGGEST}
+	// if c.IsLogged {
+	// 	ireq.UserID = c.User.ID
+	// }
 	data, err := json.Marshal(ireq)
 	if err != nil {
 		c.Status(http.StatusInternalServerError)

+ 85 - 10
routes/search.go

@@ -1,13 +1,14 @@
 package routes
 
 import (
-	"bytes"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
 	"net/http"
 	"strconv"
+	"strings"
 
+	"github.com/G-Node/gogs/models"
 	"github.com/G-Node/gogs/pkg/context"
 	"github.com/G-Node/gogs/pkg/setting"
 	"github.com/G-Node/libgin/libgin"
@@ -19,24 +20,98 @@ const (
 	EXPLORE_COMMITS = "explore/commits"
 )
 
-func Search(c *context.Context, keywords string, sType int64) ([]byte, error) {
+type set map[int64]interface{}
+
+func newset() set {
+	return make(map[int64]interface{}, 0)
+}
+
+func (s set) add(item int64) {
+	s[item] = nil
+}
+
+func (s set) contains(item int64) bool {
+	_, yes := s[item]
+	return yes
+}
+
+func (s set) remove(item int64) {
+	delete(s, item)
+}
+
+func (s set) asSlice() []int64 {
+	slice := make([]int64, len(s))
+	idx := 0
+	for item := range s {
+		slice[idx] = item
+		idx++
+	}
+	return slice
+}
+
+func collectSearchableRepoIDs(c *context.Context) ([]int64, error) {
+	repoIDSet := newset()
+
+	updateSet := func(repos []*models.Repository) {
+		for _, r := range repos {
+			repoIDSet.add(r.ID)
+		}
+	}
+	ownRepos := c.User.Repos // user's own repositories
+	updateSet(ownRepos)
+
+	accessibleRepos, _ := c.User.GetAccessibleRepositories(0) // shared and org repos
+	updateSet(accessibleRepos)
+
+	repos, _, err := models.SearchRepositoryByName(&models.SearchRepoOptions{
+		Keyword:  "",
+		UserID:   c.UserID(),
+		OrderBy:  "updated_unix DESC",
+		Page:     0,
+		PageSize: 0,
+	})
+	if err != nil {
+		c.ServerError("SearchRepositoryByName", err)
+		return nil, err
+	}
+
+	// If it's not unlisted, add it to the set
+	// This will add public (listed) repositories
+	for _, r := range repos {
+		if !r.Unlisted {
+			repoIDSet.add(r.ID)
+		}
+	}
+
+	return repoIDSet.asSlice(), nil
+}
+
+func Search(c *context.Context, keywords string, sType int) ([]byte, error) {
 	if setting.Search.SearchURL == "" {
 		c.Status(http.StatusNotImplemented)
 		return nil, fmt.Errorf("Extended search not implemented")
 	}
 
-	ireq := libgin.SearchRequest{Token: c.GetCookie(setting.SessionConfig.CookieName),
-		Query: keywords, CsrfT: c.GetCookie(setting.CSRFCookieName), SType: sType, UserID: -10}
-	if c.IsLogged {
-		ireq.UserID = c.User.ID
+	key := []byte(setting.Search.Key)
+
+	repoids, err := collectSearchableRepoIDs(c)
+	if err != nil {
+		return nil, err
+	}
+	searchdata := libgin.SearchRequest{keywords, sType, repoids}
+
+	data, err := json.Marshal(searchdata)
+	if err != nil {
+		c.Status(http.StatusInternalServerError)
+		return nil, err
 	}
 
-	data, err := json.Marshal(ireq)
+	encdata, err := libgin.EncryptString(key, string(data))
 	if err != nil {
 		c.Status(http.StatusInternalServerError)
 		return nil, err
 	}
-	req, _ := http.NewRequest("Post", setting.Search.SearchURL, bytes.NewReader(data))
+	req, _ := http.NewRequest("POST", setting.Search.SearchURL, strings.NewReader(encdata))
 	cl := http.Client{}
 	resp, err := cl.Do(req)
 	if err != nil {
@@ -63,7 +138,7 @@ func ExploreData(c *context.Context) {
 		log.Error(2, "Search type not understood: %s", err.Error())
 		sType = 0
 	}
-	data, err := Search(c, keywords, sType)
+	data, err := Search(c, keywords, int(sType))
 	if err != nil {
 		c.Handle(http.StatusInternalServerError, "Could not query", err)
 		return
@@ -91,7 +166,7 @@ func ExploreCommits(c *context.Context) {
 		log.Error(2, "Search type not understood: %s", err.Error())
 		sType = 0
 	}
-	data, err := Search(c, keywords, sType)
+	data, err := Search(c, keywords, int(sType))
 
 	if err != nil {
 		c.Handle(http.StatusInternalServerError, "Could not query", err)