mirror of
https://github.com/documize/community.git
synced 2025-07-18 20:59:43 +02:00
moving endpoints to new API (WIP)
This commit is contained in:
parent
27640dffc4
commit
72b14def6d
36 changed files with 1371 additions and 472 deletions
|
@ -718,7 +718,7 @@ func ResetUserPassword(w http.ResponseWriter, r *http.Request) {
|
|||
log.IfErr(err)
|
||||
}
|
||||
|
||||
// Get user object contain associated accounts but credentials are wiped.
|
||||
// GetSecuredUser wipes credentials.
|
||||
func GetSecuredUser(p request.Persister, orgID, user string) (u entity.User, err error) {
|
||||
u, err = p.GetUser(user)
|
||||
AttachUserAccounts(p, orgID, &u)
|
||||
|
@ -726,6 +726,7 @@ func GetSecuredUser(p request.Persister, orgID, user string) (u entity.User, err
|
|||
return
|
||||
}
|
||||
|
||||
// AttachUserAccounts ...
|
||||
func AttachUserAccounts(p request.Persister, orgID string, user *entity.User) {
|
||||
user.ProtectSecrets()
|
||||
a, err := p.GetUserAccounts(user.RefID)
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package request provides HTTP request parsing functions.
|
||||
package request
|
12
domain/account/endpoint.go
Normal file
12
domain/account/endpoint.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package account
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
Store domain.Store
|
||||
}
|
|
@ -1,22 +1,40 @@
|
|||
package account
|
||||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/store/mysql"
|
||||
"github.com/documize/community/model/account"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// Add inserts the given record into the datbase account table.
|
||||
func Add(s domain.StoreContext, account Account) (err error) {
|
||||
func (s Scope) Add(ctx domain.RequestContext, account account.Account) (err error) {
|
||||
account.Created = time.Now().UTC()
|
||||
account.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO account (refid, orgid, userid, admin, editor, active, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO account (refid, orgid, userid, admin, editor, active, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -35,7 +53,7 @@ func Add(s domain.StoreContext, account Account) (err error) {
|
|||
}
|
||||
|
||||
// GetUserAccount returns the database account record corresponding to the given userID, using the client's current organizaion.
|
||||
func GetUserAccount(s domain.StoreContext, userID string) (account Account, err error) {
|
||||
func (s Scope) GetUserAccount(ctx domain.RequestContext, userID string) (account account.Account, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT a.*, b.company, b.title, b.message, b.domain FROM account a, organization b WHERE b.refid=a.orgid and a.orgid=? and a.userid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -44,7 +62,7 @@ func GetUserAccount(s domain.StoreContext, userID string) (account Account, err
|
|||
return
|
||||
}
|
||||
|
||||
err = stmt.Get(&account, s.Context.OrgID, userID)
|
||||
err = stmt.Get(&account, ctx.OrgID, userID)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute select for account by user %s", userID))
|
||||
return
|
||||
|
@ -54,7 +72,7 @@ func GetUserAccount(s domain.StoreContext, userID string) (account Account, err
|
|||
}
|
||||
|
||||
// GetUserAccounts returns a slice of database account records, for all organizations that the userID is a member of, in organization title order.
|
||||
func GetUserAccounts(s domain.StoreContext, userID string) (t []Account, err error) {
|
||||
func (s Scope) GetUserAccounts(ctx domain.RequestContext, userID string) (t []account.Account, err error) {
|
||||
err = s.Runtime.Db.Select(&t, "SELECT a.*, b.company, b.title, b.message, b.domain FROM account a, organization b WHERE a.userid=? AND a.orgid=b.refid AND a.active=1 ORDER BY b.title", userID)
|
||||
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
|
@ -65,19 +83,19 @@ func GetUserAccounts(s domain.StoreContext, userID string) (t []Account, err err
|
|||
}
|
||||
|
||||
// GetAccountsByOrg returns a slice of database account records, for all users in the client's organization.
|
||||
func GetAccountsByOrg(s domain.StoreContext) (t []Account, err error) {
|
||||
err = s.Runtime.Db.Select(&t, "SELECT a.*, b.company, b.title, b.message, b.domain FROM account a, organization b WHERE a.orgid=b.refid AND a.orgid=? AND a.active=1", s.Context.OrgID)
|
||||
func (s Scope) GetAccountsByOrg(ctx domain.RequestContext) (t []account.Account, err error) {
|
||||
err = s.Runtime.Db.Select(&t, "SELECT a.*, b.company, b.title, b.message, b.domain FROM account a, organization b WHERE a.orgid=b.refid AND a.orgid=? AND a.active=1", ctx.OrgID)
|
||||
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute select account for org %s", s.Context.OrgID))
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute select account for org %s", ctx.OrgID))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CountOrgAccounts returns the numnber of active user accounts for specified organization.
|
||||
func CountOrgAccounts(s domain.StoreContext) (c int) {
|
||||
row := s.Runtime.Db.QueryRow("SELECT count(*) FROM account WHERE orgid=? AND active=1", s.Context.OrgID)
|
||||
func (s Scope) CountOrgAccounts(ctx domain.RequestContext) (c int) {
|
||||
row := s.Runtime.Db.QueryRow("SELECT count(*) FROM account WHERE orgid=? AND active=1", ctx.OrgID)
|
||||
|
||||
err := row.Scan(&c)
|
||||
|
||||
|
@ -94,10 +112,10 @@ func CountOrgAccounts(s domain.StoreContext) (c int) {
|
|||
}
|
||||
|
||||
// UpdateAccount updates the database record for the given account to the given values.
|
||||
func UpdateAccount(s domain.StoreContext, account Account) (err error) {
|
||||
func (s Scope) UpdateAccount(ctx domain.RequestContext, account account.Account) (err error) {
|
||||
account.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.PrepareNamed("UPDATE account SET userid=:userid, admin=:admin, editor=:editor, active=:active, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
stmt, err := ctx.Transaction.PrepareNamed("UPDATE account SET userid=:userid, admin=:admin, editor=:editor, active=:active, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -115,7 +133,7 @@ func UpdateAccount(s domain.StoreContext, account Account) (err error) {
|
|||
}
|
||||
|
||||
// HasOrgAccount returns if the given orgID has valid userID.
|
||||
func HasOrgAccount(s domain.StoreContext, orgID, userID string) bool {
|
||||
func (s Scope) HasOrgAccount(ctx domain.RequestContext, orgID, userID string) bool {
|
||||
row := s.Runtime.Db.QueryRow("SELECT count(*) FROM account WHERE orgid=? and userid=?", orgID, userID)
|
||||
|
||||
var count int
|
||||
|
@ -138,7 +156,7 @@ func HasOrgAccount(s domain.StoreContext, orgID, userID string) bool {
|
|||
}
|
||||
|
||||
// DeleteAccount deletes the database record in the account table for user ID.
|
||||
func DeleteAccount(s domain.StoreContext, ID string) (rows int64, err error) {
|
||||
func (s Scope) DeleteAccount(ctx domain.RequestContext, ID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.DeleteConstrained(s.Context.Transaction, "account", s.Context.OrgID, ID)
|
||||
return b.DeleteConstrained(ctx.Transaction, "account", ctx.OrgID, ID)
|
||||
}
|
|
@ -9,23 +9,30 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package eventing records user events.
|
||||
package eventing
|
||||
// Package audit records user events.
|
||||
package audit
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/model/audit"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// Record adds event entry for specified user.
|
||||
func Record(s domain.StoreContext, t EventType) {
|
||||
e := AppEvent{}
|
||||
e.OrgID = s.Context.OrgID
|
||||
e.UserID = s.Context.UserID
|
||||
func (s Scope) Record(ctx domain.RequestContext, t audit.EventType) {
|
||||
e := audit.AppEvent{}
|
||||
e.OrgID = ctx.OrgID
|
||||
e.UserID = ctx.UserID
|
||||
e.Created = time.Now().UTC()
|
||||
e.IP = s.Context.ClientIP
|
||||
e.IP = ctx.ClientIP
|
||||
e.Type = string(t)
|
||||
|
||||
tx, err := s.Runtime.Db.Beginx()
|
|
@ -11,20 +11,7 @@
|
|||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/documize/community/core/response"
|
||||
"github.com/documize/community/core/secrets"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/organization"
|
||||
"github.com/documize/community/domain/section/provider"
|
||||
"github.com/documize/community/domain/user"
|
||||
)
|
||||
|
||||
/*
|
||||
// Authenticate user based up HTTP Authorization header.
|
||||
// An encrypted authentication token is issued with an expiry date.
|
||||
func (h *Handler) Authenticate(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -205,3 +192,4 @@ func (h *Handler) ValidateAuthToken(w http.ResponseWriter, r *http.Request) {
|
|||
response.WriteJSON(w, u)
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -11,11 +11,7 @@
|
|||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain/user"
|
||||
)
|
||||
|
||||
/*
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
|
@ -26,3 +22,4 @@ type AuthenticationModel struct {
|
|||
Token string `json:"token"`
|
||||
User user.User `json:"user"`
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package domain defines data structures for moving data between services.
|
||||
package domain
|
||||
|
||||
import (
|
||||
|
@ -5,7 +17,6 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
|
@ -51,13 +62,13 @@ func GetRequestContext(r *http.Request) RequestContext {
|
|||
return r.Context().Value(DocumizeContextKey).(RequestContext)
|
||||
}
|
||||
|
||||
// StoreContext provides data persistence methods with runtime and request context.
|
||||
type StoreContext struct {
|
||||
Runtime *env.Runtime
|
||||
Context RequestContext
|
||||
}
|
||||
// // Scope provides data persistence methods with runtime and request context.
|
||||
// type Scope struct {
|
||||
// Runtime *env.Runtime
|
||||
// Context RequestContext
|
||||
// }
|
||||
|
||||
// NewContext returns request scoped user context and store context for persistence logic.
|
||||
func NewContext(rt *env.Runtime, r *http.Request) StoreContext {
|
||||
return StoreContext{Runtime: rt, Context: GetRequestContext(r)}
|
||||
}
|
||||
// // 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)}
|
||||
// }
|
||||
|
|
|
@ -14,14 +14,20 @@ package document
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// MoveDocumentSpace changes the label for client's organization's documents which have space "id", to "move".
|
||||
func MoveDocumentSpace(s domain.StoreContext, id, move string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE document SET labelid=? WHERE orgid=? AND labelid=?")
|
||||
func (s Scope) MoveDocumentSpace(ctx domain.RequestContext, id, move string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE document SET labelid=? WHERE orgid=? AND labelid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -29,7 +35,7 @@ func MoveDocumentSpace(s domain.StoreContext, id, move string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(move, s.Context.OrgID, id)
|
||||
_, err = stmt.Exec(move, ctx.OrgID, id)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute document space move %s", id))
|
||||
return
|
94
domain/organization/endpoint.go
Normal file
94
domain/organization/endpoint.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package organization
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/request"
|
||||
"github.com/documize/community/core/response"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/model/org"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
Store *domain.Store
|
||||
}
|
||||
|
||||
// Get returns the requested organization.
|
||||
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
method := "org.Get"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
orgID := request.Param(r, "orgID")
|
||||
|
||||
if orgID != ctx.OrgID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
org, err := h.Store.Organization.GetOrganization(ctx, ctx.OrgID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteJSON(w, org)
|
||||
}
|
||||
|
||||
// Update saves organization amends.
|
||||
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
method := "org.Update"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !ctx.Administrator {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
var org = org.Organization{}
|
||||
err = json.Unmarshal(body, &org)
|
||||
|
||||
org.RefID = ctx.OrgID
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.Store.Organization.UpdateOrganization(ctx, org)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteJSON(w, org)
|
||||
}
|
|
@ -21,16 +21,22 @@ import (
|
|||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/store/mysql"
|
||||
"github.com/documize/community/model/org"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// AddOrganization inserts the passed organization record into the organization table.
|
||||
func AddOrganization(s domain.StoreContext, org Organization) error {
|
||||
func (s Scope) AddOrganization(ctx domain.RequestContext, org org.Organization) error {
|
||||
org.Created = time.Now().UTC()
|
||||
org.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex(
|
||||
stmt, err := ctx.Transaction.Preparex(
|
||||
"INSERT INTO organization (refid, company, title, message, url, domain, email, allowanonymousaccess, serial, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -51,7 +57,7 @@ func AddOrganization(s domain.StoreContext, org Organization) error {
|
|||
}
|
||||
|
||||
// GetOrganization returns the Organization reocrod from the organization database table with the given id.
|
||||
func GetOrganization(s domain.StoreContext, id string) (org Organization, err error) {
|
||||
func (s Scope) GetOrganization(ctx domain.RequestContext, id string) (org org.Organization, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, company, title, message, url, domain, service as conversionendpoint, email, serial, active, allowanonymousaccess, authprovider, coalesce(authconfig,JSON_UNQUOTE('{}')) as authconfig, created, revised FROM organization WHERE refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -71,7 +77,7 @@ func GetOrganization(s domain.StoreContext, id string) (org Organization, err er
|
|||
}
|
||||
|
||||
// GetOrganizationByDomain returns the organization matching a given URL subdomain.
|
||||
func GetOrganizationByDomain(s domain.StoreContext, subdomain string) (org Organization, err error) {
|
||||
func (s Scope) GetOrganizationByDomain(ctx domain.RequestContext, subdomain string) (org org.Organization, err error) {
|
||||
err = nil
|
||||
subdomain = strings.ToLower(subdomain)
|
||||
|
||||
|
@ -98,10 +104,10 @@ func GetOrganizationByDomain(s domain.StoreContext, subdomain string) (org Organ
|
|||
}
|
||||
|
||||
// UpdateOrganization updates the given organization record in the database to the values supplied.
|
||||
func UpdateOrganization(s domain.StoreContext, org Organization) (err error) {
|
||||
func (s Scope) UpdateOrganization(ctx domain.RequestContext, org org.Organization) (err error) {
|
||||
org.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.PrepareNamed("UPDATE organization SET title=:title, message=:message, service=:conversionendpoint, email=:email, allowanonymousaccess=:allowanonymousaccess, revised=:revised WHERE refid=:refid")
|
||||
stmt, err := ctx.Transaction.PrepareNamed("UPDATE organization SET title=:title, message=:message, service=:conversionendpoint, email=:email, allowanonymousaccess=:allowanonymousaccess, revised=:revised WHERE refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -119,14 +125,14 @@ func UpdateOrganization(s domain.StoreContext, org Organization) (err error) {
|
|||
}
|
||||
|
||||
// DeleteOrganization deletes the orgID organization from the organization table.
|
||||
func DeleteOrganization(s domain.StoreContext, orgID string) (rows int64, err error) {
|
||||
func (s Scope) DeleteOrganization(ctx domain.RequestContext, orgID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.Delete(s.Context.Transaction, "organization", orgID)
|
||||
return b.Delete(ctx.Transaction, "organization", orgID)
|
||||
}
|
||||
|
||||
// RemoveOrganization sets the orgID organization to be inactive, thus executing a "soft delete" operation.
|
||||
func RemoveOrganization(s domain.StoreContext, rc domain.RequestContext, orgID string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE organization SET active=0 WHERE refid=?")
|
||||
func (s Scope) RemoveOrganization(ctx domain.RequestContext, orgID string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE organization SET active=0 WHERE refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -144,10 +150,10 @@ func RemoveOrganization(s domain.StoreContext, rc domain.RequestContext, orgID s
|
|||
}
|
||||
|
||||
// UpdateAuthConfig updates the given organization record in the database with the auth config details.
|
||||
func UpdateAuthConfig(s domain.StoreContext, org Organization) (err error) {
|
||||
func (s Scope) UpdateAuthConfig(ctx domain.RequestContext, org org.Organization) (err error) {
|
||||
org.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.PrepareNamed("UPDATE organization SET allowanonymousaccess=:allowanonymousaccess, authprovider=:authprovider, authconfig=:authconfig, revised=:revised WHERE refid=:refid")
|
||||
stmt, err := ctx.Transaction.PrepareNamed("UPDATE organization SET allowanonymousaccess=:allowanonymousaccess, authprovider=:authprovider, authconfig=:authconfig, revised=:revised WHERE refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -165,7 +171,7 @@ func UpdateAuthConfig(s domain.StoreContext, org Organization) (err error) {
|
|||
}
|
||||
|
||||
// CheckDomain makes sure there is an organisation with the correct domain
|
||||
func CheckDomain(s domain.StoreContext, domain string) string {
|
||||
func (s Scope) CheckDomain(ctx domain.RequestContext, domain string) string {
|
||||
row := s.Runtime.Db.QueryRow("SELECT COUNT(*) FROM organization WHERE domain=? AND active=1", domain)
|
||||
|
||||
var count int
|
|
@ -14,22 +14,19 @@ package organization
|
|||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// GetRequestSubdomain extracts subdomain from referring URL.
|
||||
func GetRequestSubdomain(s domain.StoreContext, r *http.Request) string {
|
||||
return urlSubdomain(s, r.Referer())
|
||||
func GetRequestSubdomain(r *http.Request) string {
|
||||
return urlSubdomain(r.Referer())
|
||||
}
|
||||
|
||||
// GetSubdomainFromHost extracts the subdomain from the requesting URL.
|
||||
func GetSubdomainFromHost(s domain.StoreContext, r *http.Request) string {
|
||||
return urlSubdomain(s, r.Host)
|
||||
func GetSubdomainFromHost(r *http.Request) string {
|
||||
return urlSubdomain(r.Host)
|
||||
}
|
||||
|
||||
// Find the subdomain (which is actually the organisation).
|
||||
func urlSubdomain(s domain.StoreContext, url string) string {
|
||||
func urlSubdomain(url string) string {
|
||||
url = strings.ToLower(url)
|
||||
url = strings.Replace(url, "https://", "", 1)
|
||||
url = strings.Replace(url, "http://", "", 1)
|
||||
|
@ -42,5 +39,5 @@ func urlSubdomain(s domain.StoreContext, url string) string {
|
|||
url = ""
|
||||
}
|
||||
|
||||
return CheckDomain(s, url)
|
||||
return url
|
||||
}
|
||||
|
|
|
@ -18,17 +18,25 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/request"
|
||||
"github.com/documize/community/core/response"
|
||||
"github.com/documize/community/core/uniqueid"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/eventing"
|
||||
"github.com/documize/community/model/audit"
|
||||
"github.com/documize/community/model/pin"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
Store *domain.Store
|
||||
}
|
||||
|
||||
// Add saves pinned item.
|
||||
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||
method := "pin.Add"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
userID := request.Param(r, "userID")
|
||||
if len(userID) == 0 {
|
||||
|
@ -41,7 +49,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !s.Context.Authenticated {
|
||||
if !ctx.Authenticated {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -53,7 +61,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var pin Pin
|
||||
var pin pin.Pin
|
||||
err = json.Unmarshal(body, &pin)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "pin")
|
||||
|
@ -61,31 +69,31 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
pin.RefID = uniqueid.Generate()
|
||||
pin.OrgID = s.Context.OrgID
|
||||
pin.UserID = s.Context.UserID
|
||||
pin.OrgID = ctx.OrgID
|
||||
pin.UserID = ctx.UserID
|
||||
pin.Pin = strings.TrimSpace(pin.Pin)
|
||||
if len(pin.Pin) > 20 {
|
||||
pin.Pin = pin.Pin[0:20]
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = Add(s, pin)
|
||||
err = h.Store.Pin.Add(ctx, pin)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypePinAdd)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypePinAdd)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
newPin, err := GetPin(s, pin.RefID)
|
||||
newPin, err := h.Store.Pin.GetPin(ctx, pin.RefID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
|
@ -97,7 +105,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
// GetUserPins returns users' pins.
|
||||
func (h *Handler) GetUserPins(w http.ResponseWriter, r *http.Request) {
|
||||
method := "pin.GetUserPins"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
userID := request.Param(r, "userID")
|
||||
if len(userID) == 0 {
|
||||
|
@ -105,19 +113,19 @@ func (h *Handler) GetUserPins(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !s.Context.Authenticated {
|
||||
if !ctx.Authenticated {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
pins, err := GetUserPins(s, userID)
|
||||
pins, err := h.Store.Pin.GetUserPins(ctx, userID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
pins = []Pin{}
|
||||
pins = []pin.Pin{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, pins)
|
||||
|
@ -126,7 +134,7 @@ func (h *Handler) GetUserPins(w http.ResponseWriter, r *http.Request) {
|
|||
// DeleteUserPin removes saved user pin.
|
||||
func (h *Handler) DeleteUserPin(w http.ResponseWriter, r *http.Request) {
|
||||
method := "pin.DeleteUserPin"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
userID := request.Param(r, "userID")
|
||||
if len(userID) == 0 {
|
||||
|
@ -145,28 +153,28 @@ func (h *Handler) DeleteUserPin(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if s.Context.UserID != userID {
|
||||
if ctx.UserID != userID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = DeletePin(s, pinID)
|
||||
_, err = h.Store.Pin.DeletePin(ctx, pinID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypePinDelete)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypePinDelete)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
@ -174,7 +182,7 @@ func (h *Handler) DeleteUserPin(w http.ResponseWriter, r *http.Request) {
|
|||
// UpdatePinSequence records order of pinned items.
|
||||
func (h *Handler) UpdatePinSequence(w http.ResponseWriter, r *http.Request) {
|
||||
method := "pin.DeleteUserPin"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
userID := request.Param(r, "userID")
|
||||
if len(userID) == 0 {
|
||||
|
@ -187,7 +195,7 @@ func (h *Handler) UpdatePinSequence(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !s.Context.Authenticated {
|
||||
if !ctx.Authenticated {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -207,26 +215,26 @@ func (h *Handler) UpdatePinSequence(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range pins {
|
||||
err = UpdatePinSequence(s, v, k+1)
|
||||
err = h.Store.Pin.UpdatePinSequence(ctx, v, k+1)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypePinResequence)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypePinResequence)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
newPins, err := GetUserPins(s, userID)
|
||||
newPins, err := h.Store.Pin.GetUserPins(ctx, userID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
|
|
|
@ -15,17 +15,23 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/api/entity"
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/store/mysql"
|
||||
"github.com/documize/community/model/pin"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// Add saves pinned item.
|
||||
func Add(s domain.StoreContext, pin Pin) (err error) {
|
||||
row := s.Runtime.Db.QueryRow("SELECT max(sequence) FROM pin WHERE orgid=? AND userid=?", s.Context.OrgID, s.Context.UserID)
|
||||
func (s Scope) Add(ctx domain.RequestContext, pin pin.Pin) (err error) {
|
||||
row := s.Runtime.Db.QueryRow("SELECT max(sequence) FROM pin WHERE orgid=? AND userid=?", ctx.OrgID, ctx.UserID)
|
||||
var maxSeq int
|
||||
err = row.Scan(&maxSeq)
|
||||
|
||||
|
@ -37,7 +43,7 @@ func Add(s domain.StoreContext, pin Pin) (err error) {
|
|||
pin.Revised = time.Now().UTC()
|
||||
pin.Sequence = maxSeq + 1
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO pin (refid, orgid, userid, labelid, documentid, pin, sequence, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO pin (refid, orgid, userid, labelid, documentid, pin, sequence, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -55,7 +61,7 @@ func Add(s domain.StoreContext, pin Pin) (err error) {
|
|||
}
|
||||
|
||||
// GetPin returns requested pinned item.
|
||||
func GetPin(s domain.StoreContext, id string) (pin Pin, err error) {
|
||||
func (s Scope) GetPin(ctx domain.RequestContext, id string) (pin pin.Pin, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -64,7 +70,7 @@ func GetPin(s domain.StoreContext, id string) (pin Pin, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
err = stmt.Get(&pin, s.Context.OrgID, id)
|
||||
err = stmt.Get(&pin, ctx.OrgID, id)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute select for pin %s", id))
|
||||
return
|
||||
|
@ -74,11 +80,11 @@ func GetPin(s domain.StoreContext, id string) (pin Pin, err error) {
|
|||
}
|
||||
|
||||
// GetUserPins returns pinned items for specified user.
|
||||
func GetUserPins(s domain.StoreContext, userID string) (pins []Pin, err error) {
|
||||
err = s.Runtime.Db.Select(&pins, "SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND userid=? ORDER BY sequence", s.Context.OrgID, userID)
|
||||
func (s Scope) GetUserPins(ctx domain.RequestContext, userID string) (pins []pin.Pin, err error) {
|
||||
err = s.Runtime.Db.Select(&pins, "SELECT id, refid, orgid, userid, labelid as folderid, documentid, pin, sequence, created, revised FROM pin WHERE orgid=? AND userid=? ORDER BY sequence", ctx.OrgID, userID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute select pins for org %s and user %s", s.Context.OrgID, userID))
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute select pins for org %s and user %s", ctx.OrgID, userID))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -86,11 +92,11 @@ func GetUserPins(s domain.StoreContext, userID string) (pins []Pin, err error) {
|
|||
}
|
||||
|
||||
// UpdatePin updates existing pinned item.
|
||||
func UpdatePin(s domain.StoreContext, pin entity.Pin) (err error) {
|
||||
func (s Scope) UpdatePin(ctx domain.RequestContext, pin pin.Pin) (err error) {
|
||||
pin.Revised = time.Now().UTC()
|
||||
|
||||
var stmt *sqlx.NamedStmt
|
||||
stmt, err = s.Context.Transaction.PrepareNamed("UPDATE pin SET labelid=:folderid, documentid=:documentid, pin=:pin, sequence=:sequence, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
stmt, err = ctx.Transaction.PrepareNamed("UPDATE pin SET labelid=:folderid, documentid=:documentid, pin=:pin, sequence=:sequence, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -108,8 +114,8 @@ func UpdatePin(s domain.StoreContext, pin entity.Pin) (err error) {
|
|||
}
|
||||
|
||||
// UpdatePinSequence updates existing pinned item sequence number
|
||||
func UpdatePinSequence(s domain.StoreContext, pinID string, sequence int) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE pin SET sequence=?, revised=? WHERE orgid=? AND userid=? AND refid=?")
|
||||
func (s Scope) UpdatePinSequence(ctx domain.RequestContext, pinID string, sequence int) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE pin SET sequence=?, revised=? WHERE orgid=? AND userid=? AND refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -117,7 +123,7 @@ func UpdatePinSequence(s domain.StoreContext, pinID string, sequence int) (err e
|
|||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(sequence, time.Now().UTC(), s.Context.OrgID, s.Context.UserID, pinID)
|
||||
_, err = stmt.Exec(sequence, time.Now().UTC(), ctx.OrgID, ctx.UserID, pinID)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute pin sequence update %s", pinID))
|
||||
return
|
||||
|
@ -127,19 +133,19 @@ func UpdatePinSequence(s domain.StoreContext, pinID string, sequence int) (err e
|
|||
}
|
||||
|
||||
// DeletePin removes folder from the store.
|
||||
func DeletePin(s domain.StoreContext, id string) (rows int64, err error) {
|
||||
func (s Scope) DeletePin(ctx domain.RequestContext, id string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.DeleteConstrained(s.Context.Transaction, "pin", s.Context.OrgID, id)
|
||||
return b.DeleteConstrained(ctx.Transaction, "pin", ctx.OrgID, id)
|
||||
}
|
||||
|
||||
// DeletePinnedSpace removes any pins for specified space.
|
||||
func DeletePinnedSpace(s domain.StoreContext, spaceID string) (rows int64, err error) {
|
||||
func (s Scope) DeletePinnedSpace(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.DeleteWhere(s.Context.Transaction, fmt.Sprintf("DELETE FROM pin WHERE orgid=\"%s\" AND labelid=\"%s\"", s.Context.OrgID, spaceID))
|
||||
return b.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM pin WHERE orgid=\"%s\" AND labelid=\"%s\"", ctx.OrgID, spaceID))
|
||||
}
|
||||
|
||||
// DeletePinnedDocument removes any pins for specified document.
|
||||
func DeletePinnedDocument(s domain.StoreContext, documentID string) (rows int64, err error) {
|
||||
func (s Scope) DeletePinnedDocument(ctx domain.RequestContext, documentID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.DeleteWhere(s.Context.Transaction, fmt.Sprintf("DELETE FROM pin WHERE orgid=\"%s\" AND documentid=\"%s\"", s.Context.OrgID, documentID))
|
||||
return b.DeleteWhere(ctx.Transaction, fmt.Sprintf("DELETE FROM pin WHERE orgid=\"%s\" AND documentid=\"%s\"", ctx.OrgID, documentID))
|
||||
}
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/documize/api/wordsmith/log"
|
||||
"github.com/documize/community/core/api/mail"
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/request"
|
||||
"github.com/documize/community/core/response"
|
||||
"github.com/documize/community/core/secrets"
|
||||
|
@ -30,25 +31,29 @@ import (
|
|||
"github.com/documize/community/core/stringutil"
|
||||
"github.com/documize/community/core/uniqueid"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/account"
|
||||
"github.com/documize/community/domain/document"
|
||||
"github.com/documize/community/domain/eventing"
|
||||
"github.com/documize/community/domain/organization"
|
||||
"github.com/documize/community/domain/pin"
|
||||
"github.com/documize/community/domain/user"
|
||||
"github.com/documize/community/model/account"
|
||||
"github.com/documize/community/model/audit"
|
||||
"github.com/documize/community/model/space"
|
||||
"github.com/documize/community/model/user"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
Store *domain.Store
|
||||
}
|
||||
|
||||
// Add creates a new space.
|
||||
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||
method := "AddSpace"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
method := "space.Add"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !s.Context.Editor {
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -60,7 +65,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var space = Space{}
|
||||
var space = space.Space{}
|
||||
err = json.Unmarshal(body, &space)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
|
@ -72,27 +77,27 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
space.RefID = uniqueid.Generate()
|
||||
space.OrgID = s.Context.OrgID
|
||||
space.OrgID = ctx.OrgID
|
||||
|
||||
err = addSpace(s, space)
|
||||
err = h.Store.Space.Add(ctx, space)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceAdd)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceAdd)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
space, _ = Get(s, space.RefID)
|
||||
space, _ = h.Store.Space.Get(ctx, space.RefID)
|
||||
|
||||
response.WriteJSON(w, space)
|
||||
}
|
||||
|
@ -100,7 +105,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
|||
// Get returns the requested space.
|
||||
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
method := "Get"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
if len(id) == 0 {
|
||||
|
@ -108,7 +113,7 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
sp, err := Get(s, id)
|
||||
sp, err := h.Store.Space.Get(ctx, id)
|
||||
if err == sql.ErrNoRows {
|
||||
response.WriteNotFoundError(w, method, id)
|
||||
return
|
||||
|
@ -124,16 +129,16 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
|||
// GetAll returns spaces the user can see.
|
||||
func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
|
||||
method := "GetAll"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
sp, err := GetAll(s)
|
||||
sp, err := h.Store.Space.GetAll(ctx)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(sp) == 0 {
|
||||
sp = []Space{}
|
||||
sp = []space.Space{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, sp)
|
||||
|
@ -141,17 +146,17 @@ func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// GetSpaceViewers returns the users that can see the shared spaces.
|
||||
func (h *Handler) GetSpaceViewers(w http.ResponseWriter, r *http.Request) {
|
||||
method := "GetSpaceViewers"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
method := "space.Viewers"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
v, err := Viewers(s)
|
||||
v, err := h.Store.Space.Viewers(ctx)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(v) == 0 {
|
||||
v = []Viewer{}
|
||||
v = []space.Viewer{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, v)
|
||||
|
@ -160,9 +165,9 @@ func (h *Handler) GetSpaceViewers(w http.ResponseWriter, r *http.Request) {
|
|||
// Update processes request to save space object to the database
|
||||
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Update"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !s.Context.Editor {
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -180,7 +185,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var sp Space
|
||||
var sp space.Space
|
||||
err = json.Unmarshal(body, &sp)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "marshal")
|
||||
|
@ -194,22 +199,22 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
sp.RefID = folderID
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = Update(s, sp)
|
||||
err = h.Store.Space.Update(ctx, sp)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceUpdate)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceUpdate)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteJSON(w, sp)
|
||||
}
|
||||
|
@ -217,68 +222,68 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|||
// Remove moves documents to another folder before deleting it
|
||||
func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Remove"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !s.Context.Editor {
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
move := request.Param(r, "moveToId")
|
||||
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
move := request.Param(r, "moveToId")
|
||||
if len(move) == 0 {
|
||||
response.WriteMissingDataError(w, method, "moveToId")
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Delete(s, id)
|
||||
_, err = h.Store.Space.Delete(ctx, id)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = document.MoveDocumentSpace(s, id, move)
|
||||
err = h.Store.Document.MoveDocumentSpace(ctx, id, move)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = MoveSpaceRoles(s, id, move)
|
||||
err = h.Store.Space.MoveSpaceRoles(ctx, id, move)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = pin.DeletePinnedSpace(s, id)
|
||||
_, err = h.Store.Pin.DeletePinnedSpace(ctx, id)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceDelete)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceDelete)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
@ -286,14 +291,14 @@ func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
|||
// Delete deletes empty space.
|
||||
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Delete"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !s.Context.Editor {
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -305,45 +310,46 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
var err error
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Delete(s, id)
|
||||
_, err = h.Store.Space.Delete(ctx, id)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = DeleteSpaceRoles(s, id)
|
||||
_, err = h.Store.Space.DeleteSpaceRoles(ctx, id)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = pin.DeletePinnedSpace(s, id)
|
||||
_, err = h.Store.Pin.DeletePinnedSpace(ctx, id)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceDelete)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceDelete)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// SetPermissions persists specified spac3 permissions
|
||||
func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.SetPermissions"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !s.Context.Editor {
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -354,13 +360,13 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
sp, err := Get(s, id)
|
||||
sp, err := h.Store.Space.Get(ctx, id)
|
||||
if err != nil {
|
||||
response.WriteNotFoundError(w, method, "No such space")
|
||||
return
|
||||
}
|
||||
|
||||
if sp.UserID != s.Context.UserID {
|
||||
if sp.UserID != ctx.UserID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -372,14 +378,14 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var model = RolesModel{}
|
||||
var model = space.RolesModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
|
@ -387,9 +393,9 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// We compare new permisions to what we had before.
|
||||
// Why? So we can send out folder invitation emails.
|
||||
previousRoles, err := GetRoles(s, id)
|
||||
previousRoles, err := h.Store.Space.GetRoles(ctx, id)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
@ -402,17 +408,17 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// Who is sharing this folder?
|
||||
inviter, err := user.Get(s, s.Context.UserID)
|
||||
inviter, err := h.Store.User.Get(ctx, ctx.UserID)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Nuke all previous permissions for this folder
|
||||
_, err = DeleteSpaceRoles(s, id)
|
||||
_, err = h.Store.Space.DeleteSpaceRoles(ctx, id)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
@ -421,14 +427,14 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
hasEveryoneRole := false
|
||||
roleCount := 0
|
||||
|
||||
url := s.Context.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
|
||||
for _, role := range model.Roles {
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.OrgID = ctx.OrgID
|
||||
role.LabelID = id
|
||||
|
||||
// Ensure the folder owner always has access!
|
||||
if role.UserID == s.Context.UserID {
|
||||
if role.UserID == ctx.UserID {
|
||||
me = true
|
||||
role.CanView = true
|
||||
role.CanEdit = true
|
||||
|
@ -442,7 +448,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
if role.CanView || role.CanEdit {
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
err = AddRole(s, role)
|
||||
err = h.Store.Space.AddRole(ctx, role)
|
||||
roleCount++
|
||||
log.IfErr(err)
|
||||
|
||||
|
@ -453,7 +459,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
// we skip 'everyone' (user id != empty string)
|
||||
if len(role.UserID) > 0 {
|
||||
var existingUser user.User
|
||||
existingUser, err = user.Get(s, role.UserID)
|
||||
existingUser, err = h.Store.User.Get(ctx, role.UserID)
|
||||
|
||||
if err == nil {
|
||||
go mail.ShareFolderExistingUser(existingUser.Email, inviter.Fullname(), url, sp.Name, model.Message)
|
||||
|
@ -468,18 +474,18 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Do we need to ensure permissions for space owner when shared?
|
||||
if !me {
|
||||
role := Role{}
|
||||
role := space.Role{}
|
||||
role.LabelID = id
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.UserID = s.Context.UserID
|
||||
role.OrgID = ctx.OrgID
|
||||
role.UserID = ctx.UserID
|
||||
role.CanEdit = true
|
||||
role.CanView = true
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
|
||||
err = AddRole(s, role)
|
||||
err = h.Store.Space.AddRole(ctx, role)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
@ -487,25 +493,25 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Mark up folder type as either public, private or restricted access.
|
||||
if hasEveryoneRole {
|
||||
sp.Type = ScopePublic
|
||||
sp.Type = space.ScopePublic
|
||||
} else {
|
||||
if roleCount > 1 {
|
||||
sp.Type = ScopeRestricted
|
||||
sp.Type = space.ScopeRestricted
|
||||
} else {
|
||||
sp.Type = ScopePrivate
|
||||
sp.Type = space.ScopePrivate
|
||||
}
|
||||
}
|
||||
|
||||
err = Update(s, sp)
|
||||
err = h.Store.Space.Update(ctx, sp)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpacePermission)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpacePermission)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
@ -513,7 +519,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
// GetPermissions returns user permissions for the requested folder.
|
||||
func (h *Handler) GetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.GetPermissions"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
folderID := request.Param(r, "folderID")
|
||||
if len(folderID) == 0 {
|
||||
|
@ -521,14 +527,14 @@ func (h *Handler) GetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
roles, err := GetRoles(s, folderID)
|
||||
roles, err := h.Store.Space.GetRoles(ctx, folderID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(roles) == 0 {
|
||||
roles = []Role{}
|
||||
roles = []space.Role{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, roles)
|
||||
|
@ -537,7 +543,7 @@ func (h *Handler) GetPermissions(w http.ResponseWriter, r *http.Request) {
|
|||
// AcceptInvitation records the fact that a user has completed space onboard process.
|
||||
func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.AcceptInvitation"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
folderID := request.Param(r, "folderID")
|
||||
if len(folderID) == 0 {
|
||||
|
@ -545,14 +551,14 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
org, err := organization.GetOrganizationByDomain(s, s.Context.Subdomain)
|
||||
org, err := h.Store.Organization.GetOrganizationByDomain(ctx, ctx.Subdomain)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// AcceptShare does not authenticate the user hence the context needs to set up
|
||||
s.Context.OrgID = org.RefID
|
||||
ctx.OrgID = org.RefID
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
@ -561,7 +567,7 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var model = AcceptShareModel{}
|
||||
var model = space.AcceptShareModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
|
@ -573,44 +579,44 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
u, err := user.GetBySerial(s, model.Serial)
|
||||
u, err := h.Store.User.GetBySerial(ctx, model.Serial)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
response.WriteDuplicateError(w, method, "user")
|
||||
return
|
||||
}
|
||||
|
||||
// AcceptShare does not authenticate the user hence the context needs to set up
|
||||
s.Context.UserID = u.RefID
|
||||
ctx.UserID = u.RefID
|
||||
|
||||
u.Firstname = model.Firstname
|
||||
u.Lastname = model.Lastname
|
||||
u.Initials = stringutil.MakeInitials(u.Firstname, u.Lastname)
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = user.UpdateUser(s, u)
|
||||
err = h.Store.User.UpdateUser(ctx, u)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
salt := secrets.GenerateSalt()
|
||||
|
||||
err = user.UpdateUserPassword(s, u.RefID, salt, secrets.GeneratePassword(model.Password, salt))
|
||||
err = h.Store.User.UpdateUserPassword(ctx, u.RefID, salt, secrets.GeneratePassword(model.Password, salt))
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceJoin)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceJoin)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteJSON(w, u)
|
||||
}
|
||||
|
@ -618,7 +624,7 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
// Invite sends users folder invitation emails.
|
||||
func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Invite"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
if len(id) == 0 {
|
||||
|
@ -626,13 +632,13 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
sp, err := Get(s, id)
|
||||
sp, err := h.Store.Space.Get(ctx, id)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if sp.UserID != s.Context.UserID {
|
||||
if sp.UserID != ctx.UserID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
@ -644,38 +650,38 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var model = InvitationModel{}
|
||||
var model = space.InvitationModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "json")
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
inviter, err := user.Get(s, s.Context.UserID)
|
||||
inviter, err := h.Store.User.Get(ctx, ctx.UserID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, email := range model.Recipients {
|
||||
u, err := user.GetByEmail(s, email)
|
||||
u, err := h.Store.User.GetByEmail(ctx, email)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(u.RefID) > 0 {
|
||||
// Ensure they have access to this organization
|
||||
accounts, err2 := account.GetUserAccounts(s, u.RefID)
|
||||
accounts, err2 := h.Store.Account.GetUserAccounts(ctx, u.RefID)
|
||||
if err2 != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
@ -683,7 +689,7 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
|||
// we create if they c
|
||||
hasAccess := false
|
||||
for _, a := range accounts {
|
||||
if a.OrgID == s.Context.OrgID {
|
||||
if a.OrgID == ctx.OrgID {
|
||||
hasAccess = true
|
||||
}
|
||||
}
|
||||
|
@ -691,52 +697,52 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
|||
if !hasAccess {
|
||||
var a account.Account
|
||||
a.UserID = u.RefID
|
||||
a.OrgID = s.Context.OrgID
|
||||
a.OrgID = ctx.OrgID
|
||||
a.Admin = false
|
||||
a.Editor = false
|
||||
a.Active = true
|
||||
accountID := uniqueid.Generate()
|
||||
a.RefID = accountID
|
||||
|
||||
err = account.Add(s, a)
|
||||
err = h.Store.Account.Add(ctx, a)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure they have space roles
|
||||
DeleteUserSpaceRoles(s, sp.RefID, u.RefID)
|
||||
h.Store.Space.DeleteUserSpaceRoles(ctx, sp.RefID, u.RefID)
|
||||
|
||||
role := Role{}
|
||||
role := space.Role{}
|
||||
role.LabelID = sp.RefID
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.OrgID = ctx.OrgID
|
||||
role.UserID = u.RefID
|
||||
role.CanEdit = false
|
||||
role.CanView = true
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
|
||||
err = AddRole(s, role)
|
||||
err = h.Store.Space.AddRole(ctx, role)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
url := s.Context.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
go mail.ShareFolderExistingUser(email, inviter.Fullname(), url, sp.Name, model.Message)
|
||||
|
||||
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, sp.Name, email))
|
||||
} else {
|
||||
// On-board new user
|
||||
if strings.Contains(email, "@") {
|
||||
url := s.Context.GetAppURL(fmt.Sprintf("auth/share/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
err = inviteNewUserToSharedSpace(s, email, inviter, url, sp, model.Message)
|
||||
url := ctx.GetAppURL(fmt.Sprintf("auth/share/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
err = inviteNewUserToSharedSpace(ctx, h.Store, email, inviter, url, sp, model.Message)
|
||||
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
@ -747,20 +753,20 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// We ensure that the folder is marked as restricted as a minimum!
|
||||
if len(model.Recipients) > 0 && sp.Type == ScopePrivate {
|
||||
sp.Type = ScopeRestricted
|
||||
if len(model.Recipients) > 0 && sp.Type == space.ScopePrivate {
|
||||
sp.Type = space.ScopeRestricted
|
||||
|
||||
err = Update(s, sp)
|
||||
err = h.Store.Space.Update(ctx, sp)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceInvite)
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceInvite)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
|
|
@ -9,28 +9,34 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
// Package mysql handles data persistence for spaces.
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/store/mysql"
|
||||
"github.com/documize/community/model/space"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// Add adds new folder into the store.
|
||||
func Add(s domain.StoreContext, sp Space) (err error) {
|
||||
sp.UserID = s.Context.UserID
|
||||
func (s Scope) Add(ctx domain.RequestContext, sp space.Space) (err error) {
|
||||
sp.UserID = ctx.UserID
|
||||
sp.Created = time.Now().UTC()
|
||||
sp.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO label (refid, label, orgid, userid, type, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO label (refid, label, orgid, userid, type, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -48,7 +54,7 @@ func Add(s domain.StoreContext, sp Space) (err error) {
|
|||
}
|
||||
|
||||
// Get returns a space from the store.
|
||||
func Get(s domain.StoreContext, id string) (sp Space, err error) {
|
||||
func (s Scope) Get(ctx domain.RequestContext, id string) (sp space.Space, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label WHERE orgid=? and refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -57,7 +63,7 @@ func Get(s domain.StoreContext, id string) (sp Space, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
err = stmt.Get(&sp, s.Context.OrgID, id)
|
||||
err = stmt.Get(&sp, ctx.OrgID, id)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for label %s", id))
|
||||
return
|
||||
|
@ -67,7 +73,7 @@ func Get(s domain.StoreContext, id string) (sp Space, err error) {
|
|||
}
|
||||
|
||||
// PublicSpaces returns folders that anyone can see.
|
||||
func PublicSpaces(s domain.StoreContext, orgID string) (sp []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"
|
||||
|
||||
err = s.Runtime.Db.Select(&sp, sql, orgID)
|
||||
|
@ -82,7 +88,7 @@ func PublicSpaces(s domain.StoreContext, orgID string) (sp []Space, err error) {
|
|||
|
||||
// GetAll returns folders that the user can see.
|
||||
// Also handles which folders can be seen by anonymous users.
|
||||
func GetAll(s domain.StoreContext) (sp []Space, err error) {
|
||||
func (s Scope) GetAll(ctx domain.RequestContext) (sp []space.Space, err error) {
|
||||
sql := `
|
||||
(SELECT id,refid,label as name,orgid,userid,type,created,revised from label WHERE orgid=? AND type=2 AND userid=?)
|
||||
UNION ALL
|
||||
|
@ -94,16 +100,16 @@ UNION ALL
|
|||
ORDER BY name`
|
||||
|
||||
err = s.Runtime.Db.Select(&sp, sql,
|
||||
s.Context.OrgID,
|
||||
s.Context.UserID,
|
||||
s.Context.OrgID,
|
||||
s.Context.OrgID,
|
||||
s.Context.OrgID,
|
||||
s.Context.OrgID,
|
||||
s.Context.UserID)
|
||||
ctx.OrgID,
|
||||
ctx.UserID,
|
||||
ctx.OrgID,
|
||||
ctx.OrgID,
|
||||
ctx.OrgID,
|
||||
ctx.OrgID,
|
||||
ctx.UserID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("Unable to execute select labels for org %s", s.Context.OrgID))
|
||||
err = errors.Wrap(err, fmt.Sprintf("Unable to execute select labels for org %s", ctx.OrgID))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -111,10 +117,10 @@ ORDER BY name`
|
|||
}
|
||||
|
||||
// Update saves space changes.
|
||||
func Update(s domain.StoreContext, sp Space) (err error) {
|
||||
func (s Scope) Update(ctx domain.RequestContext, sp space.Space) (err error) {
|
||||
sp.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.PrepareNamed("UPDATE label SET label=:name, type=:type, userid=:userid, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
stmt, err := ctx.Transaction.PrepareNamed("UPDATE label SET label=:name, type=:type, userid=:userid, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -132,8 +138,8 @@ func Update(s domain.StoreContext, sp Space) (err error) {
|
|||
}
|
||||
|
||||
// ChangeOwner transfer space ownership.
|
||||
func ChangeOwner(s domain.StoreContext, currentOwner, newOwner string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE label SET userid=? WHERE userid=? AND orgid=?")
|
||||
func (s Scope) ChangeOwner(ctx domain.RequestContext, currentOwner, newOwner string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE label SET userid=? WHERE userid=? AND orgid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -141,7 +147,7 @@ func ChangeOwner(s domain.StoreContext, currentOwner, newOwner string) (err erro
|
|||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(newOwner, currentOwner, s.Context.OrgID)
|
||||
_, err = stmt.Exec(newOwner, currentOwner, ctx.OrgID)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute change space owner for %s", currentOwner))
|
||||
return
|
||||
|
@ -151,7 +157,7 @@ func ChangeOwner(s domain.StoreContext, currentOwner, newOwner string) (err erro
|
|||
}
|
||||
|
||||
// Viewers returns the list of people who can see shared folders.
|
||||
func Viewers(s domain.StoreContext) (v []Viewer, err error) {
|
||||
func (s Scope) Viewers(ctx domain.RequestContext) (v []space.Viewer, err error) {
|
||||
sql := `
|
||||
SELECT a.userid,
|
||||
COALESCE(u.firstname, '') as firstname,
|
||||
|
@ -167,23 +173,23 @@ WHERE a.orgid=? AND b.type != 2
|
|||
GROUP BY a.labelid,a.userid
|
||||
ORDER BY u.firstname,u.lastname`
|
||||
|
||||
err = s.Runtime.Db.Select(&v, sql, s.Context.OrgID)
|
||||
err = s.Runtime.Db.Select(&v, sql, ctx.OrgID)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes space from the store.
|
||||
func Delete(s domain.StoreContext, id string) (rows int64, err error) {
|
||||
func (s Scope) Delete(ctx domain.RequestContext, id string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.DeleteConstrained(s.Context.Transaction, "label", s.Context.OrgID, id)
|
||||
return b.DeleteConstrained(ctx.Transaction, "label", ctx.OrgID, id)
|
||||
}
|
||||
|
||||
// AddRole inserts the given record into the labelrole database table.
|
||||
func AddRole(s domain.StoreContext, r Role) (err error) {
|
||||
func (s Scope) AddRole(ctx domain.RequestContext, r space.Role) (err error) {
|
||||
r.Created = time.Now().UTC()
|
||||
r.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO labelrole (refid, labelid, orgid, userid, canview, canedit, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO labelrole (refid, labelid, orgid, userid, canview, canedit, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -201,10 +207,10 @@ func AddRole(s domain.StoreContext, r Role) (err error) {
|
|||
}
|
||||
|
||||
// GetRoles returns a slice of labelrole records, for the given labelID in the client's organization, grouped by user.
|
||||
func GetRoles(s domain.StoreContext, labelID string) (r []Role, err error) {
|
||||
func (s Scope) GetRoles(ctx domain.RequestContext, labelID string) (r []space.Role, err error) {
|
||||
query := `SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND labelid=?` // was + "GROUP BY userid"
|
||||
|
||||
err = s.Runtime.Db.Select(&r, query, s.Context.OrgID, labelID)
|
||||
err = s.Runtime.Db.Select(&r, query, ctx.OrgID, labelID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
|
@ -220,19 +226,19 @@ func GetRoles(s domain.StoreContext, labelID string) (r []Role, err error) {
|
|||
|
||||
// GetUserRoles returns a slice of role records, for both the client's user and organization, and
|
||||
// those space roles that exist for all users in the client's organization.
|
||||
func GetUserRoles(s domain.StoreContext) (r []Role, err error) {
|
||||
func (s Scope) GetUserRoles(ctx domain.RequestContext) (r []space.Role, err error) {
|
||||
err = s.Runtime.Db.Select(&r, `
|
||||
SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? and userid=?
|
||||
UNION ALL
|
||||
SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND userid=''`,
|
||||
s.Context.OrgID, s.Context.UserID, s.Context.OrgID)
|
||||
ctx.OrgID, ctx.UserID, ctx.OrgID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for user space roles %s", s.Context.UserID))
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for user space roles %s", ctx.UserID))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -240,36 +246,36 @@ func GetUserRoles(s domain.StoreContext) (r []Role, err error) {
|
|||
}
|
||||
|
||||
// DeleteRole deletes the labelRoleID record from the labelrole table.
|
||||
func DeleteRole(s domain.StoreContext, roleID string) (rows int64, err error) {
|
||||
func (s Scope) DeleteRole(ctx domain.RequestContext, roleID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND refid='%s'", s.Context.OrgID, roleID)
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND refid='%s'", ctx.OrgID, roleID)
|
||||
|
||||
return b.DeleteWhere(s.Context.Transaction, sql)
|
||||
return b.DeleteWhere(ctx.Transaction, sql)
|
||||
}
|
||||
|
||||
// DeleteSpaceRoles deletes records from the labelrole table which have the given space ID.
|
||||
func DeleteSpaceRoles(s domain.StoreContext, spaceID string) (rows int64, err error) {
|
||||
func (s Scope) DeleteSpaceRoles(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s'", s.Context.OrgID, spaceID)
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s'", ctx.OrgID, spaceID)
|
||||
|
||||
return b.DeleteWhere(s.Context.Transaction, sql)
|
||||
return b.DeleteWhere(ctx.Transaction, sql)
|
||||
}
|
||||
|
||||
// DeleteUserSpaceRoles removes all roles for the specified user, for the specified space.
|
||||
func DeleteUserSpaceRoles(s domain.StoreContext, spaceID, userID string) (rows int64, err error) {
|
||||
func (s Scope) DeleteUserSpaceRoles(ctx domain.RequestContext, spaceID, userID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s' AND userid='%s'",
|
||||
s.Context.OrgID, spaceID, userID)
|
||||
ctx.OrgID, spaceID, userID)
|
||||
|
||||
return b.DeleteWhere(s.Context.Transaction, sql)
|
||||
return b.DeleteWhere(ctx.Transaction, sql)
|
||||
}
|
||||
|
||||
// MoveSpaceRoles changes the space ID for space role records from previousLabel to newLabel.
|
||||
func MoveSpaceRoles(s domain.StoreContext, previousLabel, newLabel string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE labelrole SET labelid=? WHERE labelid=? AND orgid=?")
|
||||
func (s Scope) MoveSpaceRoles(ctx domain.RequestContext, previousLabel, newLabel string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE labelrole SET labelid=? WHERE labelid=? AND orgid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -277,7 +283,7 @@ func MoveSpaceRoles(s domain.StoreContext, previousLabel, newLabel string) (err
|
|||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(newLabel, previousLabel, s.Context.OrgID)
|
||||
_, err = stmt.Exec(newLabel, previousLabel, ctx.OrgID)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute move space roles for label %s", previousLabel))
|
||||
}
|
|
@ -13,13 +13,7 @@
|
|||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
/*
|
||||
// CanViewSpace returns if the user has permission to view the given spaceID.
|
||||
func CanViewSpace(s domain.StoreContext, spaceID string) (hasPermission bool) {
|
||||
roles, err := GetRoles(s, spaceID)
|
||||
|
@ -60,3 +54,4 @@ func CanViewSpaceDocuments(s domain.StoreContext, spaceID string) (hasPermission
|
|||
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -18,29 +18,30 @@ import (
|
|||
"github.com/documize/community/core/secrets"
|
||||
"github.com/documize/community/core/uniqueid"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/account"
|
||||
"github.com/documize/community/domain/user"
|
||||
"github.com/documize/community/model/account"
|
||||
"github.com/documize/community/model/space"
|
||||
"github.com/documize/community/model/user"
|
||||
)
|
||||
|
||||
// addSpace prepares and creates space record.
|
||||
func addSpace(s domain.StoreContext, sp Space) (err error) {
|
||||
sp.Type = ScopePrivate
|
||||
sp.UserID = s.Context.UserID
|
||||
func addSpace(ctx domain.RequestContext, s *domain.Store, sp space.Space) (err error) {
|
||||
sp.Type = space.ScopePrivate
|
||||
sp.UserID = ctx.UserID
|
||||
|
||||
err = Add(s, sp)
|
||||
err = s.Space.Add(ctx, sp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
role := Role{}
|
||||
role := space.Role{}
|
||||
role.LabelID = sp.RefID
|
||||
role.OrgID = sp.OrgID
|
||||
role.UserID = s.Context.UserID
|
||||
role.UserID = ctx.UserID
|
||||
role.CanEdit = true
|
||||
role.CanView = true
|
||||
role.RefID = uniqueid.Generate()
|
||||
|
||||
err = AddRole(s, role)
|
||||
err = s.Space.AddRole(ctx, role)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -49,8 +50,8 @@ func addSpace(s domain.StoreContext, sp Space) (err error) {
|
|||
// We create the user account with default values and then take them
|
||||
// through a welcome process designed to capture profile data.
|
||||
// We add them to the organization and grant them view-only folder access.
|
||||
func inviteNewUserToSharedSpace(s domain.StoreContext, email string, invitedBy user.User,
|
||||
baseURL string, sp Space, invitationMessage string) (err error) {
|
||||
func inviteNewUserToSharedSpace(ctx domain.RequestContext, s *domain.Store, email string, invitedBy user.User,
|
||||
baseURL string, sp space.Space, invitationMessage string) (err error) {
|
||||
|
||||
var u = user.User{}
|
||||
u.Email = email
|
||||
|
@ -62,7 +63,7 @@ func inviteNewUserToSharedSpace(s domain.StoreContext, email string, invitedBy u
|
|||
userID := uniqueid.Generate()
|
||||
u.RefID = userID
|
||||
|
||||
err = user.Add(s, u)
|
||||
err = s.User.Add(ctx, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -70,28 +71,28 @@ func inviteNewUserToSharedSpace(s domain.StoreContext, email string, invitedBy u
|
|||
// Let's give this user access to the organization
|
||||
var a account.Account
|
||||
a.UserID = userID
|
||||
a.OrgID = s.Context.OrgID
|
||||
a.OrgID = ctx.OrgID
|
||||
a.Admin = false
|
||||
a.Editor = false
|
||||
a.Active = true
|
||||
accountID := uniqueid.Generate()
|
||||
a.RefID = accountID
|
||||
|
||||
err = account.Add(s, a)
|
||||
err = s.Account.Add(ctx, a)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
role := Role{}
|
||||
role := space.Role{}
|
||||
role.LabelID = sp.RefID
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.OrgID = ctx.OrgID
|
||||
role.UserID = userID
|
||||
role.CanEdit = false
|
||||
role.CanView = true
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
|
||||
err = AddRole(s, role)
|
||||
err = s.Space.AddRole(ctx, role)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
118
domain/storer.go
Normal file
118
domain/storer.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package domain ...
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/documize/community/model/account"
|
||||
"github.com/documize/community/model/audit"
|
||||
"github.com/documize/community/model/org"
|
||||
"github.com/documize/community/model/pin"
|
||||
"github.com/documize/community/model/space"
|
||||
"github.com/documize/community/model/user"
|
||||
)
|
||||
|
||||
// Store provides access to data store (database)
|
||||
type Store struct {
|
||||
Space SpaceStorer
|
||||
User UserStorer
|
||||
Account AccountStorer
|
||||
Organization OrganizationStorer
|
||||
Pin PinStorer
|
||||
Audit AuditStorer
|
||||
Document DocumentStorer
|
||||
}
|
||||
|
||||
// SpaceStorer defines required methods for space management
|
||||
type SpaceStorer interface {
|
||||
Add(ctx RequestContext, sp space.Space) (err error)
|
||||
Get(ctx RequestContext, id string) (sp space.Space, err error)
|
||||
PublicSpaces(ctx RequestContext, orgID string) (sp []space.Space, err error)
|
||||
GetAll(ctx RequestContext) (sp []space.Space, err error)
|
||||
Update(ctx RequestContext, sp space.Space) (err error)
|
||||
ChangeOwner(ctx RequestContext, currentOwner, newOwner string) (err error)
|
||||
Viewers(ctx RequestContext) (v []space.Viewer, err error)
|
||||
Delete(ctx RequestContext, id string) (rows int64, err error)
|
||||
AddRole(ctx RequestContext, r space.Role) (err error)
|
||||
GetRoles(ctx RequestContext, labelID string) (r []space.Role, err error)
|
||||
GetUserRoles(ctx RequestContext) (r []space.Role, err error)
|
||||
DeleteRole(ctx RequestContext, roleID string) (rows int64, err error)
|
||||
DeleteSpaceRoles(ctx RequestContext, spaceID string) (rows int64, err error)
|
||||
DeleteUserSpaceRoles(ctx RequestContext, spaceID, userID string) (rows int64, err error)
|
||||
MoveSpaceRoles(ctx RequestContext, previousLabel, newLabel string) (err error)
|
||||
}
|
||||
|
||||
// UserStorer defines required methods for user management
|
||||
type UserStorer interface {
|
||||
Add(ctx RequestContext, u user.User) (err error)
|
||||
Get(ctx RequestContext, id string) (u user.User, err error)
|
||||
GetByDomain(ctx RequestContext, domain, email string) (u user.User, err error)
|
||||
GetByEmail(ctx RequestContext, email string) (u user.User, err error)
|
||||
GetByToken(ctx RequestContext, token string) (u user.User, err error)
|
||||
GetBySerial(ctx RequestContext, serial string) (u user.User, err error)
|
||||
GetActiveUsersForOrganization(ctx RequestContext) (u []user.User, err error)
|
||||
GetUsersForOrganization(ctx RequestContext) (u []user.User, err error)
|
||||
GetSpaceUsers(ctx RequestContext, folderID string) (u []user.User, err error)
|
||||
UpdateUser(ctx RequestContext, u user.User) (err error)
|
||||
UpdateUserPassword(ctx RequestContext, userID, salt, password string) (err error)
|
||||
DeactiveUser(ctx RequestContext, userID string) (err error)
|
||||
ForgotUserPassword(ctx RequestContext, email, token string) (err error)
|
||||
CountActiveUsers(ctx RequestContext) (c int)
|
||||
}
|
||||
|
||||
// AccountStorer defines required methods for account management
|
||||
type AccountStorer interface {
|
||||
Add(ctx RequestContext, account account.Account) (err error)
|
||||
GetUserAccount(ctx RequestContext, userID string) (account account.Account, err error)
|
||||
GetUserAccounts(ctx RequestContext, userID string) (t []account.Account, err error)
|
||||
GetAccountsByOrg(ctx RequestContext) (t []account.Account, err error)
|
||||
DeleteAccount(ctx RequestContext, ID string) (rows int64, err error)
|
||||
UpdateAccount(ctx RequestContext, account account.Account) (err error)
|
||||
HasOrgAccount(ctx RequestContext, orgID, userID string) bool
|
||||
CountOrgAccounts(ctx RequestContext) int
|
||||
}
|
||||
|
||||
// OrganizationStorer defines required methods for organization management
|
||||
type OrganizationStorer interface {
|
||||
AddOrganization(ctx RequestContext, org org.Organization) error
|
||||
GetOrganization(ctx RequestContext, id string) (org org.Organization, err error)
|
||||
GetOrganizationByDomain(ctx RequestContext, subdomain string) (org org.Organization, err error)
|
||||
UpdateOrganization(ctx RequestContext, org org.Organization) (err error)
|
||||
DeleteOrganization(ctx RequestContext, orgID string) (rows int64, err error)
|
||||
RemoveOrganization(ctx RequestContext, orgID string) (err error)
|
||||
UpdateAuthConfig(ctx RequestContext, org org.Organization) (err error)
|
||||
CheckDomain(ctx RequestContext, domain string) string
|
||||
}
|
||||
|
||||
// PinStorer defines required methods for pin management
|
||||
type PinStorer interface {
|
||||
Add(ctx RequestContext, pin pin.Pin) (err error)
|
||||
GetPin(ctx RequestContext, id string) (pin pin.Pin, err error)
|
||||
GetUserPins(ctx RequestContext, userID string) (pins []pin.Pin, err error)
|
||||
UpdatePin(ctx RequestContext, pin pin.Pin) (err error)
|
||||
UpdatePinSequence(ctx RequestContext, pinID string, sequence int) (err error)
|
||||
DeletePin(ctx RequestContext, id string) (rows int64, err error)
|
||||
DeletePinnedSpace(ctx RequestContext, spaceID string) (rows int64, err error)
|
||||
DeletePinnedDocument(ctx RequestContext, documentID string) (rows int64, err error)
|
||||
}
|
||||
|
||||
// AuditStorer defines required methods for audit trails
|
||||
type AuditStorer interface {
|
||||
Record(ctx RequestContext, t audit.EventType)
|
||||
}
|
||||
|
||||
// DocumentStorer defines required methods for document handling
|
||||
type DocumentStorer interface {
|
||||
MoveDocumentSpace(ctx RequestContext, id, move string) (err error)
|
||||
}
|
||||
|
||||
// https://github.com/golang-sql/sqlexp/blob/c2488a8be21d20d31abf0d05c2735efd2d09afe4/quoter.go#L46
|
616
domain/user/endpoint.go
Normal file
616
domain/user/endpoint.go
Normal file
|
@ -0,0 +1,616 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
Store domain.Store
|
||||
}
|
||||
|
||||
/*
|
||||
// AddUser is the endpoint that enables an administrator to add a new user for their orgaisation.
|
||||
func (h *Handler) AddUser(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.AddUser"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
}
|
||||
|
||||
if !s.Context.Administrator {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
userModel := model.User{}
|
||||
err = json.Unmarshal(body, &userModel)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// data validation
|
||||
userModel.Email = strings.ToLower(strings.TrimSpace(userModel.Email))
|
||||
userModel.Firstname = strings.TrimSpace(userModel.Firstname)
|
||||
userModel.Lastname = strings.TrimSpace(userModel.Lastname)
|
||||
userModel.Password = strings.TrimSpace(userModel.Password)
|
||||
|
||||
if len(userModel.Email) == 0 {
|
||||
response.WriteMissingDataError(w, method, "email")
|
||||
return
|
||||
}
|
||||
|
||||
if len(userModel.Firstname) == 0 {
|
||||
response.WriteMissingDataError(w, method, "firsrtname")
|
||||
return
|
||||
}
|
||||
|
||||
if len(userModel.Lastname) == 0 {
|
||||
response.WriteMissingDataError(w, method, "lastname")
|
||||
return
|
||||
}
|
||||
|
||||
userModel.Initials = stringutil.MakeInitials(userModel.Firstname, userModel.Lastname)
|
||||
requestedPassword := secrets.GenerateRandomPassword()
|
||||
userModel.Salt = secrets.GenerateSalt()
|
||||
userModel.Password = secrets.GeneratePassword(requestedPassword, userModel.Salt)
|
||||
|
||||
// only create account if not dupe
|
||||
addUser := true
|
||||
addAccount := true
|
||||
var userID string
|
||||
|
||||
userDupe, err := h.Store.User.GetByEmail(s, userModel.Email)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if userModel.Email == userDupe.Email {
|
||||
addUser = false
|
||||
userID = userDupe.RefID
|
||||
|
||||
h.Runtime.Log.Info("Dupe user found, will not add " + userModel.Email)
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = request.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if addUser {
|
||||
userID = uniqueid.Generate()
|
||||
userModel.RefID = userID
|
||||
|
||||
err = h.Store.User.Add(s, userModel)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.Runtime.Log.Info("Adding user")
|
||||
} else {
|
||||
AttachUserAccounts(s, s.Context.OrgID, &userDupe)
|
||||
|
||||
for _, a := range userDupe.Accounts {
|
||||
if a.OrgID == s.Context.OrgID {
|
||||
addAccount = false
|
||||
h.Runtime.Log.Info("Dupe account found, will not add")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set up user account for the org
|
||||
if addAccount {
|
||||
var a model.Account
|
||||
a.RefID = uniqueid.Generate()
|
||||
a.UserID = userID
|
||||
a.OrgID = s.Context.OrgID
|
||||
a.Editor = true
|
||||
a.Admin = false
|
||||
a.Active = true
|
||||
|
||||
err = account.Add(s, a)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if addUser {
|
||||
event.Handler().Publish(string(event.TypeAddUser))
|
||||
eventing.Record(s, eventing.EventTypeUserAdd)
|
||||
}
|
||||
|
||||
if addAccount {
|
||||
event.Handler().Publish(string(event.TypeAddAccount))
|
||||
eventing.Record(s, eventing.EventTypeAccountAdd)
|
||||
}
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
|
||||
// If we did not add user or give them access (account) then we error back
|
||||
if !addUser && !addAccount {
|
||||
response.WriteDuplicateError(w, method, "user")
|
||||
return
|
||||
}
|
||||
|
||||
// Invite new user
|
||||
inviter, err := h.Store.User.Get(s, s.Context.UserID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare invitation email (that contains SSO link)
|
||||
if addUser && addAccount {
|
||||
size := len(requestedPassword)
|
||||
|
||||
auth := fmt.Sprintf("%s:%s:%s", s.Context.AppURL, userModel.Email, requestedPassword[:size])
|
||||
encrypted := secrets.EncodeBase64([]byte(auth))
|
||||
|
||||
url := fmt.Sprintf("%s/%s", s.Context.GetAppURL("auth/sso"), url.QueryEscape(string(encrypted)))
|
||||
go mail.InviteNewUser(userModel.Email, inviter.Fullname(), url, userModel.Email, requestedPassword)
|
||||
|
||||
h.Runtime.Log.Info(fmt.Sprintf("%s invited by %s on %s", userModel.Email, inviter.Email, s.Context.AppURL))
|
||||
|
||||
} else {
|
||||
go mail.InviteExistingUser(userModel.Email, inviter.Fullname(), s.Context.GetAppURL(""))
|
||||
|
||||
h.Runtime.Log.Info(fmt.Sprintf("%s is giving access to an existing user %s", inviter.Email, userModel.Email))
|
||||
}
|
||||
|
||||
response.WriteJSON(w, userModel)
|
||||
}
|
||||
|
||||
/*
|
||||
// GetOrganizationUsers is the endpoint that allows administrators to view the users in their organisation.
|
||||
func (h *Handler) GetOrganizationUsers(w http.ResponseWriter, r *http.Request) {
|
||||
method := "pin.GetUserPins"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
if !s.Context.Editor && !s.Context.Administrator {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
active, err := strconv.ParseBool(request.Query("active"))
|
||||
if err != nil {
|
||||
active = false
|
||||
}
|
||||
|
||||
u := []User{}
|
||||
|
||||
if active {
|
||||
u, err = GetActiveUsersForOrganization(s)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
u, err = GetUsersForOrganization(s)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(u) == 0 {
|
||||
u = []User{}
|
||||
}
|
||||
|
||||
for i := range u {
|
||||
AttachUserAccounts(s, s.Context.OrgID, &u[i])
|
||||
}
|
||||
|
||||
response.WriteJSON(w, u)
|
||||
}
|
||||
|
||||
// GetSpaceUsers returns every user within a given space
|
||||
func (h *Handler) GetSpaceUsers(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.GetSpaceUsers"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
var u []User
|
||||
var err error
|
||||
|
||||
folderID := request.Param("folderID")
|
||||
if len(folderID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
// check to see space type as it determines user selection criteria
|
||||
folder, err := space.Get(s, folderID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
h.Runtime.Log.Error("cannot get space", err)
|
||||
response.WriteJSON(w, u)
|
||||
return
|
||||
}
|
||||
|
||||
switch folder.Type {
|
||||
case entity.FolderTypePublic:
|
||||
u, err = GetActiveUsersForOrganization(s)
|
||||
break
|
||||
case entity.FolderTypePrivate:
|
||||
// just me
|
||||
var me User
|
||||
user, err = Get(s, s.Context.UserID)
|
||||
u = append(u, me)
|
||||
break
|
||||
case entity.FolderTypeRestricted:
|
||||
u, err = GetSpaceUsers(s, folderID)
|
||||
break
|
||||
}
|
||||
|
||||
if len(u) == 0 {
|
||||
u = []User
|
||||
}
|
||||
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
h.Runtime.Log.Error("cannot get users for space", err)
|
||||
response.WriteJSON(w, u)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteJSON(w, u)
|
||||
}
|
||||
|
||||
// GetUser returns user specified by ID
|
||||
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.GetUser"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
userID := request.Param("userID")
|
||||
if len(userID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "userId")
|
||||
return
|
||||
}
|
||||
|
||||
if userID != s.Context.UserID {
|
||||
response.WriteBadRequestError(w, method, "userId mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
u, err := GetSecuredUser(s, s.Context.OrgID, userID)
|
||||
if err == sql.ErrNoRows {
|
||||
response.WriteNotFoundError(s, method, s.Context.UserID)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteJSON(u)
|
||||
|
||||
// DeleteUser is the endpoint to delete a user specified by userID, the caller must be an Administrator.
|
||||
func (h *Handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.DeleteUser"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
if !s.Context.Administrator {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
userID := response.Params("userID")
|
||||
if len(userID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "userID")
|
||||
return
|
||||
}
|
||||
|
||||
if userID == s.Context.UserID {
|
||||
response.WriteBadRequestError(w, method, "cannot delete self")
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = DeactiveUser(s, userID)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = space.ChangeLabelOwner(s, userID, s.Context.UserID)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeUserDelete)
|
||||
event.Handler().Publish(string(event.TypeRemoveUser))
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty()
|
||||
}
|
||||
|
||||
// UpdateUser is the endpoint to update user information for the given userID.
|
||||
// Note that unless they have admin privildges, a user can only update their own information.
|
||||
// Also, only admins can update user roles in organisations.
|
||||
func (h *Handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.DeleteUser"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
userID := request.Param("userID")
|
||||
if len(userID) == 0 {
|
||||
response.WriteBadRequestError(w, method, "user id must be numeric")
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WritePayloadError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
u := User{}
|
||||
err = json.Unmarshal(body, &u)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// can only update your own account unless you are an admin
|
||||
if s.Context.UserID != userID && !s.Context.Administrator {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
// can only update your own account unless you are an admin
|
||||
if len(u.Email) == 0 {
|
||||
response.WriteMissingDataError(w, method, "email")
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
u.RefID = userID
|
||||
u.Initials = stringutil.MakeInitials(u.Firstname, u.Lastname)
|
||||
|
||||
err = UpdateUser(s, u)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Now we update user roles for this organization.
|
||||
// That means we have to first find their account record
|
||||
// for this organization.
|
||||
a, err := account.GetUserAccount(s, userID)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.Editor = u.Editor
|
||||
a.Admin = u.Admin
|
||||
a.Active = u.Active
|
||||
|
||||
err = account.UpdateAccount(s, account)
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeUserUpdate)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
|
||||
response.WriteJSON(u)
|
||||
}
|
||||
|
||||
// ChangeUserPassword accepts password change from within the app.
|
||||
func (h *Handler) ChangeUserPassword(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.ChangeUserPassword"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
userID := response.Param("userID")
|
||||
if len(userID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "user id")
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
newPassword := string(body)
|
||||
|
||||
// can only update your own account unless you are an admin
|
||||
if userID != s.Context.UserID && !s.Context.Administrator {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := Get(s, userID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
u.Salt = secrets.GenerateSalt()
|
||||
|
||||
err = UpdateUserPassword(s, userID, user.Salt, secrets.GeneratePassword(newPassword, user.Salt))
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// GetUserFolderPermissions returns folder permission for authenticated user.
|
||||
func (h *Handler) GetUserFolderPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.ChangeUserPassword"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
userID := request.Param("userID")
|
||||
if userID != p.Context.UserID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := space.GetUserLabelRoles(s, userID)
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
roles = []space.Role{}
|
||||
}
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteJSON(w, roles)
|
||||
}
|
||||
|
||||
// ForgotUserPassword initiates the change password procedure.
|
||||
// Generates a reset token and sends email to the user.
|
||||
// User has to click link in email and then provide a new password.
|
||||
func (h *Handler) ForgotUserPassword(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.ForgotUserPassword"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "cannot ready payload")
|
||||
return
|
||||
}
|
||||
|
||||
u := new(User)
|
||||
err = json.Unmarshal(body, &u)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "JSON body")
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction, err = request.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
token := secrets.GenerateSalt()
|
||||
|
||||
err = ForgotUserPassword(s, u.Email, token)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
response.WriteEmpty(w)
|
||||
h.Runtime.Log.Info(fmt.Errorf("User %s not found for password reset process", u.Email))
|
||||
return
|
||||
}
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
|
||||
appURL := s.Context.GetAppURL(fmt.Sprintf("auth/reset/%s", token))
|
||||
go mail.PasswordReset(u.Email, appURL)
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// ResetUserPassword stores the newly chosen password for the user.
|
||||
func (h *Handler) ResetUserPassword(w http.ResponseWriter, r *http.Request) {
|
||||
method := "user.ForgotUserPassword"
|
||||
s := domain.NewContext(h.Runtime, r)
|
||||
|
||||
token := request.Param("token")
|
||||
if len(token) == 0 {
|
||||
response.WriteMissingDataError(w, method, "missing token")
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "JSON body")
|
||||
return
|
||||
}
|
||||
newPassword := string(body)
|
||||
|
||||
s.Context.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := GetByToken(token)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
user.Salt = secrets.GenerateSalt()
|
||||
|
||||
err = UpdateUserPassword(s, u.RefID, u.Salt, secrets.GeneratePassword(newPassword, u.Salt))
|
||||
if err != nil {
|
||||
s.Context.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeUserPasswordReset)
|
||||
|
||||
s.Context.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
*/
|
|
@ -9,7 +9,7 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
package user
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
@ -17,17 +17,24 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/model/user"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Scope provides data access to MySQL.
|
||||
type Scope struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// Add adds the given user record to the user table.
|
||||
func Add(s domain.StoreContext, u User) (err error) {
|
||||
func (s Scope) Add(ctx domain.RequestContext, u user.User) (err error) {
|
||||
u.Created = time.Now().UTC()
|
||||
u.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO user (refid, firstname, lastname, email, initials, password, salt, reset, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO user (refid, firstname, lastname, email, initials, password, salt, reset, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -45,7 +52,7 @@ func Add(s domain.StoreContext, u User) (err error) {
|
|||
}
|
||||
|
||||
// Get returns the user record for the given id.
|
||||
func Get(s domain.StoreContext, id string) (u User, err error) {
|
||||
func (s Scope) Get(ctx domain.RequestContext, id string) (u user.User, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, firstname, lastname, email, initials, global, password, salt, reset, created, revised FROM user WHERE refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -64,7 +71,7 @@ func Get(s domain.StoreContext, id string) (u User, err error) {
|
|||
}
|
||||
|
||||
// GetByDomain matches user by email and domain.
|
||||
func GetByDomain(s domain.StoreContext, domain, email string) (u User, err error) {
|
||||
func (s Scope) GetByDomain(ctx domain.RequestContext, domain, email string) (u user.User, err error) {
|
||||
email = strings.TrimSpace(strings.ToLower(email))
|
||||
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.global, u.password, u.salt, u.reset, u.created, u.revised FROM user u, account a, organization o WHERE TRIM(LOWER(u.email))=? AND u.refid=a.userid AND a.orgid=o.refid AND TRIM(LOWER(o.domain))=?")
|
||||
|
@ -85,7 +92,7 @@ func GetByDomain(s domain.StoreContext, domain, email string) (u User, err error
|
|||
}
|
||||
|
||||
// GetByEmail returns a single row match on email.
|
||||
func GetByEmail(s domain.StoreContext, email string) (u User, err error) {
|
||||
func (s Scope) GetByEmail(ctx domain.RequestContext, email string) (u user.User, err error) {
|
||||
email = strings.TrimSpace(strings.ToLower(email))
|
||||
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, firstname, lastname, email, initials, global, password, salt, reset, created, revised FROM user WHERE TRIM(LOWER(email))=?")
|
||||
|
@ -106,7 +113,7 @@ func GetByEmail(s domain.StoreContext, email string) (u User, err error) {
|
|||
}
|
||||
|
||||
// GetByToken returns a user record given a reset token value.
|
||||
func GetByToken(s domain.StoreContext, token string) (u User, err error) {
|
||||
func (s Scope) GetByToken(ctx domain.RequestContext, token string) (u user.User, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, firstname, lastname, email, initials, global, password, salt, reset, created, revised FROM user WHERE reset=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -127,7 +134,7 @@ func GetByToken(s domain.StoreContext, token string) (u User, err error) {
|
|||
// GetBySerial is used to retrieve a user via their temporary password salt value!
|
||||
// This occurs when we you share a folder with a new user and they have to complete
|
||||
// the onboarding process.
|
||||
func GetBySerial(s domain.StoreContext, serial string) (u User, err error) {
|
||||
func (s Scope) GetBySerial(ctx domain.RequestContext, serial string) (u user.User, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, firstname, lastname, email, initials, global, password, salt, reset, created, revised FROM user WHERE salt=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -147,15 +154,15 @@ func GetBySerial(s domain.StoreContext, serial string) (u User, err error) {
|
|||
|
||||
// GetActiveUsersForOrganization returns a slice containing of active user records for the organization
|
||||
// identified in the Persister.
|
||||
func GetActiveUsersForOrganization(s domain.StoreContext) (u []User, err error) {
|
||||
func (s Scope) GetActiveUsersForOrganization(ctx domain.RequestContext) (u []user.User, err error) {
|
||||
err = s.Runtime.Db.Select(&u,
|
||||
`SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised
|
||||
FROM user u
|
||||
WHERE u.refid IN (SELECT userid FROM account WHERE orgid = ? AND active=1) ORDER BY u.firstname,u.lastname`,
|
||||
s.Context.OrgID)
|
||||
ctx.OrgID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("get active users by org %s", s.Context.OrgID))
|
||||
err = errors.Wrap(err, fmt.Sprintf("get active users by org %s", ctx.OrgID))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -164,12 +171,12 @@ func GetActiveUsersForOrganization(s domain.StoreContext) (u []User, err error)
|
|||
|
||||
// GetUsersForOrganization returns a slice containing all of the user records for the organizaiton
|
||||
// identified in the Persister.
|
||||
func GetUsersForOrganization(s domain.StoreContext) (u []User, err error) {
|
||||
func (s Scope) GetUsersForOrganization(ctx domain.RequestContext) (u []user.User, err error) {
|
||||
err = s.Runtime.Db.Select(&u,
|
||||
"SELECT id, refid, firstname, lastname, email, initials, password, salt, reset, created, revised FROM user WHERE refid IN (SELECT userid FROM account where orgid = ?) ORDER BY firstname,lastname", s.Context.OrgID)
|
||||
"SELECT id, refid, firstname, lastname, email, initials, password, salt, reset, created, revised FROM user WHERE refid IN (SELECT userid FROM account where orgid = ?) ORDER BY firstname,lastname", ctx.OrgID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf(" get users for org %s", s.Context.OrgID))
|
||||
err = errors.Wrap(err, fmt.Sprintf(" get users for org %s", ctx.OrgID))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -177,17 +184,17 @@ func GetUsersForOrganization(s domain.StoreContext) (u []User, err error) {
|
|||
}
|
||||
|
||||
// GetSpaceUsers returns a slice containing all user records for given folder.
|
||||
func GetSpaceUsers(s domain.StoreContext, folderID string) (u []User, err error) {
|
||||
func (s Scope) GetSpaceUsers(ctx domain.RequestContext, folderID string) (u []user.User, err error) {
|
||||
err = s.Runtime.Db.Select(&u,
|
||||
`SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised
|
||||
`SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised
|
||||
FROM user u, account a
|
||||
WHERE u.refid IN (SELECT userid from labelrole WHERE orgid=? AND labelid=?)
|
||||
WHERE u.refid IN (SELECT userid from labelrole WHERE orgid=? AND labelid=?)
|
||||
AND a.orgid=? AND u.refid = a.userid AND a.active=1
|
||||
ORDER BY u.firstname, u.lastname`,
|
||||
s.Context.OrgID, folderID, s.Context.OrgID)
|
||||
ctx.OrgID, folderID, ctx.OrgID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("get space users for org %s", s.Context.OrgID))
|
||||
err = errors.Wrap(err, fmt.Sprintf("get space users for org %s", ctx.OrgID))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -195,11 +202,11 @@ func GetSpaceUsers(s domain.StoreContext, folderID string) (u []User, err error)
|
|||
}
|
||||
|
||||
// UpdateUser updates the user table using the given replacement user record.
|
||||
func UpdateUser(s domain.StoreContext, u User) (err error) {
|
||||
func (s Scope) UpdateUser(ctx domain.RequestContext, u user.User) (err error) {
|
||||
u.Revised = time.Now().UTC()
|
||||
u.Email = strings.ToLower(u.Email)
|
||||
|
||||
stmt, err := s.Context.Transaction.PrepareNamed(
|
||||
stmt, err := ctx.Transaction.PrepareNamed(
|
||||
"UPDATE user SET firstname=:firstname, lastname=:lastname, email=:email, revised=:revised, initials=:initials WHERE refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
|
@ -218,8 +225,8 @@ func UpdateUser(s domain.StoreContext, u User) (err error) {
|
|||
}
|
||||
|
||||
// UpdateUserPassword updates a user record with new password and salt values.
|
||||
func UpdateUserPassword(s domain.StoreContext, userID, salt, password string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE user SET salt=?, password=?, reset='' WHERE refid=?")
|
||||
func (s Scope) UpdateUserPassword(ctx domain.RequestContext, userID, salt, password string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE user SET salt=?, password=?, reset='' WHERE refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -237,8 +244,8 @@ func UpdateUserPassword(s domain.StoreContext, userID, salt, password string) (e
|
|||
}
|
||||
|
||||
// DeactiveUser deletes the account record for the given userID and persister.Context.OrgID.
|
||||
func DeactiveUser(s domain.StoreContext, userID string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("DELETE FROM account WHERE userid=? and orgid=?")
|
||||
func (s Scope) DeactiveUser(ctx domain.RequestContext, userID string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("DELETE FROM account WHERE userid=? and orgid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -246,7 +253,7 @@ func DeactiveUser(s domain.StoreContext, userID string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(userID, s.Context.OrgID)
|
||||
_, err = stmt.Exec(userID, ctx.OrgID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "execute user deactivation")
|
||||
|
@ -257,8 +264,8 @@ func DeactiveUser(s domain.StoreContext, userID string) (err error) {
|
|||
}
|
||||
|
||||
// ForgotUserPassword sets the password to '' and the reset field to token, for a user identified by email.
|
||||
func ForgotUserPassword(s domain.StoreContext, email, token string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE user SET reset=?, password='' WHERE LOWER(email)=?")
|
||||
func (s Scope) ForgotUserPassword(ctx domain.RequestContext, email, token string) (err error) {
|
||||
stmt, err := ctx.Transaction.Preparex("UPDATE user SET reset=?, password='' WHERE LOWER(email)=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
|
@ -276,7 +283,7 @@ func ForgotUserPassword(s domain.StoreContext, email, token string) (err error)
|
|||
}
|
||||
|
||||
// CountActiveUsers returns the number of active users in the system.
|
||||
func CountActiveUsers(s domain.StoreContext) (c int) {
|
||||
func (s Scope) CountActiveUsers(ctx domain.RequestContext) (c int) {
|
||||
row := s.Runtime.Db.QueryRow("SELECT count(*) FROM user u WHERE u.refid IN (SELECT userid FROM account WHERE active=1)")
|
||||
|
||||
err := row.Scan(&c)
|
|
@ -13,23 +13,23 @@ package user
|
|||
|
||||
import (
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/account"
|
||||
"github.com/documize/community/model/user"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// GetSecuredUser contain associated accounts but credentials are wiped.
|
||||
func GetSecuredUser(s domain.StoreContext, orgID, q string) (u User, err error) {
|
||||
u, err = Get(s, q)
|
||||
AttachUserAccounts(s, orgID, &u)
|
||||
func GetSecuredUser(ctx domain.RequestContext, s domain.Store, orgID, q string) (u user.User, err error) {
|
||||
u, err = s.User.Get(ctx, q)
|
||||
AttachUserAccounts(ctx, s, orgID, &u)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AttachUserAccounts attachs user accounts to user object.
|
||||
func AttachUserAccounts(s domain.StoreContext, orgID string, u *User) {
|
||||
func AttachUserAccounts(ctx domain.RequestContext, s domain.Store, orgID string, u *user.User) {
|
||||
u.ProtectSecrets()
|
||||
|
||||
a, err := account.GetUserAccounts(s, u.RefID)
|
||||
a, err := s.Account.GetUserAccounts(ctx, u.RefID)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "fetch user accounts")
|
||||
return
|
||||
|
|
|
@ -19,11 +19,12 @@ import (
|
|||
"github.com/documize/community/core/database"
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/core/secrets"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// InitRuntime prepares runtime using command line and environment variables.
|
||||
func InitRuntime(r *env.Runtime) bool {
|
||||
func InitRuntime(r *env.Runtime, s *domain.Store) bool {
|
||||
// We need SALT to hash auth JWT tokens
|
||||
if r.Flags.Salt == "" {
|
||||
r.Flags.Salt = secrets.RandSalt()
|
||||
|
@ -76,6 +77,9 @@ func InitRuntime(r *env.Runtime) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// setup store based upon database type
|
||||
AttachStore(r, s)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
36
edition/boot/store.go
Normal file
36
edition/boot/store.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package boot prepares runtime environment.
|
||||
package boot
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
account "github.com/documize/community/domain/account/mysql"
|
||||
audit "github.com/documize/community/domain/audit/mysql"
|
||||
org "github.com/documize/community/domain/organization/mysql"
|
||||
pin "github.com/documize/community/domain/pin/mysql"
|
||||
space "github.com/documize/community/domain/space/mysql"
|
||||
user "github.com/documize/community/domain/user/mysql"
|
||||
doc "github.com/documize/community/domain/document/mysql"
|
||||
)
|
||||
|
||||
// AttachStore selects database persistence layer
|
||||
func AttachStore(r *env.Runtime, s *domain.Store) {
|
||||
s.Space = space.Scope{Runtime: r}
|
||||
s.Account = account.Scope{Runtime: r}
|
||||
s.Organization = org.Scope{Runtime: r}
|
||||
s.User = user.Scope{Runtime: r}
|
||||
s.Pin = pin.Scope{Runtime: r}
|
||||
s.Audit = audit.Scope{Runtime: r}
|
||||
s.Document = doc.Scope{Runtime: r}
|
||||
}
|
|
@ -24,6 +24,7 @@ import (
|
|||
_ "github.com/documize/community/embed" // the compressed front-end code and static data
|
||||
"github.com/documize/community/server"
|
||||
_ "github.com/go-sql-driver/mysql" // the mysql driver is required behind the scenes
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
var rt env.Runtime
|
||||
|
@ -49,9 +50,12 @@ func main() {
|
|||
rt.Product.License.Trial = false
|
||||
rt.Product.License.Edition = "Community"
|
||||
|
||||
// setup store
|
||||
s := domain.Store{}
|
||||
|
||||
// parse settings from command line and environment
|
||||
rt.Flags = env.ParseFlags()
|
||||
flagsOK := boot.InitRuntime(&rt)
|
||||
flagsOK := boot.InitRuntime(&rt, &s)
|
||||
|
||||
if flagsOK {
|
||||
// runtime.Log = runtime.Log.SetDB(runtime.Db)
|
||||
|
@ -65,5 +69,5 @@ func main() {
|
|||
section.Register(rt)
|
||||
|
||||
ready := make(chan struct{}, 1) // channel signals router ready
|
||||
server.Start(&rt, ready)
|
||||
server.Start(&rt, &s, ready)
|
||||
}
|
||||
|
|
|
@ -11,19 +11,11 @@
|
|||
|
||||
package account
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
import "github.com/documize/community/model"
|
||||
|
||||
// Account links a User to an Organization.
|
||||
type Account struct {
|
||||
domain.BaseEntity
|
||||
model.BaseEntity
|
||||
Admin bool `json:"admin"`
|
||||
Editor bool `json:"editor"`
|
||||
UserID string `json:"userId"`
|
|
@ -10,7 +10,7 @@
|
|||
// https://documize.com
|
||||
|
||||
// Package eventing records and propagates events based on user actions.
|
||||
package eventing
|
||||
package audit
|
||||
|
||||
import "time"
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package domain ...
|
||||
package domain
|
||||
// Package model ...
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
|
@ -9,21 +9,13 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
package organization
|
||||
package org
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
import "github.com/documize/community/model"
|
||||
|
||||
// Organization defines a company that uses this app.
|
||||
type Organization struct {
|
||||
domain.BaseEntity
|
||||
model.BaseEntity
|
||||
Company string `json:"-"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
|
@ -11,19 +11,11 @@
|
|||
|
||||
package pin
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
import "github.com/documize/community/model"
|
||||
|
||||
// Pin defines a saved link to a document or space
|
||||
type Pin struct {
|
||||
domain.BaseEntity
|
||||
model.BaseEntity
|
||||
OrgID string `json:"orgId"`
|
||||
UserID string `json:"userId"`
|
||||
FolderID string `json:"folderId"`
|
|
@ -9,23 +9,13 @@
|
|||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
import "github.com/documize/community/model"
|
||||
|
||||
// Space defines a container for documents.
|
||||
type Space struct {
|
||||
domain.BaseEntity
|
||||
model.BaseEntity
|
||||
Name string `json:"name"`
|
||||
OrgID string `json:"orgId"`
|
||||
UserID string `json:"userId"`
|
||||
|
@ -63,7 +53,7 @@ func (l *Space) IsRestricted() bool {
|
|||
|
||||
// Role determines user permissions for a folder.
|
||||
type Role struct {
|
||||
domain.BaseEntityObfuscated
|
||||
model.BaseEntityObfuscated
|
||||
OrgID string `json:"-"`
|
||||
LabelID string `json:"folderId"`
|
||||
UserID string `json:"userId"`
|
|
@ -14,19 +14,13 @@ package user
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/account"
|
||||
"github.com/documize/community/model"
|
||||
"github.com/documize/community/model/account"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime *env.Runtime
|
||||
}
|
||||
|
||||
// User defines a login.
|
||||
type User struct {
|
||||
domain.BaseEntity
|
||||
model.BaseEntity
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Email string `json:"email"`
|
|
@ -25,10 +25,12 @@ import (
|
|||
"github.com/documize/community/domain/auth"
|
||||
"github.com/documize/community/domain/organization"
|
||||
"github.com/documize/community/domain/user"
|
||||
"github.com/documize/community/model/org"
|
||||
)
|
||||
|
||||
type middleware struct {
|
||||
Runtime *env.Runtime
|
||||
Store *domain.Store
|
||||
}
|
||||
|
||||
func (m *middleware) cors(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
|
@ -65,8 +67,6 @@ func (m *middleware) metrics(w http.ResponseWriter, r *http.Request, next http.H
|
|||
func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
method := "Authorize"
|
||||
|
||||
s := domain.StoreContext{Runtime: m.Runtime, Context: domain.RequestContext{}}
|
||||
|
||||
// Let certain requests pass straight through
|
||||
authenticated := preAuthorizeStaticAssets(m.Runtime, r)
|
||||
|
||||
|
@ -74,13 +74,15 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
|
|||
token := auth.FindJWT(r)
|
||||
rc, _, tokenErr := auth.DecodeJWT(m.Runtime, token)
|
||||
|
||||
var org = organization.Organization{}
|
||||
var org = org.Organization{}
|
||||
var err = errors.New("")
|
||||
|
||||
if len(rc.OrgID) == 0 {
|
||||
org, err = organization.GetOrganizationByDomain(s, organization.GetRequestSubdomain(s, r))
|
||||
dom := organization.GetRequestSubdomain(r)
|
||||
dom = m.Store.Organization.CheckDomain(rc, dom)
|
||||
org, err = m.Store.Organization.GetOrganizationByDomain(rc, dom)
|
||||
} else {
|
||||
org, err = organization.GetOrganization(s, rc.OrgID)
|
||||
org, err = m.Store.Organization.GetOrganization(rc, rc.OrgID)
|
||||
}
|
||||
|
||||
// Inability to find org record spells the end of this request.
|
||||
|
@ -96,8 +98,8 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
|
|||
}
|
||||
|
||||
rc.Subdomain = org.Domain
|
||||
dom := organization.GetSubdomainFromHost(s, r)
|
||||
dom2 := organization.GetRequestSubdomain(s, r)
|
||||
dom := organization.GetSubdomainFromHost(r)
|
||||
dom2 := organization.GetRequestSubdomain(r)
|
||||
|
||||
if org.Domain != dom && org.Domain != dom2 {
|
||||
m.Runtime.Log.Info(fmt.Sprintf("domain mismatch %s vs. %s vs. %s", dom, dom2, org.Domain))
|
||||
|
@ -130,7 +132,7 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
|
|||
rc.Editor = false
|
||||
rc.Global = false
|
||||
rc.AppURL = r.Host
|
||||
rc.Subdomain = organization.GetSubdomainFromHost(s, r)
|
||||
rc.Subdomain = organization.GetSubdomainFromHost(r)
|
||||
rc.SSL = r.TLS != nil
|
||||
|
||||
// get user IP from request
|
||||
|
@ -148,8 +150,7 @@ func (m *middleware) Authorize(w http.ResponseWriter, r *http.Request, next http
|
|||
|
||||
// Fetch user permissions for this org
|
||||
if rc.Authenticated {
|
||||
u, err := user.GetSecuredUser(s, org.RefID, rc.UserID)
|
||||
|
||||
u, err := user.GetSecuredUser(rc, *m.Store, org.RefID, rc.UserID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
|
|
|
@ -17,11 +17,15 @@ import (
|
|||
"github.com/documize/community/core/api"
|
||||
"github.com/documize/community/core/api/endpoint"
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/organization"
|
||||
"github.com/documize/community/domain/pin"
|
||||
"github.com/documize/community/domain/space"
|
||||
"github.com/documize/community/server/web"
|
||||
)
|
||||
|
||||
// RegisterEndpoints register routes for serving API endpoints
|
||||
func RegisterEndpoints(rt *env.Runtime) {
|
||||
func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
|
||||
//**************************************************
|
||||
// Non-secure routes
|
||||
//**************************************************
|
||||
|
@ -75,20 +79,22 @@ func RegisterEndpoints(rt *env.Runtime) {
|
|||
Add(rt, RoutePrefixPrivate, "documents/{documentID}/pages/{pageID}/copy/{targetID}", []string{"POST", "OPTIONS"}, nil, endpoint.CopyPage)
|
||||
|
||||
// Organization
|
||||
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"GET", "OPTIONS"}, nil, endpoint.GetOrganization)
|
||||
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"PUT", "OPTIONS"}, nil, endpoint.UpdateOrganization)
|
||||
organization := organization.Handler{Runtime: rt, Store: s}
|
||||
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"GET", "OPTIONS"}, nil, organization.Get)
|
||||
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"PUT", "OPTIONS"}, nil, organization.Update)
|
||||
|
||||
// Folder
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"DELETE", "OPTIONS"}, nil, endpoint.DeleteFolder)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/move/{moveToId}", []string{"DELETE", "OPTIONS"}, nil, endpoint.RemoveFolder)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/permissions", []string{"PUT", "OPTIONS"}, nil, endpoint.SetFolderPermissions)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/permissions", []string{"GET", "OPTIONS"}, nil, endpoint.GetFolderPermissions)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/invitation", []string{"POST", "OPTIONS"}, nil, endpoint.InviteToFolder)
|
||||
Add(rt, RoutePrefixPrivate, "folders", []string{"GET", "OPTIONS"}, []string{"filter", "viewers"}, endpoint.GetFolderVisibility)
|
||||
Add(rt, RoutePrefixPrivate, "folders", []string{"POST", "OPTIONS"}, nil, endpoint.AddFolder)
|
||||
Add(rt, RoutePrefixPrivate, "folders", []string{"GET", "OPTIONS"}, nil, endpoint.GetFolders)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"GET", "OPTIONS"}, nil, endpoint.GetFolder)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"PUT", "OPTIONS"}, nil, endpoint.UpdateFolder)
|
||||
// Space
|
||||
space := space.Handler{Runtime: rt, Store: s}
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"DELETE", "OPTIONS"}, nil, space.Delete)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/move/{moveToId}", []string{"DELETE", "OPTIONS"}, nil, space.Remove)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/permissions", []string{"PUT", "OPTIONS"}, nil, space.SetPermissions)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/permissions", []string{"GET", "OPTIONS"}, nil, space.GetPermissions)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/invitation", []string{"POST", "OPTIONS"}, nil, space.Invite)
|
||||
Add(rt, RoutePrefixPrivate, "folders", []string{"GET", "OPTIONS"}, []string{"filter", "viewers"}, space.GetSpaceViewers)
|
||||
Add(rt, RoutePrefixPrivate, "folders", []string{"POST", "OPTIONS"}, nil, space.Add)
|
||||
Add(rt, RoutePrefixPrivate, "folders", []string{"GET", "OPTIONS"}, nil, space.GetAll)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"GET", "OPTIONS"}, nil, space.Get)
|
||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"PUT", "OPTIONS"}, nil, space.Update)
|
||||
|
||||
// Users
|
||||
Add(rt, RoutePrefixPrivate, "users/{userID}/password", []string{"POST", "OPTIONS"}, nil, endpoint.ChangeUserPassword)
|
||||
|
@ -136,10 +142,11 @@ func RegisterEndpoints(rt *env.Runtime) {
|
|||
Add(rt, RoutePrefixPrivate, "global/auth", []string{"PUT", "OPTIONS"}, nil, endpoint.SaveAuthConfig)
|
||||
|
||||
// Pinned items
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, endpoint.AddPin)
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}", []string{"GET", "OPTIONS"}, nil, endpoint.GetUserPins)
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}/sequence", []string{"POST", "OPTIONS"}, nil, endpoint.UpdatePinSequence)
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}/{pinID}", []string{"DELETE", "OPTIONS"}, nil, endpoint.DeleteUserPin)
|
||||
pin := pin.Handler{Runtime: rt, Store: s}
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, pin.Add)
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}", []string{"GET", "OPTIONS"}, nil, pin.GetUserPins)
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}/sequence", []string{"POST", "OPTIONS"}, nil, pin.UpdatePinSequence)
|
||||
Add(rt, RoutePrefixPrivate, "pin/{userID}/{pinID}", []string{"DELETE", "OPTIONS"}, nil, pin.DeleteUserPin)
|
||||
|
||||
// Single page app handler
|
||||
Add(rt, RoutePrefixRoot, "robots.txt", []string{"GET", "OPTIONS"}, nil, endpoint.GetRobots)
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/documize/community/core/api/plugins"
|
||||
"github.com/documize/community/core/database"
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/server/routing"
|
||||
"github.com/documize/community/server/web"
|
||||
"github.com/gorilla/mux"
|
||||
|
@ -30,8 +31,7 @@ import (
|
|||
var testHost string // used during automated testing
|
||||
|
||||
// Start router to handle all HTTP traffic.
|
||||
func Start(rt *env.Runtime, ready chan struct{}) {
|
||||
|
||||
func Start(rt *env.Runtime, s *domain.Store, ready chan struct{}) {
|
||||
err := plugins.LibSetup()
|
||||
if err != nil {
|
||||
rt.Log.Error("Terminating before running - invalid plugin.json", err)
|
||||
|
@ -54,10 +54,10 @@ func Start(rt *env.Runtime, ready chan struct{}) {
|
|||
}
|
||||
|
||||
// define middleware
|
||||
cm := middleware{Runtime: rt}
|
||||
cm := middleware{Runtime: rt, Store: s}
|
||||
|
||||
// define API endpoints
|
||||
routing.RegisterEndpoints(rt)
|
||||
routing.RegisterEndpoints(rt, s)
|
||||
|
||||
// wire up API endpoints
|
||||
router := mux.NewRouter()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue