github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/api/endpoint/label_endpoint.go (about)

     1  // Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
     2  //
     3  // This software (Documize Community Edition) is licensed under
     4  // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
     5  //
     6  // You can operate outside the AGPL restrictions by purchasing
     7  // Documize Enterprise Edition and obtaining a commercial license
     8  // by contacting <sales@documize.com>.
     9  //
    10  // https://documize.com
    11  
    12  package endpoint
    13  
    14  import (
    15  	"database/sql"
    16  	"encoding/json"
    17  	"fmt"
    18  	"io/ioutil"
    19  	"net/http"
    20  	"strings"
    21  
    22  	"github.com/gorilla/mux"
    23  
    24  	"github.com/documize/community/documize/api/endpoint/models"
    25  	"github.com/documize/community/documize/api/entity"
    26  	"github.com/documize/community/documize/api/mail"
    27  	"github.com/documize/community/documize/api/request"
    28  	"github.com/documize/community/documize/api/util"
    29  	"github.com/documize/community/wordsmith/log"
    30  	"github.com/documize/community/wordsmith/utility"
    31  )
    32  
    33  // AddFolder creates a new folder.
    34  func AddFolder(w http.ResponseWriter, r *http.Request) {
    35  	method := "AddFolder"
    36  	p := request.GetPersister(r)
    37  
    38  	if !p.Context.Editor {
    39  		writeForbiddenError(w)
    40  		return
    41  	}
    42  
    43  	defer utility.Close(r.Body)
    44  	body, err := ioutil.ReadAll(r.Body)
    45  
    46  	if err != nil {
    47  		writePayloadError(w, method, err)
    48  		return
    49  	}
    50  
    51  	var folder = entity.Label{}
    52  	err = json.Unmarshal(body, &folder)
    53  
    54  	if len(folder.Name) == 0 {
    55  		writeJSONMarshalError(w, method, "folder", err)
    56  		return
    57  	}
    58  
    59  	tx, err := request.Db.Beginx()
    60  
    61  	if err != nil {
    62  		writeTransactionError(w, method, err)
    63  		return
    64  	}
    65  
    66  	p.Context.Transaction = tx
    67  
    68  	id := util.UniqueID()
    69  	folder.RefID = id
    70  	folder.OrgID = p.Context.OrgID
    71  	err = addFolder(p, &folder)
    72  
    73  	if err != nil {
    74  		log.IfErr(tx.Rollback())
    75  		writeGeneralSQLError(w, method, err)
    76  		return
    77  	}
    78  
    79  	log.IfErr(tx.Commit())
    80  
    81  	folder, err = p.GetLabel(id)
    82  
    83  	json, err := json.Marshal(folder)
    84  
    85  	if err != nil {
    86  		writeJSONMarshalError(w, method, "folder", err)
    87  		return
    88  	}
    89  
    90  	writeSuccessBytes(w, json)
    91  }
    92  
    93  func addFolder(p request.Persister, label *entity.Label) (err error) {
    94  	label.Type = entity.FolderTypePrivate
    95  	label.UserID = p.Context.UserID
    96  
    97  	err = p.AddLabel(*label)
    98  
    99  	if err != nil {
   100  		return
   101  	}
   102  
   103  	role := entity.LabelRole{}
   104  	role.LabelID = label.RefID
   105  	role.OrgID = label.OrgID
   106  	role.UserID = p.Context.UserID
   107  	role.CanEdit = true
   108  	role.CanView = true
   109  	refID := util.UniqueID()
   110  	role.RefID = refID
   111  
   112  	err = p.AddLabelRole(role)
   113  
   114  	return
   115  }
   116  
   117  // GetFolder returns the requested folder.
   118  func GetFolder(w http.ResponseWriter, r *http.Request) {
   119  	method := "GetFolder"
   120  	p := request.GetPersister(r)
   121  
   122  	params := mux.Vars(r)
   123  	id := params["folderID"]
   124  
   125  	if len(id) == 0 {
   126  		writeMissingDataError(w, method, "folderID")
   127  		return
   128  	}
   129  
   130  	folder, err := p.GetLabel(id)
   131  
   132  	if err != nil && err != sql.ErrNoRows {
   133  		writeServerError(w, method, err)
   134  		return
   135  	}
   136  
   137  	if err == sql.ErrNoRows {
   138  		writeNotFoundError(w, method, id)
   139  		return
   140  	}
   141  
   142  	json, err := json.Marshal(folder)
   143  
   144  	if err != nil {
   145  		writeJSONMarshalError(w, method, "folder", err)
   146  		return
   147  	}
   148  
   149  	writeSuccessBytes(w, json)
   150  }
   151  
   152  // GetFolders returns the folders the user can see.
   153  func GetFolders(w http.ResponseWriter, r *http.Request) {
   154  	method := "GetFolders"
   155  	p := request.GetPersister(r)
   156  
   157  	folders, err := p.GetLabels()
   158  
   159  	if err != nil && err != sql.ErrNoRows {
   160  		writeServerError(w, method, err)
   161  		return
   162  	}
   163  
   164  	if len(folders) == 0 {
   165  		folders = []entity.Label{}
   166  	}
   167  
   168  	json, err := json.Marshal(folders)
   169  
   170  	if err != nil {
   171  		writeJSONMarshalError(w, method, "folder", err)
   172  		return
   173  	}
   174  
   175  	writeSuccessBytes(w, json)
   176  }
   177  
   178  // GetFolderVisibility returns the users that can see the shared folders.
   179  func GetFolderVisibility(w http.ResponseWriter, r *http.Request) {
   180  	method := "GetFolderVisibility"
   181  	p := request.GetPersister(r)
   182  
   183  	folders, err := p.GetFolderVisibility()
   184  
   185  	if err != nil && err != sql.ErrNoRows {
   186  		writeServerError(w, method, err)
   187  		return
   188  	}
   189  
   190  	json, err := json.Marshal(folders)
   191  
   192  	if err != nil {
   193  		writeJSONMarshalError(w, method, "folder", err)
   194  		return
   195  	}
   196  
   197  	writeSuccessBytes(w, json)
   198  }
   199  
   200  // UpdateFolder processes request to save folder object to the database
   201  func UpdateFolder(w http.ResponseWriter, r *http.Request) {
   202  	method := "UpdateFolder"
   203  	p := request.GetPersister(r)
   204  
   205  	if !p.Context.Editor {
   206  		writeForbiddenError(w)
   207  		return
   208  	}
   209  
   210  	params := mux.Vars(r)
   211  	folderID := params["folderID"]
   212  
   213  	if len(folderID) == 0 {
   214  		writeMissingDataError(w, method, "folderID")
   215  		return
   216  	}
   217  
   218  	defer utility.Close(r.Body)
   219  	body, err := ioutil.ReadAll(r.Body)
   220  
   221  	if err != nil {
   222  		writePayloadError(w, method, err)
   223  		return
   224  	}
   225  
   226  	var folder = entity.Label{}
   227  	err = json.Unmarshal(body, &folder)
   228  
   229  	if len(folder.Name) == 0 {
   230  		writeJSONMarshalError(w, method, "folder", err)
   231  		return
   232  	}
   233  
   234  	folder.RefID = folderID
   235  
   236  	tx, err := request.Db.Beginx()
   237  
   238  	if err != nil {
   239  		writeTransactionError(w, method, err)
   240  		return
   241  	}
   242  
   243  	p.Context.Transaction = tx
   244  
   245  	err = p.UpdateLabel(folder)
   246  
   247  	if err != nil {
   248  		log.IfErr(tx.Rollback())
   249  		writeGeneralSQLError(w, method, err)
   250  		return
   251  	}
   252  
   253  	log.IfErr(tx.Commit())
   254  
   255  	json, err := json.Marshal(folder)
   256  
   257  	if err != nil {
   258  		writeJSONMarshalError(w, method, "folder", err)
   259  		return
   260  	}
   261  
   262  	writeSuccessBytes(w, json)
   263  }
   264  
   265  // RemoveFolder moves documents to another folder before deleting it
   266  func RemoveFolder(w http.ResponseWriter, r *http.Request) {
   267  	method := "RemoveFolder"
   268  	p := request.GetPersister(r)
   269  
   270  	if !p.Context.Editor {
   271  		writeForbiddenError(w)
   272  		return
   273  	}
   274  
   275  	params := mux.Vars(r)
   276  	id := params["folderID"]
   277  	move := params["moveToId"]
   278  
   279  	if len(id) == 0 {
   280  		writeMissingDataError(w, method, "folderID")
   281  		return
   282  	}
   283  
   284  	if len(move) == 0 {
   285  		writeMissingDataError(w, method, "moveToId")
   286  		return
   287  	}
   288  
   289  	tx, err := request.Db.Beginx()
   290  
   291  	if err != nil {
   292  		writeTransactionError(w, method, err)
   293  		return
   294  	}
   295  
   296  	p.Context.Transaction = tx
   297  
   298  	_, err = p.DeleteLabel(id)
   299  
   300  	if err != nil {
   301  		log.IfErr(tx.Rollback())
   302  		writeServerError(w, method, err)
   303  		return
   304  	}
   305  
   306  	err = p.MoveDocumentLabel(id, move)
   307  
   308  	if err != nil {
   309  		log.IfErr(tx.Rollback())
   310  		writeServerError(w, method, err)
   311  		return
   312  	}
   313  
   314  	err = p.MoveLabelRoles(id, move)
   315  
   316  	if err != nil {
   317  		log.IfErr(tx.Rollback())
   318  		writeServerError(w, method, err)
   319  		return
   320  	}
   321  
   322  	log.IfErr(tx.Commit())
   323  
   324  	writeSuccessString(w, "{}")
   325  }
   326  
   327  // SetFolderPermissions persists specified folder permissions
   328  func SetFolderPermissions(w http.ResponseWriter, r *http.Request) {
   329  	method := "SetFolderPermissions"
   330  	p := request.GetPersister(r)
   331  
   332  	params := mux.Vars(r)
   333  	id := params["folderID"]
   334  
   335  	if len(id) == 0 {
   336  		writeMissingDataError(w, method, "folderID")
   337  		return
   338  	}
   339  
   340  	label, err := p.GetLabel(id)
   341  
   342  	if err != nil {
   343  		writeBadRequestError(w, method, "No such folder")
   344  		return
   345  	}
   346  
   347  	if label.UserID != p.Context.UserID {
   348  		writeForbiddenError(w)
   349  		return
   350  	}
   351  
   352  	defer utility.Close(r.Body)
   353  	body, err := ioutil.ReadAll(r.Body)
   354  
   355  	if err != nil {
   356  		writePayloadError(w, method, err)
   357  		return
   358  	}
   359  
   360  	var model = models.FolderRolesModel{}
   361  	err = json.Unmarshal(body, &model)
   362  
   363  	tx, err := request.Db.Beginx()
   364  
   365  	if err != nil {
   366  		writeTransactionError(w, method, err)
   367  		return
   368  	}
   369  
   370  	p.Context.Transaction = tx
   371  
   372  	// We compare new permisions to what we had before.
   373  	// Why? So we can send out folder invitation emails.
   374  	previousRoles, err := p.GetLabelRoles(id)
   375  
   376  	if err != nil {
   377  		writeGeneralSQLError(w, method, err)
   378  		return
   379  	}
   380  
   381  	// Store all previous roles as map for easy querying
   382  	previousRoleUsers := make(map[string]bool)
   383  
   384  	for _, v := range previousRoles {
   385  		previousRoleUsers[v.UserID] = true
   386  	}
   387  
   388  	// Who is sharing this folder?
   389  	inviter, err := p.GetUser(p.Context.UserID)
   390  
   391  	if err != nil {
   392  		log.IfErr(tx.Rollback())
   393  		writeGeneralSQLError(w, method, err)
   394  		return
   395  	}
   396  
   397  	// Nuke all previous permissions for this folder
   398  	_, err = p.DeleteLabelRoles(id)
   399  
   400  	if err != nil {
   401  		log.IfErr(tx.Rollback())
   402  		writeGeneralSQLError(w, method, err)
   403  		return
   404  	}
   405  
   406  	me := false
   407  	hasEveryoneRole := false
   408  	roleCount := 0
   409  
   410  	url := getAppURL(p.Context, fmt.Sprintf("s/%s/%s", label.RefID, utility.MakeSlug(label.Name)))
   411  
   412  	for _, role := range model.Roles {
   413  		role.OrgID = p.Context.OrgID
   414  		role.LabelID = id
   415  
   416  		// Ensure the folder owner always has access!
   417  		if role.UserID == p.Context.UserID {
   418  			me = true
   419  			role.CanView = true
   420  			role.CanEdit = true
   421  		}
   422  
   423  		if len(role.UserID) == 0 && (role.CanView || role.CanEdit) {
   424  			hasEveryoneRole = true
   425  		}
   426  
   427  		// Only persist if there is a role!
   428  		if role.CanView || role.CanEdit {
   429  			roleID := util.UniqueID()
   430  			role.RefID = roleID
   431  			err = p.AddLabelRole(role)
   432  			roleCount++
   433  			log.IfErr(err)
   434  
   435  			// We send out folder invitation emails to those users
   436  			// that have *just* been given permissions.
   437  			if _, isExisting := previousRoleUsers[role.UserID]; !isExisting {
   438  
   439  				// we skip 'everyone' (user id != empty string)
   440  				if len(role.UserID) > 0 {
   441  					var existingUser entity.User
   442  					existingUser, err = p.GetUser(role.UserID)
   443  
   444  					if err == nil {
   445  						go mail.ShareFolderExistingUser(existingUser.Email, inviter.Fullname(), url, label.Name, model.Message)
   446  						log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, label.Name, existingUser.Email))
   447  					} else {
   448  						writeServerError(w, method, err)
   449  					}
   450  				}
   451  			}
   452  		}
   453  	}
   454  
   455  	// Do we need to ensure permissions for folder owner when shared?
   456  	if !me {
   457  		role := entity.LabelRole{}
   458  		role.LabelID = id
   459  		role.OrgID = p.Context.OrgID
   460  		role.UserID = p.Context.UserID
   461  		role.CanEdit = true
   462  		role.CanView = true
   463  		roleID := util.UniqueID()
   464  		role.RefID = roleID
   465  		err = p.AddLabelRole(role)
   466  		log.IfErr(err)
   467  	}
   468  
   469  	// Mark up folder type as either public, private or restricted access.
   470  	if hasEveryoneRole {
   471  		label.Type = entity.FolderTypePublic
   472  	} else {
   473  		if roleCount > 1 {
   474  			label.Type = entity.FolderTypeRestricted
   475  		} else {
   476  			label.Type = entity.FolderTypePrivate
   477  		}
   478  	}
   479  
   480  	log.Error("p.UpdateLabel()", p.UpdateLabel(label))
   481  
   482  	log.Error("tx.Commit()", tx.Commit())
   483  
   484  	writeSuccessEmptyJSON(w)
   485  }
   486  
   487  // GetFolderPermissions returns user permissions for the requested folder.
   488  func GetFolderPermissions(w http.ResponseWriter, r *http.Request) {
   489  	method := "GetFolderPermissions"
   490  	p := request.GetPersister(r)
   491  
   492  	params := mux.Vars(r)
   493  	folderID := params["folderID"]
   494  
   495  	if len(folderID) == 0 {
   496  		writeMissingDataError(w, method, "folderID")
   497  		return
   498  	}
   499  
   500  	roles, err := p.GetLabelRoles(folderID)
   501  
   502  	if err != nil && err != sql.ErrNoRows {
   503  		writeGeneralSQLError(w, method, err)
   504  		return
   505  	}
   506  
   507  	if len(roles) == 0 {
   508  		roles = []entity.LabelRole{}
   509  	}
   510  
   511  	json, err := json.Marshal(roles)
   512  
   513  	if err != nil {
   514  		writeJSONMarshalError(w, method, "folder-permissions", err)
   515  		return
   516  	}
   517  
   518  	writeSuccessBytes(w, json)
   519  }
   520  
   521  // AcceptSharedFolder records the fact that a user has completed folder onboard process.
   522  func AcceptSharedFolder(w http.ResponseWriter, r *http.Request) {
   523  	method := "AcceptSharedFolder"
   524  	p := request.GetPersister(r)
   525  
   526  	params := mux.Vars(r)
   527  	folderID := params["folderID"]
   528  
   529  	if len(folderID) == 0 {
   530  		writeMissingDataError(w, method, "folderID")
   531  		return
   532  	}
   533  
   534  	org, err := p.GetOrganizationByDomain(p.Context.Subdomain)
   535  
   536  	if err != nil {
   537  		writeGeneralSQLError(w, method, err)
   538  		return
   539  	}
   540  
   541  	p.Context.OrgID = org.RefID
   542  
   543  	defer utility.Close(r.Body)
   544  	body, err := ioutil.ReadAll(r.Body)
   545  
   546  	if err != nil {
   547  		writePayloadError(w, method, err)
   548  		return
   549  	}
   550  
   551  	var model = models.AcceptSharedFolderModel{}
   552  	err = json.Unmarshal(body, &model)
   553  
   554  	if err != nil {
   555  		writePayloadError(w, method, err)
   556  		return
   557  	}
   558  
   559  	if len(model.Serial) == 0 || len(model.Firstname) == 0 || len(model.Lastname) == 0 || len(model.Password) == 0 {
   560  		writeJSONMarshalError(w, method, "missing field data", err)
   561  		return
   562  	}
   563  
   564  	if err != nil {
   565  		writeGeneralSQLError(w, method, err)
   566  		return
   567  	}
   568  
   569  	user, err := p.GetUserBySerial(model.Serial)
   570  
   571  	// User has already on-boarded.
   572  	if err != nil && err == sql.ErrNoRows {
   573  		writeDuplicateError(w, method, "user")
   574  		return
   575  	}
   576  
   577  	if err != nil {
   578  		writeGeneralSQLError(w, method, err)
   579  		return
   580  	}
   581  
   582  	user.Firstname = model.Firstname
   583  	user.Lastname = model.Lastname
   584  	user.Initials = utility.MakeInitials(user.Firstname, user.Lastname)
   585  
   586  	tx, err := request.Db.Beginx()
   587  
   588  	if err != nil {
   589  		writeTransactionError(w, method, err)
   590  		return
   591  	}
   592  
   593  	p.Context.Transaction = tx
   594  
   595  	err = p.UpdateUser(user)
   596  
   597  	if err != nil {
   598  		log.IfErr(tx.Rollback())
   599  		writeGeneralSQLError(w, method, err)
   600  		return
   601  	}
   602  
   603  	salt := util.GenerateSalt()
   604  
   605  	log.IfErr(p.UpdateUserPassword(user.RefID, salt, util.GeneratePassword(model.Password, salt)))
   606  
   607  	if err != nil {
   608  		log.IfErr(tx.Rollback())
   609  		writeGeneralSQLError(w, method, err)
   610  		return
   611  	}
   612  
   613  	log.IfErr(tx.Commit())
   614  
   615  	data, err := json.Marshal(user)
   616  
   617  	if err != nil {
   618  		writeJSONMarshalError(w, method, "user", err)
   619  		return
   620  	}
   621  
   622  	writeSuccessBytes(w, data)
   623  }
   624  
   625  // InviteToFolder sends users folder invitation emails.
   626  func InviteToFolder(w http.ResponseWriter, r *http.Request) {
   627  	method := "InviteToFolder"
   628  	p := request.GetPersister(r)
   629  
   630  	params := mux.Vars(r)
   631  	id := params["folderID"]
   632  
   633  	if len(id) == 0 {
   634  		writeMissingDataError(w, method, "folderID")
   635  		return
   636  	}
   637  
   638  	label, err := p.GetLabel(id)
   639  
   640  	if err != nil {
   641  		writeBadRequestError(w, method, "folder not found")
   642  		return
   643  	}
   644  
   645  	if label.UserID != p.Context.UserID {
   646  		writeForbiddenError(w)
   647  		return
   648  	}
   649  
   650  	defer utility.Close(r.Body)
   651  	body, err := ioutil.ReadAll(r.Body)
   652  
   653  	if err != nil {
   654  		writePayloadError(w, method, err)
   655  		return
   656  	}
   657  
   658  	var model = models.FolderInvitationModel{}
   659  	err = json.Unmarshal(body, &model)
   660  
   661  	tx, err := request.Db.Beginx()
   662  
   663  	if err != nil {
   664  		writeTransactionError(w, method, err)
   665  		return
   666  	}
   667  
   668  	p.Context.Transaction = tx
   669  
   670  	inviter, err := p.GetUser(p.Context.UserID)
   671  
   672  	if err != nil {
   673  		writeGeneralSQLError(w, method, err)
   674  		return
   675  	}
   676  
   677  	for _, email := range model.Recipients {
   678  		var user entity.User
   679  		user, err = p.GetUserByEmail(email)
   680  
   681  		if err != nil && err != sql.ErrNoRows {
   682  			log.IfErr(tx.Rollback())
   683  			writeGeneralSQLError(w, method, err)
   684  			return
   685  		}
   686  
   687  		if len(user.RefID) > 0 {
   688  
   689  			// Ensure they have access to this organization
   690  			accounts, err2 := p.GetUserAccounts(user.RefID)
   691  
   692  			if err2 != nil {
   693  				log.IfErr(tx.Rollback())
   694  				writeGeneralSQLError(w, method, err2)
   695  				return
   696  			}
   697  
   698  			// we create if they c
   699  			hasAccess := false
   700  			for _, a := range accounts {
   701  				if a.OrgID == p.Context.OrgID {
   702  					hasAccess = true
   703  				}
   704  			}
   705  
   706  			if !hasAccess {
   707  				var a entity.Account
   708  				a.UserID = user.RefID
   709  				a.OrgID = p.Context.OrgID
   710  				a.Admin = false
   711  				a.Editor = false
   712  				accountID := util.UniqueID()
   713  				a.RefID = accountID
   714  
   715  				err = p.AddAccount(a)
   716  
   717  				if err != nil {
   718  					log.IfErr(tx.Rollback())
   719  					writeGeneralSQLError(w, method, err)
   720  					return
   721  				}
   722  			}
   723  
   724  			// Ensure they have folder roles
   725  			_, err = p.DeleteUserFolderRoles(label.RefID, user.RefID)
   726  			log.IfErr(err)
   727  
   728  			role := entity.LabelRole{}
   729  			role.LabelID = label.RefID
   730  			role.OrgID = p.Context.OrgID
   731  			role.UserID = user.RefID
   732  			role.CanEdit = false
   733  			role.CanView = true
   734  			roleID := util.UniqueID()
   735  			role.RefID = roleID
   736  
   737  			err = p.AddLabelRole(role)
   738  
   739  			if err != nil {
   740  				log.IfErr(tx.Rollback())
   741  				writeGeneralSQLError(w, method, err)
   742  				return
   743  			}
   744  
   745  			url := getAppURL(p.Context, fmt.Sprintf("s/%s/%s", label.RefID, utility.MakeSlug(label.Name)))
   746  			go mail.ShareFolderExistingUser(email, inviter.Fullname(), url, label.Name, model.Message)
   747  			log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, label.Name, email))
   748  		} else {
   749  			// On-board new user
   750  			if strings.Contains(email, "@") {
   751  				url := getAppURL(p.Context, fmt.Sprintf("auth/share/%s/%s", label.RefID, utility.MakeSlug(label.Name)))
   752  				err = inviteNewUserToSharedFolder(p, email, inviter, url, label, model.Message)
   753  
   754  				if err != nil {
   755  					log.IfErr(tx.Rollback())
   756  					writeServerError(w, method, err)
   757  					return
   758  				}
   759  
   760  				log.Info(fmt.Sprintf("%s is sharing space %s with new user %s", inviter.Email, label.Name, email))
   761  			}
   762  		}
   763  	}
   764  
   765  	// We ensure that the folder is marked as restricted as a minimum!
   766  	if len(model.Recipients) > 0 && label.Type == entity.FolderTypePrivate {
   767  		label.Type = entity.FolderTypeRestricted
   768  		err = p.UpdateLabel(label)
   769  
   770  		if err != nil {
   771  			log.IfErr(tx.Rollback())
   772  			writeServerError(w, method, err)
   773  			return
   774  		}
   775  	}
   776  
   777  	log.IfErr(tx.Commit())
   778  
   779  	_, err = w.Write([]byte("{}"))
   780  	log.IfErr(err)
   781  }
   782  
   783  // Invite new user to a folder that someone has shared with them.
   784  // We create the user account with default values and then take them
   785  // through a welcome process designed to capture profile data.
   786  // We add them to the organization and grant them view-only folder access.
   787  func inviteNewUserToSharedFolder(p request.Persister, email string, invitedBy entity.User,
   788  	baseURL string, label entity.Label, invitationMessage string) (err error) {
   789  
   790  	var user = entity.User{}
   791  	user.Email = email
   792  	user.Firstname = email
   793  	user.Lastname = ""
   794  	user.Salt = util.GenerateSalt()
   795  	requestedPassword := util.GenerateRandomPassword()
   796  	user.Password = util.GeneratePassword(requestedPassword, user.Salt)
   797  	userID := util.UniqueID()
   798  	user.RefID = userID
   799  
   800  	err = p.AddUser(user)
   801  
   802  	if err != nil {
   803  		return
   804  	}
   805  
   806  	// Let's give this user access to the organization
   807  	var a entity.Account
   808  	a.UserID = userID
   809  	a.OrgID = p.Context.OrgID
   810  	a.Admin = false
   811  	a.Editor = false
   812  	accountID := util.UniqueID()
   813  	a.RefID = accountID
   814  
   815  	err = p.AddAccount(a)
   816  
   817  	if err != nil {
   818  		return
   819  	}
   820  
   821  	role := entity.LabelRole{}
   822  	role.LabelID = label.RefID
   823  	role.OrgID = p.Context.OrgID
   824  	role.UserID = userID
   825  	role.CanEdit = false
   826  	role.CanView = true
   827  	roleID := util.UniqueID()
   828  	role.RefID = roleID
   829  
   830  	err = p.AddLabelRole(role)
   831  
   832  	if err != nil {
   833  		return
   834  	}
   835  
   836  	url := fmt.Sprintf("%s/%s", baseURL, user.Salt)
   837  	go mail.ShareFolderNewUser(user.Email, invitedBy.Fullname(), url, label.Name, invitationMessage)
   838  
   839  	return
   840  }