mirror of
https://github.com/documize/community.git
synced 2025-08-07 22:45:24 +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
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)
|
||||
}
|
||||
*/
|
|
@ -1,65 +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 user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/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
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Email string `json:"email"`
|
||||
Initials string `json:"initials"`
|
||||
Active bool `json:"active"`
|
||||
Editor bool `json:"editor"`
|
||||
Admin bool `json:"admin"`
|
||||
Global bool `json:"global"`
|
||||
Password string `json:"-"`
|
||||
Salt string `json:"-"`
|
||||
Reset string `json:"-"`
|
||||
Accounts []account.Account `json:"accounts"`
|
||||
}
|
||||
|
||||
// ProtectSecrets blanks sensitive data.
|
||||
func (user *User) ProtectSecrets() {
|
||||
user.Password = ""
|
||||
user.Salt = ""
|
||||
user.Reset = ""
|
||||
}
|
||||
|
||||
// Fullname returns Firstname + Lastname.
|
||||
func (user *User) Fullname() string {
|
||||
return fmt.Sprintf("%s %s", user.Firstname, user.Lastname)
|
||||
}
|
||||
|
||||
// GetAccount returns matching org account using orgID
|
||||
func (user *User) GetAccount(orgID string) (a account.Account, found bool) {
|
||||
for _, a := range user.Accounts {
|
||||
if a.OrgID == orgID {
|
||||
return a, true
|
||||
}
|
||||
}
|
||||
|
||||
return a, false
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue