github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/core/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/core/api/endpoint/models"
    25  	"github.com/documize/community/core/api/entity"
    26  	"github.com/documize/community/core/api/mail"
    27  	"github.com/documize/community/core/api/request"
    28  	"github.com/documize/community/core/api/util"
    29  	"github.com/documize/community/core/log"
    30  	"github.com/documize/community/core/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  	_, err = p.DeletePinnedSpace(id)
   323  
   324  	if err != nil && err != sql.ErrNoRows {
   325  		log.IfErr(tx.Rollback())
   326  		writeServerError(w, method, err)
   327  		return
   328  	}
   329  
   330  	log.IfErr(tx.Commit())
   331  
   332  	writeSuccessString(w, "{}")
   333  }
   334  
   335  // SetFolderPermissions persists specified folder permissions
   336  func SetFolderPermissions(w http.ResponseWriter, r *http.Request) {
   337  	method := "SetFolderPermissions"
   338  	p := request.GetPersister(r)
   339  
   340  	params := mux.Vars(r)
   341  	id := params["folderID"]
   342  
   343  	if len(id) == 0 {
   344  		writeMissingDataError(w, method, "folderID")
   345  		return
   346  	}
   347  
   348  	label, err := p.GetLabel(id)
   349  
   350  	if err != nil {
   351  		writeBadRequestError(w, method, "No such folder")
   352  		return
   353  	}
   354  
   355  	if label.UserID != p.Context.UserID {
   356  		writeForbiddenError(w)
   357  		return
   358  	}
   359  
   360  	defer utility.Close(r.Body)
   361  	body, err := ioutil.ReadAll(r.Body)
   362  
   363  	if err != nil {
   364  		writePayloadError(w, method, err)
   365  		return
   366  	}
   367  
   368  	var model = models.FolderRolesModel{}
   369  	err = json.Unmarshal(body, &model)
   370  
   371  	tx, err := request.Db.Beginx()
   372  
   373  	if err != nil {
   374  		writeTransactionError(w, method, err)
   375  		return
   376  	}
   377  
   378  	p.Context.Transaction = tx
   379  
   380  	// We compare new permisions to what we had before.
   381  	// Why? So we can send out folder invitation emails.
   382  	previousRoles, err := p.GetLabelRoles(id)
   383  
   384  	if err != nil {
   385  		writeGeneralSQLError(w, method, err)
   386  		return
   387  	}
   388  
   389  	// Store all previous roles as map for easy querying
   390  	previousRoleUsers := make(map[string]bool)
   391  
   392  	for _, v := range previousRoles {
   393  		previousRoleUsers[v.UserID] = true
   394  	}
   395  
   396  	// Who is sharing this folder?
   397  	inviter, err := p.GetUser(p.Context.UserID)
   398  
   399  	if err != nil {
   400  		log.IfErr(tx.Rollback())
   401  		writeGeneralSQLError(w, method, err)
   402  		return
   403  	}
   404  
   405  	// Nuke all previous permissions for this folder
   406  	_, err = p.DeleteLabelRoles(id)
   407  
   408  	if err != nil {
   409  		log.IfErr(tx.Rollback())
   410  		writeGeneralSQLError(w, method, err)
   411  		return
   412  	}
   413  
   414  	me := false
   415  	hasEveryoneRole := false
   416  	roleCount := 0
   417  
   418  	url := p.Context.GetAppURL(fmt.Sprintf("s/%s/%s", label.RefID, utility.MakeSlug(label.Name)))
   419  
   420  	for _, role := range model.Roles {
   421  		role.OrgID = p.Context.OrgID
   422  		role.LabelID = id
   423  
   424  		// Ensure the folder owner always has access!
   425  		if role.UserID == p.Context.UserID {
   426  			me = true
   427  			role.CanView = true
   428  			role.CanEdit = true
   429  		}
   430  
   431  		if len(role.UserID) == 0 && (role.CanView || role.CanEdit) {
   432  			hasEveryoneRole = true
   433  		}
   434  
   435  		// Only persist if there is a role!
   436  		if role.CanView || role.CanEdit {
   437  			roleID := util.UniqueID()
   438  			role.RefID = roleID
   439  			err = p.AddLabelRole(role)
   440  			roleCount++
   441  			log.IfErr(err)
   442  
   443  			// We send out folder invitation emails to those users
   444  			// that have *just* been given permissions.
   445  			if _, isExisting := previousRoleUsers[role.UserID]; !isExisting {
   446  
   447  				// we skip 'everyone' (user id != empty string)
   448  				if len(role.UserID) > 0 {
   449  					var existingUser entity.User
   450  					existingUser, err = p.GetUser(role.UserID)
   451  
   452  					if err == nil {
   453  						go mail.ShareFolderExistingUser(existingUser.Email, inviter.Fullname(), url, label.Name, model.Message)
   454  						log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, label.Name, existingUser.Email))
   455  					} else {
   456  						writeServerError(w, method, err)
   457  					}
   458  				}
   459  			}
   460  		}
   461  	}
   462  
   463  	// Do we need to ensure permissions for folder owner when shared?
   464  	if !me {
   465  		role := entity.LabelRole{}
   466  		role.LabelID = id
   467  		role.OrgID = p.Context.OrgID
   468  		role.UserID = p.Context.UserID
   469  		role.CanEdit = true
   470  		role.CanView = true
   471  		roleID := util.UniqueID()
   472  		role.RefID = roleID
   473  		err = p.AddLabelRole(role)
   474  		log.IfErr(err)
   475  	}
   476  
   477  	// Mark up folder type as either public, private or restricted access.
   478  	if hasEveryoneRole {
   479  		label.Type = entity.FolderTypePublic
   480  	} else {
   481  		if roleCount > 1 {
   482  			label.Type = entity.FolderTypeRestricted
   483  		} else {
   484  			label.Type = entity.FolderTypePrivate
   485  		}
   486  	}
   487  
   488  	log.Error("p.UpdateLabel()", p.UpdateLabel(label))
   489  
   490  	log.Error("tx.Commit()", tx.Commit())
   491  
   492  	writeSuccessEmptyJSON(w)
   493  }
   494  
   495  // GetFolderPermissions returns user permissions for the requested folder.
   496  func GetFolderPermissions(w http.ResponseWriter, r *http.Request) {
   497  	method := "GetFolderPermissions"
   498  	p := request.GetPersister(r)
   499  
   500  	params := mux.Vars(r)
   501  	folderID := params["folderID"]
   502  
   503  	if len(folderID) == 0 {
   504  		writeMissingDataError(w, method, "folderID")
   505  		return
   506  	}
   507  
   508  	roles, err := p.GetLabelRoles(folderID)
   509  
   510  	if err != nil && err != sql.ErrNoRows {
   511  		writeGeneralSQLError(w, method, err)
   512  		return
   513  	}
   514  
   515  	if len(roles) == 0 {
   516  		roles = []entity.LabelRole{}
   517  	}
   518  
   519  	json, err := json.Marshal(roles)
   520  
   521  	if err != nil {
   522  		writeJSONMarshalError(w, method, "folder-permissions", err)
   523  		return
   524  	}
   525  
   526  	writeSuccessBytes(w, json)
   527  }
   528  
   529  // AcceptSharedFolder records the fact that a user has completed folder onboard process.
   530  func AcceptSharedFolder(w http.ResponseWriter, r *http.Request) {
   531  	method := "AcceptSharedFolder"
   532  	p := request.GetPersister(r)
   533  
   534  	params := mux.Vars(r)
   535  	folderID := params["folderID"]
   536  
   537  	if len(folderID) == 0 {
   538  		writeMissingDataError(w, method, "folderID")
   539  		return
   540  	}
   541  
   542  	org, err := p.GetOrganizationByDomain(p.Context.Subdomain)
   543  
   544  	if err != nil {
   545  		writeGeneralSQLError(w, method, err)
   546  		return
   547  	}
   548  
   549  	p.Context.OrgID = org.RefID
   550  
   551  	defer utility.Close(r.Body)
   552  	body, err := ioutil.ReadAll(r.Body)
   553  
   554  	if err != nil {
   555  		writePayloadError(w, method, err)
   556  		return
   557  	}
   558  
   559  	var model = models.AcceptSharedFolderModel{}
   560  	err = json.Unmarshal(body, &model)
   561  
   562  	if err != nil {
   563  		writePayloadError(w, method, err)
   564  		return
   565  	}
   566  
   567  	if len(model.Serial) == 0 || len(model.Firstname) == 0 || len(model.Lastname) == 0 || len(model.Password) == 0 {
   568  		writeJSONMarshalError(w, method, "missing field data", err)
   569  		return
   570  	}
   571  
   572  	if err != nil {
   573  		writeGeneralSQLError(w, method, err)
   574  		return
   575  	}
   576  
   577  	user, err := p.GetUserBySerial(model.Serial)
   578  
   579  	// User has already on-boarded.
   580  	if err != nil && err == sql.ErrNoRows {
   581  		writeDuplicateError(w, method, "user")
   582  		return
   583  	}
   584  
   585  	if err != nil {
   586  		writeGeneralSQLError(w, method, err)
   587  		return
   588  	}
   589  
   590  	user.Firstname = model.Firstname
   591  	user.Lastname = model.Lastname
   592  	user.Initials = utility.MakeInitials(user.Firstname, user.Lastname)
   593  
   594  	tx, err := request.Db.Beginx()
   595  
   596  	if err != nil {
   597  		writeTransactionError(w, method, err)
   598  		return
   599  	}
   600  
   601  	p.Context.Transaction = tx
   602  
   603  	err = p.UpdateUser(user)
   604  
   605  	if err != nil {
   606  		log.IfErr(tx.Rollback())
   607  		writeGeneralSQLError(w, method, err)
   608  		return
   609  	}
   610  
   611  	salt := util.GenerateSalt()
   612  
   613  	log.IfErr(p.UpdateUserPassword(user.RefID, salt, util.GeneratePassword(model.Password, salt)))
   614  
   615  	if err != nil {
   616  		log.IfErr(tx.Rollback())
   617  		writeGeneralSQLError(w, method, err)
   618  		return
   619  	}
   620  
   621  	log.IfErr(tx.Commit())
   622  
   623  	data, err := json.Marshal(user)
   624  
   625  	if err != nil {
   626  		writeJSONMarshalError(w, method, "user", err)
   627  		return
   628  	}
   629  
   630  	writeSuccessBytes(w, data)
   631  }
   632  
   633  // InviteToFolder sends users folder invitation emails.
   634  func InviteToFolder(w http.ResponseWriter, r *http.Request) {
   635  	method := "InviteToFolder"
   636  	p := request.GetPersister(r)
   637  
   638  	params := mux.Vars(r)
   639  	id := params["folderID"]
   640  
   641  	if len(id) == 0 {
   642  		writeMissingDataError(w, method, "folderID")
   643  		return
   644  	}
   645  
   646  	label, err := p.GetLabel(id)
   647  
   648  	if err != nil {
   649  		writeBadRequestError(w, method, "folder not found")
   650  		return
   651  	}
   652  
   653  	if label.UserID != p.Context.UserID {
   654  		writeForbiddenError(w)
   655  		return
   656  	}
   657  
   658  	defer utility.Close(r.Body)
   659  	body, err := ioutil.ReadAll(r.Body)
   660  
   661  	if err != nil {
   662  		writePayloadError(w, method, err)
   663  		return
   664  	}
   665  
   666  	var model = models.FolderInvitationModel{}
   667  	err = json.Unmarshal(body, &model)
   668  
   669  	tx, err := request.Db.Beginx()
   670  
   671  	if err != nil {
   672  		writeTransactionError(w, method, err)
   673  		return
   674  	}
   675  
   676  	p.Context.Transaction = tx
   677  
   678  	inviter, err := p.GetUser(p.Context.UserID)
   679  
   680  	if err != nil {
   681  		writeGeneralSQLError(w, method, err)
   682  		return
   683  	}
   684  
   685  	for _, email := range model.Recipients {
   686  		var user entity.User
   687  		user, err = p.GetUserByEmail(email)
   688  
   689  		if err != nil && err != sql.ErrNoRows {
   690  			log.IfErr(tx.Rollback())
   691  			writeGeneralSQLError(w, method, err)
   692  			return
   693  		}
   694  
   695  		if len(user.RefID) > 0 {
   696  
   697  			// Ensure they have access to this organization
   698  			accounts, err2 := p.GetUserAccounts(user.RefID)
   699  
   700  			if err2 != nil {
   701  				log.IfErr(tx.Rollback())
   702  				writeGeneralSQLError(w, method, err2)
   703  				return
   704  			}
   705  
   706  			// we create if they c
   707  			hasAccess := false
   708  			for _, a := range accounts {
   709  				if a.OrgID == p.Context.OrgID {
   710  					hasAccess = true
   711  				}
   712  			}
   713  
   714  			if !hasAccess {
   715  				var a entity.Account
   716  				a.UserID = user.RefID
   717  				a.OrgID = p.Context.OrgID
   718  				a.Admin = false
   719  				a.Editor = false
   720  				accountID := util.UniqueID()
   721  				a.RefID = accountID
   722  
   723  				err = p.AddAccount(a)
   724  
   725  				if err != nil {
   726  					log.IfErr(tx.Rollback())
   727  					writeGeneralSQLError(w, method, err)
   728  					return
   729  				}
   730  			}
   731  
   732  			// Ensure they have folder roles
   733  			_, err = p.DeleteUserFolderRoles(label.RefID, user.RefID)
   734  			log.IfErr(err)
   735  
   736  			role := entity.LabelRole{}
   737  			role.LabelID = label.RefID
   738  			role.OrgID = p.Context.OrgID
   739  			role.UserID = user.RefID
   740  			role.CanEdit = false
   741  			role.CanView = true
   742  			roleID := util.UniqueID()
   743  			role.RefID = roleID
   744  
   745  			err = p.AddLabelRole(role)
   746  
   747  			if err != nil {
   748  				log.IfErr(tx.Rollback())
   749  				writeGeneralSQLError(w, method, err)
   750  				return
   751  			}
   752  
   753  			url := p.Context.GetAppURL(fmt.Sprintf("s/%s/%s", label.RefID, utility.MakeSlug(label.Name)))
   754  			go mail.ShareFolderExistingUser(email, inviter.Fullname(), url, label.Name, model.Message)
   755  			log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, label.Name, email))
   756  		} else {
   757  			// On-board new user
   758  			if strings.Contains(email, "@") {
   759  				url := p.Context.GetAppURL(fmt.Sprintf("auth/share/%s/%s", label.RefID, utility.MakeSlug(label.Name)))
   760  				err = inviteNewUserToSharedFolder(p, email, inviter, url, label, model.Message)
   761  
   762  				if err != nil {
   763  					log.IfErr(tx.Rollback())
   764  					writeServerError(w, method, err)
   765  					return
   766  				}
   767  
   768  				log.Info(fmt.Sprintf("%s is sharing space %s with new user %s", inviter.Email, label.Name, email))
   769  			}
   770  		}
   771  	}
   772  
   773  	// We ensure that the folder is marked as restricted as a minimum!
   774  	if len(model.Recipients) > 0 && label.Type == entity.FolderTypePrivate {
   775  		label.Type = entity.FolderTypeRestricted
   776  		err = p.UpdateLabel(label)
   777  
   778  		if err != nil {
   779  			log.IfErr(tx.Rollback())
   780  			writeServerError(w, method, err)
   781  			return
   782  		}
   783  	}
   784  
   785  	log.IfErr(tx.Commit())
   786  
   787  	_, err = w.Write([]byte("{}"))
   788  	log.IfErr(err)
   789  }
   790  
   791  // Invite new user to a folder that someone has shared with them.
   792  // We create the user account with default values and then take them
   793  // through a welcome process designed to capture profile data.
   794  // We add them to the organization and grant them view-only folder access.
   795  func inviteNewUserToSharedFolder(p request.Persister, email string, invitedBy entity.User,
   796  	baseURL string, label entity.Label, invitationMessage string) (err error) {
   797  
   798  	var user = entity.User{}
   799  	user.Email = email
   800  	user.Firstname = email
   801  	user.Lastname = ""
   802  	user.Salt = util.GenerateSalt()
   803  	requestedPassword := util.GenerateRandomPassword()
   804  	user.Password = util.GeneratePassword(requestedPassword, user.Salt)
   805  	userID := util.UniqueID()
   806  	user.RefID = userID
   807  
   808  	err = p.AddUser(user)
   809  
   810  	if err != nil {
   811  		return
   812  	}
   813  
   814  	// Let's give this user access to the organization
   815  	var a entity.Account
   816  	a.UserID = userID
   817  	a.OrgID = p.Context.OrgID
   818  	a.Admin = false
   819  	a.Editor = false
   820  	accountID := util.UniqueID()
   821  	a.RefID = accountID
   822  
   823  	err = p.AddAccount(a)
   824  
   825  	if err != nil {
   826  		return
   827  	}
   828  
   829  	role := entity.LabelRole{}
   830  	role.LabelID = label.RefID
   831  	role.OrgID = p.Context.OrgID
   832  	role.UserID = userID
   833  	role.CanEdit = false
   834  	role.CanView = true
   835  	roleID := util.UniqueID()
   836  	role.RefID = roleID
   837  
   838  	err = p.AddLabelRole(role)
   839  
   840  	if err != nil {
   841  		return
   842  	}
   843  
   844  	url := fmt.Sprintf("%s/%s", baseURL, user.Salt)
   845  	go mail.ShareFolderNewUser(user.Email, invitedBy.Fullname(), url, label.Name, invitationMessage)
   846  
   847  	return
   848  }