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

bug fixes galore

This commit is contained in:
Harvey Kandola 2017-08-07 14:42:02 +01:00
parent 62b7b149c1
commit 557da2847e
13 changed files with 148 additions and 67 deletions

View file

@ -92,7 +92,7 @@ func Check(runtime *env.Runtime) bool {
} }
{ // check the MySQL character set and collation { // check the MySQL character set and collation
if charset != "utf8" { if charset != "utf8" && charset != "utf8mb4" {
runtime.Log.Error("MySQL character set not utf8:", errors.New(charset)) runtime.Log.Error("MySQL character set not utf8:", errors.New(charset))
web.SiteInfo.Issue = "MySQL character set not utf8: " + charset web.SiteInfo.Issue = "MySQL character set not utf8: " + charset
runtime.Flags.SiteMode = env.SiteModeBadDB runtime.Flags.SiteMode = env.SiteModeBadDB

40
core/database/readme.md Normal file
View file

@ -0,0 +1,40 @@
## TODO
1. Remove audit table
2. Remove document.layout field
## MYSQL
https://stackoverflow.com/questions/37307146/difference-between-utf8mb4-unicode-ci-and-utf8mb4-unicode-520-ci-collations-in-m
https://mathiasbynens.be/notes/mysql-utf8mb4
https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434
ALTER DATABASE documize CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE account CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE attachment CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE block CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE config CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE document CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE feedback CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE label CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE labelrole CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE link CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE organization CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE page CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE pagemeta CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE participant CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE pin CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE revision CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE search CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE share CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE useraction CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE useractivity CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE userconfig CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE userevent CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

View file

@ -1,5 +0,0 @@
TODO
-----
1. Remove audit table
2. Remove document.layout field

View file

@ -44,7 +44,6 @@ type RequestContext struct {
//GetAppURL returns full HTTP url for the app //GetAppURL returns full HTTP url for the app
func (c *RequestContext) GetAppURL(endpoint string) string { func (c *RequestContext) GetAppURL(endpoint string) string {
scheme := "http://" scheme := "http://"
if c.SSL { if c.SSL {
scheme = "https://" scheme = "https://"
} }
@ -58,17 +57,12 @@ type key string
const DocumizeContextKey key = "documize context key" const DocumizeContextKey key = "documize context key"
// GetRequestContext returns RequestContext from context.Context // GetRequestContext returns RequestContext from context.Context
func GetRequestContext(r *http.Request) RequestContext { func GetRequestContext(r *http.Request) (ctx RequestContext) {
return r.Context().Value(DocumizeContextKey).(RequestContext) c := r.Context()
if c != nil && c.Value(DocumizeContextKey) != nil {
ctx = c.Value(DocumizeContextKey).(RequestContext)
return
}
return RequestContext{}
} }
// // Scope provides data persistence methods with runtime and request context.
// type Scope struct {
// Runtime *env.Runtime
// Context RequestContext
// }
// // NewScope returns request scoped user context and store context for persistence logic.
// func NewScope(rt *env.Runtime, r *http.Request) Scope {
// return Scope{Runtime: rt, Context: GetRequestContext(r)}
// }

View file

@ -278,7 +278,7 @@ func (s Scope) Documents(ctx domain.RequestContext, keywords string) (results []
keywords = strings.Replace(keywords, " ", "", -1) keywords = strings.Replace(keywords, " ", "", -1)
} }
keywords = strings.TrimSpace(keywords) keywords = strings.ToLower(strings.TrimSpace(keywords))
if len(keywords) > 0 { if len(keywords) > 0 {
keywordQuery = "AND MATCH(pagetitle,body) AGAINST('" + keywords + "' in boolean mode)" keywordQuery = "AND MATCH(pagetitle,body) AGAINST('" + keywords + "' in boolean mode)"

View file

@ -65,15 +65,15 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
return return
} }
var space = space.Space{} var sp = space.Space{}
err = json.Unmarshal(body, &space) err = json.Unmarshal(body, &sp)
if err != nil { if err != nil {
response.WriteServerError(w, method, err) response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err) h.Runtime.Log.Error(method, err)
return return
} }
if len(space.Name) == 0 { if len(sp.Name) == 0 {
response.WriteMissingDataError(w, method, "name") response.WriteMissingDataError(w, method, "name")
return return
} }
@ -85,10 +85,12 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
return return
} }
space.RefID = uniqueid.Generate() sp.RefID = uniqueid.Generate()
space.OrgID = ctx.OrgID sp.OrgID = ctx.OrgID
sp.Type = space.ScopePrivate
sp.UserID = ctx.UserID
err = h.Store.Space.Add(ctx, space) err = h.Store.Space.Add(ctx, sp)
if err != nil { if err != nil {
ctx.Transaction.Rollback() ctx.Transaction.Rollback()
response.WriteServerError(w, method, err) response.WriteServerError(w, method, err)
@ -96,13 +98,29 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
return return
} }
h.Store.Audit.Record(ctx, audit.EventTypeSpaceAdd) role := space.Role{}
role.LabelID = sp.RefID
role.OrgID = sp.OrgID
role.UserID = ctx.UserID
role.CanEdit = true
role.CanView = true
role.RefID = uniqueid.Generate()
err = h.Store.Space.AddRole(ctx, role)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
ctx.Transaction.Commit() ctx.Transaction.Commit()
space, _ = h.Store.Space.Get(ctx, space.RefID) h.Store.Audit.Record(ctx, audit.EventTypeSpaceAdd)
response.WriteJSON(w, space) sp, _ = h.Store.Space.Get(ctx, sp.RefID)
response.WriteJSON(w, sp)
} }
// Get returns the requested space. // Get returns the requested space.

View file

@ -72,7 +72,7 @@ func (s Scope) Get(ctx domain.RequestContext, id string) (sp space.Space, err er
return return
} }
// PublicSpaces returns folders that anyone can see. // PublicSpaces returns spaces that anyone can see.
func (s Scope) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space.Space, err error) { func (s Scope) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space.Space, err error) {
sql := "SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1" sql := "SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1"
@ -86,18 +86,18 @@ func (s Scope) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space
return return
} }
// GetAll returns folders that the user can see. // GetAll returns spaces that the user can see.
// Also handles which folders can be seen by anonymous users. // Also handles which spaces can be seen by anonymous users.
func (s Scope) GetAll(ctx domain.RequestContext) (sp []space.Space, err error) { func (s Scope) GetAll(ctx domain.RequestContext) (sp []space.Space, err error) {
sql := ` sql := `
(SELECT id,refid,label as name,orgid,userid,type,created,revised from label WHERE orgid=? AND type=2 AND userid=?) (SELECT id,refid,label as name,orgid,userid,type,created,revised from label WHERE orgid=? AND type=2 AND userid=?)
UNION ALL UNION ALL
(SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1 AND refid in (SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1 AND refid in
(SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1))) (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)))
UNION ALL UNION ALL
(SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=3 AND refid in (SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=3 AND refid in
(SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1)))
ORDER BY name` ORDER BY name`
err = s.Runtime.Db.Select(&sp, sql, err = s.Runtime.Db.Select(&sp, sql,
ctx.OrgID, ctx.OrgID,
@ -156,22 +156,22 @@ func (s Scope) ChangeOwner(ctx domain.RequestContext, currentOwner, newOwner str
return return
} }
// Viewers returns the list of people who can see shared folders. // Viewers returns the list of people who can see shared spaces.
func (s Scope) Viewers(ctx domain.RequestContext) (v []space.Viewer, err error) { func (s Scope) Viewers(ctx domain.RequestContext) (v []space.Viewer, err error) {
sql := ` sql := `
SELECT a.userid, SELECT a.userid,
COALESCE(u.firstname, '') as firstname, COALESCE(u.firstname, '') as firstname,
COALESCE(u.lastname, '') as lastname, COALESCE(u.lastname, '') as lastname,
COALESCE(u.email, '') as email, COALESCE(u.email, '') as email,
a.labelid, a.labelid,
b.label as name, b.label as name,
b.type b.type
FROM labelrole a FROM labelrole a
LEFT JOIN label b ON b.refid=a.labelid LEFT JOIN label b ON b.refid=a.labelid
LEFT JOIN user u ON u.refid=a.userid LEFT JOIN user u ON u.refid=a.userid
WHERE a.orgid=? AND b.type != 2 WHERE a.orgid=? AND b.type != 2
GROUP BY a.labelid,a.userid GROUP BY a.labelid,a.userid
ORDER BY u.firstname,u.lastname` ORDER BY u.firstname,u.lastname`
err = s.Runtime.Db.Select(&v, sql, ctx.OrgID) err = s.Runtime.Db.Select(&v, sql, ctx.OrgID)

View file

@ -84,7 +84,7 @@ func InitRuntime(r *env.Runtime, s *domain.Store) bool {
} }
var stdParams = map[string]string{ var stdParams = map[string]string{
"charset": "utf8", "charset": "utf8mb4",
"parseTime": "True", "parseTime": "True",
"maxAllowedPacket": "4194304", // 4194304 // 16777216 = 16MB "maxAllowedPacket": "4194304", // 4194304 // 16777216 = 16MB
} }

View file

@ -13,8 +13,11 @@
package logging package logging
import ( import (
"bytes"
"fmt"
"log" "log"
"os" "os"
"runtime"
"github.com/documize/community/core/env" "github.com/documize/community/core/env"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -35,6 +38,14 @@ func (l Logger) Info(message string) {
func (l Logger) Error(message string, err error) { func (l Logger) Error(message string, err error) {
l.log.Println(message) l.log.Println(message)
l.log.Println(err) l.log.Println(err)
stack := make([]byte, 4096)
runtime.Stack(stack, false)
if idx := bytes.IndexByte(stack, 0); idx > 0 && idx < len(stack) {
stack = stack[:idx] // remove trailing nulls from stack dump
}
l.log.Println(fmt.Sprintf("%s", stack))
} }
// SetDB associates database connection with given logger. // SetDB associates database connection with given logger.

View file

@ -78,11 +78,11 @@ export default Ember.Component.extend(NotifierMixin, {
this.set('permissions', folderPermissions.sortBy('fullname')); this.set('permissions', folderPermissions.sortBy('fullname'));
}); });
}); });
}, },
getDefaultInvitationMessage() { getDefaultInvitationMessage() {
return "Hey there, I am sharing the " + this.get('folder.name') + " (in " + this.get("appMeta.title") + ") with you so we can both access the same documents."; return "Hey there, I am sharing the " + this.get('folder.name') + " space (in " + this.get("appMeta.title") + ") with you so we can both access the same documents.";
}, },
actions: { actions: {
@ -90,7 +90,7 @@ export default Ember.Component.extend(NotifierMixin, {
let message = this.getDefaultInvitationMessage(); let message = this.getDefaultInvitationMessage();
let folder = this.get('folder'); let folder = this.get('folder');
let permissions = this.get('permissions'); let permissions = this.get('permissions');
this.get('permissions').forEach((permission, index) => { // eslint-disable-line no-unused-vars this.get('permissions').forEach((permission, index) => { // eslint-disable-line no-unused-vars
Ember.set(permission, 'canView', $("#canView-" + permission.userId).prop('checked')); Ember.set(permission, 'canView', $("#canView-" + permission.userId).prop('checked'));
Ember.set(permission, 'canEdit', $("#canEdit-" + permission.userId).prop('checked')); Ember.set(permission, 'canEdit', $("#canEdit-" + permission.userId).prop('checked'));

View file

@ -23,7 +23,7 @@ export default Ember.Component.extend(NotifierMixin, {
inviteMessage: '', inviteMessage: '',
getDefaultInvitationMessage() { getDefaultInvitationMessage() {
return "Hey there, I am sharing the " + this.folder.get('name') + " (in " + this.get("appMeta.title") + ") with you so we can both access the same documents."; return "Hey there, I am sharing the " + this.folder.get('name') + " space (in " + this.get("appMeta.title") + ") with you so we can both access the same documents.";
}, },
willRender() { willRender() {

View file

@ -5,7 +5,7 @@
<thead> <thead>
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>View</th> <th>View&nbsp;</th>
<th>Edit</th> <th>Edit</th>
</tr> </tr>
</thead> </thead>

View file

@ -68,9 +68,11 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
method := "middleware.auth" method := "middleware.auth"
// Let certain requests pass straight through // Let certain requests pass straight through
authenticated := preAuthorizeStaticAssets(m.Runtime, r) authenticated, ctx := m.preAuthorizeStaticAssets(m.Runtime, r)
if authenticated {
if !authenticated { ctx2 := context.WithValue(r.Context(), domain.DocumizeContextKey, ctx)
r = r.WithContext(ctx2)
} else {
token := auth.FindJWT(r) token := auth.FindJWT(r)
rc, _, tokenErr := auth.DecodeJWT(m.Runtime, token) rc, _, tokenErr := auth.DecodeJWT(m.Runtime, token)
@ -195,7 +197,9 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
// Certain assets/URL do not require authentication. // Certain assets/URL do not require authentication.
// Just stops the log files being clogged up with failed auth errors. // Just stops the log files being clogged up with failed auth errors.
func preAuthorizeStaticAssets(rt *env.Runtime, r *http.Request) bool { func (m *middleware) preAuthorizeStaticAssets(rt *env.Runtime, r *http.Request) (auth bool, ctx domain.RequestContext) {
ctx = domain.RequestContext{}
if strings.ToLower(r.URL.Path) == "/" || if strings.ToLower(r.URL.Path) == "/" ||
strings.ToLower(r.URL.Path) == "/validate" || strings.ToLower(r.URL.Path) == "/validate" ||
strings.ToLower(r.URL.Path) == "/favicon.ico" || strings.ToLower(r.URL.Path) == "/favicon.ico" ||
@ -204,8 +208,27 @@ func preAuthorizeStaticAssets(rt *env.Runtime, r *http.Request) bool {
strings.HasPrefix(strings.ToLower(r.URL.Path), "/api/public/") || strings.HasPrefix(strings.ToLower(r.URL.Path), "/api/public/") ||
((rt.Flags.SiteMode == env.SiteModeSetup) && (strings.ToLower(r.URL.Path) == "/api/setup")) { ((rt.Flags.SiteMode == env.SiteModeSetup) && (strings.ToLower(r.URL.Path) == "/api/setup")) {
return true return true, ctx
} }
return false if strings.HasPrefix(strings.ToLower(r.URL.Path), "/api/public/") ||
((rt.Flags.SiteMode == env.SiteModeSetup) && (strings.ToLower(r.URL.Path) == "/api/setup")) {
dom := organization.GetRequestSubdomain(r)
dom = m.Store.Organization.CheckDomain(ctx, dom)
org, _ := m.Store.Organization.GetOrganizationByDomain(dom)
ctx.Subdomain = organization.GetSubdomainFromHost(r)
ctx.AllowAnonymousAccess = org.AllowAnonymousAccess
ctx.OrgName = org.Title
ctx.Administrator = false
ctx.Editor = false
ctx.Global = false
ctx.AppURL = r.Host
ctx.SSL = r.TLS != nil
return true, ctx
}
return false, ctx
} }