mirror of
https://github.com/documize/community.git
synced 2025-08-03 20:45:26 +02:00
Merge pull request #159 from documize/search-data-limits
Search data limits
This commit is contained in:
commit
3c5065375d
9 changed files with 770 additions and 684 deletions
|
@ -58,9 +58,9 @@ Space view.
|
||||||
|
|
||||||
## Latest version
|
## Latest version
|
||||||
|
|
||||||
[Community edition: v1.65.3](https://github.com/documize/community/releases)
|
[Community edition: v1.65.4](https://github.com/documize/community/releases)
|
||||||
|
|
||||||
[Enterprise edition: v1.67.3](https://documize.com/downloads)
|
[Enterprise edition: v1.67.4](https://documize.com/downloads)
|
||||||
|
|
||||||
## OS support
|
## OS support
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,8 @@ func (s Scope) GetAllBySpace(ctx domain.RequestContext, spaceID string) (c []cat
|
||||||
WHERE orgid=? AND labelid=?
|
WHERE orgid=? AND labelid=?
|
||||||
AND labelid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
AND labelid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view' UNION ALL
|
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view' UNION ALL
|
||||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space'
|
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid
|
||||||
AND p.action='view' AND (r.userid=? OR r.userid='0')
|
WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||||
))
|
))
|
||||||
ORDER BY category`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
ORDER BY category`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||||
|
|
||||||
|
@ -92,6 +92,28 @@ func (s Scope) GetAllBySpace(ctx domain.RequestContext, spaceID string) (c []cat
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByOrg returns all categories accessible by user for their org.
|
||||||
|
func (s Scope) GetByOrg(ctx domain.RequestContext, userID string) (c []category.Category, err error) {
|
||||||
|
err = s.Runtime.Db.Select(&c, `
|
||||||
|
SELECT id, refid, orgid, labelid, category, created, revised FROM category
|
||||||
|
WHERE orgid=?
|
||||||
|
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='category' AND refid IN (
|
||||||
|
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='category' UNION ALL
|
||||||
|
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid
|
||||||
|
WHERE p.orgid=? AND p.who='role' AND p.location='category' AND (r.userid=? OR r.userid='0')
|
||||||
|
))
|
||||||
|
ORDER BY category`, ctx.OrgID, ctx.OrgID, ctx.OrgID, userID, ctx.OrgID, userID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, fmt.Sprintf("unable to execute select categories for org %s", ctx.OrgID))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update saves category name change.
|
// Update saves category name change.
|
||||||
func (s Scope) Update(ctx domain.RequestContext, c category.Category) (err error) {
|
func (s Scope) Update(ctx domain.RequestContext, c category.Category) (err error) {
|
||||||
c.Revised = time.Now().UTC()
|
c.Revised = time.Now().UTC()
|
||||||
|
@ -255,3 +277,25 @@ func (s Scope) GetSpaceCategoryMembership(ctx domain.RequestContext, spaceID str
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrgCategoryMembership returns category/document associations within organization.
|
||||||
|
func (s Scope) GetOrgCategoryMembership(ctx domain.RequestContext, userID string) (c []category.Member, err error) {
|
||||||
|
err = s.Runtime.Db.Select(&c, `
|
||||||
|
SELECT id, refid, orgid, labelid, categoryid, documentid, created, revised FROM categorymember
|
||||||
|
WHERE orgid=?
|
||||||
|
AND labelid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||||
|
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view' UNION ALL
|
||||||
|
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space'
|
||||||
|
AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||||
|
))
|
||||||
|
ORDER BY documentid`, ctx.OrgID, ctx.OrgID, ctx.OrgID, userID, ctx.OrgID, userID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, fmt.Sprintf("select all category/document membership for organization %s", ctx.OrgID))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -418,6 +418,7 @@ func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get search criteria.
|
||||||
options := search.QueryOptions{}
|
options := search.QueryOptions{}
|
||||||
err = json.Unmarshal(body, &options)
|
err = json.Unmarshal(body, &options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -425,24 +426,30 @@ func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Keywords = strings.TrimSpace(options.Keywords)
|
options.Keywords = strings.TrimSpace(options.Keywords)
|
||||||
|
|
||||||
|
// Get documents for search criteria.
|
||||||
results, err := h.Store.Search.Documents(ctx, options)
|
results, err := h.Store.Search.Documents(ctx, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put in slugs for easy UI display of search URL
|
// Generate slugs for search URL.
|
||||||
for key, result := range results {
|
for key, result := range results {
|
||||||
results[key].DocumentSlug = stringutil.MakeSlug(result.Document)
|
results[key].DocumentSlug = stringutil.MakeSlug(result.Document)
|
||||||
results[key].SpaceSlug = stringutil.MakeSlug(result.Space)
|
results[key].SpaceSlug = stringutil.MakeSlug(result.Space)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record user search history
|
// Remove documents that cannot be seen due to lack of
|
||||||
|
// category view/access permission.
|
||||||
|
cats, err := h.Store.Category.GetByOrg(ctx, ctx.UserID)
|
||||||
|
members, err := h.Store.Category.GetOrgCategoryMembership(ctx, ctx.UserID)
|
||||||
|
filtered := indexer.FilterCategoryProtected(results, cats, members)
|
||||||
|
|
||||||
|
// Record user search history.
|
||||||
if !options.SkipLog {
|
if !options.SkipLog {
|
||||||
if len(results) > 0 {
|
if len(filtered) > 0 {
|
||||||
go h.recordSearchActivity(ctx, results, options.Keywords)
|
go h.recordSearchActivity(ctx, filtered, options.Keywords)
|
||||||
} else {
|
} else {
|
||||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -468,7 +475,7 @@ func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeSearch)
|
h.Store.Audit.Record(ctx, audit.EventTypeSearch)
|
||||||
|
|
||||||
response.WriteJSON(w, results)
|
response.WriteJSON(w, filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record search request once per document.
|
// Record search request once per document.
|
||||||
|
|
|
@ -151,7 +151,7 @@ func (s Scope) DeleteContent(ctx domain.RequestContext, pageID string) (err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// Documents searches the documents that the client is allowed to see, using the keywords search string, then audits that search.
|
// Documents searches the documents that the client is allowed to see, using the keywords search string, then audits that search.
|
||||||
// Visible documents include both those in the client's own organisation and those that are public, or whose visibility includes the client.
|
// Visible documents include both those in the client's own organization and those that are public, or whose visibility includes the client.
|
||||||
func (s Scope) Documents(ctx domain.RequestContext, q search.QueryOptions) (results []search.QueryResult, err error) {
|
func (s Scope) Documents(ctx domain.RequestContext, q search.QueryOptions) (results []search.QueryResult, err error) {
|
||||||
q.Keywords = strings.TrimSpace(q.Keywords)
|
q.Keywords = strings.TrimSpace(q.Keywords)
|
||||||
if len(q.Keywords) == 0 {
|
if len(q.Keywords) == 0 {
|
||||||
|
|
|
@ -14,8 +14,10 @@ package search
|
||||||
import (
|
import (
|
||||||
"github.com/documize/community/domain"
|
"github.com/documize/community/domain"
|
||||||
"github.com/documize/community/model/attachment"
|
"github.com/documize/community/model/attachment"
|
||||||
|
"github.com/documize/community/model/category"
|
||||||
"github.com/documize/community/model/doc"
|
"github.com/documize/community/model/doc"
|
||||||
"github.com/documize/community/model/page"
|
"github.com/documize/community/model/page"
|
||||||
|
sm "github.com/documize/community/model/search"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IndexDocument adds search indesd entries for document inserting title, tags and attachments as
|
// IndexDocument adds search indesd entries for document inserting title, tags and attachments as
|
||||||
|
@ -103,3 +105,34 @@ func (m *Indexer) DeleteContent(ctx domain.RequestContext, pageID string) {
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterCategoryProtected removes search results that cannot be seen by user
|
||||||
|
// due to document cateogory viewing permissions.
|
||||||
|
func FilterCategoryProtected(results []sm.QueryResult, cats []category.Category, members []category.Member) (filtered []sm.QueryResult) {
|
||||||
|
filtered = []sm.QueryResult{}
|
||||||
|
|
||||||
|
for _, result := range results {
|
||||||
|
hasCategory := false
|
||||||
|
canSeeCategory := false
|
||||||
|
|
||||||
|
OUTER:
|
||||||
|
|
||||||
|
for _, m := range members {
|
||||||
|
if m.DocumentID == result.DocumentID {
|
||||||
|
hasCategory = true
|
||||||
|
for _, cat := range cats {
|
||||||
|
if cat.RefID == m.CategoryID {
|
||||||
|
canSeeCategory = true
|
||||||
|
continue OUTER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasCategory || canSeeCategory {
|
||||||
|
filtered = append(filtered, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,8 @@ type CategoryStorer interface {
|
||||||
GetSpaceCategoryMembership(ctx RequestContext, spaceID string) (c []category.Member, err error)
|
GetSpaceCategoryMembership(ctx RequestContext, spaceID string) (c []category.Member, err error)
|
||||||
RemoveDocumentCategories(ctx RequestContext, documentID string) (rows int64, err error)
|
RemoveDocumentCategories(ctx RequestContext, documentID string) (rows int64, err error)
|
||||||
RemoveSpaceCategoryMemberships(ctx RequestContext, spaceID string) (rows int64, err error)
|
RemoveSpaceCategoryMemberships(ctx RequestContext, spaceID string) (rows int64, err error)
|
||||||
|
GetByOrg(ctx RequestContext, userID string) (c []category.Category, err error)
|
||||||
|
GetOrgCategoryMembership(ctx RequestContext, userID string) (c []category.Member, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionStorer defines required methods for space/document permission management
|
// PermissionStorer defines required methods for space/document permission management
|
||||||
|
|
|
@ -42,7 +42,7 @@ func main() {
|
||||||
rt.Product = env.ProdInfo{}
|
rt.Product = env.ProdInfo{}
|
||||||
rt.Product.Major = "1"
|
rt.Product.Major = "1"
|
||||||
rt.Product.Minor = "65"
|
rt.Product.Minor = "65"
|
||||||
rt.Product.Patch = "3"
|
rt.Product.Patch = "4"
|
||||||
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
|
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
|
||||||
rt.Product.Edition = "Community"
|
rt.Product.Edition = "Community"
|
||||||
rt.Product.Title = fmt.Sprintf("%s Edition", rt.Product.Edition)
|
rt.Product.Title = fmt.Sprintf("%s Edition", rt.Product.Edition)
|
||||||
|
|
1342
embed/bindata.go
1342
embed/bindata.go
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "documize",
|
"name": "documize",
|
||||||
"version": "1.65.3",
|
"version": "1.65.4",
|
||||||
"description": "The Document IDE",
|
"description": "The Document IDE",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "",
|
"repository": "",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue