1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-21 14:19:43 +02:00

Record document search history

This commit is contained in:
McMatts 2018-03-30 17:03:18 +01:00
parent 4816cf73c0
commit a6828e6b7f
8 changed files with 110 additions and 37 deletions

View file

@ -52,9 +52,9 @@ Space view.
## Latest version
[Community edition: v1.60.0](https://github.com/documize/community/releases)
[Community edition: v1.61.0](https://github.com/documize/community/releases)
[Enterprise edition: v1.62.0](https://documize.com/downloads)
[Enterprise edition: v1.63.0](https://documize.com/downloads)
## OS support
@ -69,7 +69,7 @@ Documize runs on the following:
Documize is built with the following technologies:
- EmberJS (v2.18.0)
- Go (v1.10)
- Go (v1.10.1)
...and supports the following databases:
@ -77,7 +77,7 @@ Documize is built with the following technologies:
- Percona (v5.7.16-10+)
- MariaDB (10.3.0+)
Coming soon, PostgreSQL and Microsoft SQL Server support.
Coming soon, PostgreSQL and Microsoft SQL Server database support.
## Authentication options

View file

@ -0,0 +1,28 @@
/* enterprise edition */
-- content analytics
ALTER TABLE useractivity ADD COLUMN `metadata` VARCHAR(1000) NOT NULL DEFAULT '' AFTER `activitytype`;
-- content likes/feedback
-- DROP TABLE IF EXISTS `vote`;
-- CREATE TABLE IF NOT EXISTS `vote` (
-- `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
-- `refid` CHAR(16) NOT NULL COLLATE utf8_bin,
-- `orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
-- `documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
-- `userid` CHAR(16) NOT NULL DEFAULT '' COLLATE utf8_bin,
-- `vote` INT NOT NULL DEFAULT 0,
-- `comment` VARCHAR(300) NOT NULL DEFAULT '',
-- `created` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- `revised` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- UNIQUE INDEX `idx_vote_id` (`id` ASC),
-- INDEX `idx_vote_refid` (`refid` ASC),
-- INDEX `idx_vote_documentid` (`documentid` ASC),
-- INDEX `idx_vote_orgid` (`orgid` ASC))
-- DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
-- ENGINE = MyISAM;
-- CREATE INDEX idx_vote_1 ON vaote(orgid,documentid);
-- deprecations

View file

@ -34,8 +34,8 @@ func (s Scope) RecordUserActivity(ctx domain.RequestContext, activity activity.U
activity.UserID = ctx.UserID
activity.Created = time.Now().UTC()
_, err = ctx.Transaction.Exec("INSERT INTO useractivity (orgid, userid, labelid, documentid, pageid, sourcetype, activitytype, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
activity.OrgID, activity.UserID, activity.LabelID, activity.DocumentID, activity.PageID, activity.SourceType, activity.ActivityType, activity.Created)
_, err = ctx.Transaction.Exec("INSERT INTO useractivity (orgid, userid, labelid, documentid, pageid, sourcetype, activitytype, metadata, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
activity.OrgID, activity.UserID, activity.LabelID, activity.DocumentID, activity.PageID, activity.SourceType, activity.ActivityType, activity.Metadata, activity.Created)
if err != nil {
err = errors.Wrap(err, "execute record user activity")
@ -46,7 +46,7 @@ func (s Scope) RecordUserActivity(ctx domain.RequestContext, activity activity.U
// GetDocumentActivity returns the metadata for a specified document.
func (s Scope) GetDocumentActivity(ctx domain.RequestContext, id string) (a []activity.DocumentActivity, err error) {
qry := `SELECT a.id, DATE(a.created) as created, a.orgid, IFNULL(a.userid, '') AS userid, a.labelid, a.documentid, a.pageid, a.activitytype,
qry := `SELECT a.id, DATE(a.created) as created, a.orgid, IFNULL(a.userid, '') AS userid, a.labelid, a.documentid, a.pageid, a.activitytype, a.metadata,
IFNULL(u.firstname, 'Anonymous') AS firstname, IFNULL(u.lastname, 'Viewer') AS lastname,
IFNULL(p.title, '') as pagetitle
FROM useractivity a

View file

@ -401,20 +401,44 @@ func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
// Put in slugs for easy UI display of search URL
for key, result := range results {
result.DocumentSlug = stringutil.MakeSlug(result.Document)
result.SpaceSlug = stringutil.MakeSlug(result.Space)
results[key] = result
results[key].DocumentSlug = stringutil.MakeSlug(result.Document)
results[key].SpaceSlug = stringutil.MakeSlug(result.Space)
}
if len(results) == 0 {
results = []search.QueryResult{}
}
// Record user search history
go h.recordSearchActivity(ctx, results)
h.Store.Audit.Record(ctx, audit.EventTypeSearch)
response.WriteJSON(w, results)
}
func (h *Handler) recordSearchActivity(ctx domain.RequestContext, q []search.QueryResult) {
method := "recordSearchActivity"
var err error
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
h.Runtime.Log.Error(method, err)
return
}
for i := range q {
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: q[i].SpaceID,
DocumentID: q[i].DocumentID,
SourceType: activity.SourceTypeSearch,
ActivityType: activity.TypeSearched})
if err != nil {
ctx.Transaction.Rollback()
h.Runtime.Log.Error(method, err)
}
}
ctx.Transaction.Commit()
}
// FetchDocumentData returns all document data in single API call.
func (h *Handler) FetchDocumentData(w http.ResponseWriter, r *http.Request) {
method := "document.FetchDocumentData"

View file

@ -204,6 +204,10 @@ func (s Scope) Documents(ctx domain.RequestContext, q search.QueryOptions) (resu
results = append(results, r4...)
}
if len(results) == 0 {
results = []search.QueryResult{}
}
return
}
@ -227,9 +231,10 @@ func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType strin
(
SELECT refid FROM label WHERE orgid=? AND refid IN
(
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
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 r.userid=?
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 (r.userid=? OR r.userid='0')
)
)
AND MATCH(s.content) AGAINST(? IN BOOLEAN MODE)`
@ -280,13 +285,13 @@ func (s Scope) matchLike(ctx domain.RequestContext, keywords, itemType string) (
-- AND d.template = 0
AND d.labelid IN
(
SELECT refid FROM label WHERE orgid=?
AND refid 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'
SELECT refid FROM label WHERE orgid=? AND refid IN
(
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
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')
))
AND p.location='space' AND (r.userid=? OR r.userid='0')
)
)
AND s.content LIKE ?`

View file

@ -41,7 +41,7 @@ func main() {
// product details
rt.Product = env.ProdInfo{}
rt.Product.Major = "1"
rt.Product.Minor = "60"
rt.Product.Minor = "61"
rt.Product.Patch = "0"
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
rt.Product.Edition = "Community"

View file

@ -1,6 +1,6 @@
{
"name": "documize",
"version": "1.60.0",
"version": "1.61.0",
"description": "The Document IDE",
"private": true,
"repository": "",

View file

@ -23,8 +23,11 @@ type UserActivity struct {
PageID string `json:"pageId"`
ActivityType Type `json:"activityType"`
SourceType SourceType `json:"sourceType"`
SourceName string `json:"sourceName"`
Metadata string `json:"metadata"`
Created time.Time `json:"created"`
// Read-only outbound fields (e.g. for UI display)
SourceName string `json:"sourceName"`
}
// DocumentActivity represents an activity taken against a document.
@ -57,50 +60,57 @@ const (
// SourceTypePage indicates activity against a document page.
SourceTypePage SourceType = 3
// SourceTypeSearch indicates activity on search page.
SourceTypeSearch SourceType = 4
)
const (
// TypeCreated records user document creation
// TypeCreated records user object creation (document or space).
TypeCreated Type = 1
// TypeRead states user has read document
// TypeRead states user has consumed object (document or space).
TypeRead Type = 2
// TypeEdited states user has editing document
// TypeEdited states user has editing document.
TypeEdited Type = 3
// TypeDeleted records user deleting space/document
// TypeDeleted records user deleting space/document.
TypeDeleted Type = 4
// TypeArchived records user archiving space/document
// TypeArchived records user archiving space/document.
TypeArchived Type = 5
// TypeApproved records user approval of document
// TypeApproved records user approval of document.
TypeApproved Type = 6
// TypeReverted records user content roll-back to previous version
// TypeReverted records user content roll-back to previous document version.
TypeReverted Type = 7
// TypePublishedTemplate records user creating new document template
// TypePublishedTemplate records user creating new document template.
TypePublishedTemplate Type = 8
// TypePublishedBlock records user creating reusable content block
// TypePublishedBlock records user creating reusable content block.
TypePublishedBlock Type = 9
// TypeCommented records user providing document feedback
// TypeCommented records user providing document feedback.
TypeCommented Type = 10
// TypeRejected records user rejecting document
// TypeRejected records user rejecting document.
TypeRejected Type = 11
// TypeSentSecureLink records user sending secure document link to email address(es)
// TypeSentSecureLink records user sending secure document link via email.
TypeSentSecureLink Type = 12
// TypeDraft records user marking space/document as draft
// TypeDraft records user marking space/document as draft.
TypeDraft Type = 13
// TypeVersioned records user creating new document version
// TypeVersioned records user creating new document version.
TypeVersioned Type = 14
// TypeSearched records user performing document keyword search.
// Metadata field should contain search terms.
TypeSearched Type = 15
)
// TypeName returns one-work descriptor for activity type
@ -130,6 +140,12 @@ func TypeName(t Type) string {
return "Reject"
case TypeSentSecureLink:
return "Share"
case TypeDraft:
return "Draft"
case TypeVersioned:
return "Version"
case TypeSearched:
return "Search"
}
return ""