github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/api/endpoint/user_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 "net/url" 21 "strings" 22 23 "github.com/documize/community/documize/api/entity" 24 "github.com/documize/community/documize/api/mail" 25 "github.com/documize/community/documize/api/request" 26 "github.com/documize/community/documize/api/util" 27 "github.com/documize/community/wordsmith/api" 28 "github.com/documize/community/wordsmith/log" 29 "github.com/documize/community/wordsmith/utility" 30 31 "github.com/gorilla/mux" 32 ) 33 34 // AddUser is the endpoint that enables an administrator to add a new user for their orgaisation. 35 func AddUser(w http.ResponseWriter, r *http.Request) { 36 method := "AddUser" 37 p := request.GetPersister(r) 38 39 if !p.Context.Administrator { 40 writeForbiddenError(w) 41 return 42 } 43 44 defer utility.Close(r.Body) 45 body, err := ioutil.ReadAll(r.Body) 46 47 if err != nil { 48 writePayloadError(w, method, err) 49 return 50 } 51 52 userModel := entity.User{} 53 err = json.Unmarshal(body, &userModel) 54 55 if err != nil { 56 writeJSONMarshalError(w, method, "user", err) 57 return 58 } 59 60 // data validation 61 userModel.Email = strings.ToLower(strings.TrimSpace(userModel.Email)) 62 userModel.Firstname = strings.TrimSpace(userModel.Firstname) 63 userModel.Lastname = strings.TrimSpace(userModel.Lastname) 64 userModel.Password = strings.TrimSpace(userModel.Password) 65 66 if len(userModel.Email) == 0 { 67 writeBadRequestError(w, method, "Missing email") 68 return 69 } 70 71 if len(userModel.Firstname) == 0 { 72 writeBadRequestError(w, method, "Missing firstname") 73 return 74 } 75 76 if len(userModel.Lastname) == 0 { 77 writeBadRequestError(w, method, "Missing lastname") 78 return 79 } 80 81 userModel.Initials = utility.MakeInitials(userModel.Firstname, userModel.Lastname) 82 83 // generate secrets 84 requestedPassword := util.GenerateRandomPassword() 85 userModel.Salt = util.GenerateSalt() 86 userModel.Password = util.GeneratePassword(requestedPassword, userModel.Salt) 87 88 // only create account if not dupe 89 addUser := true 90 addAccount := true 91 var userID string 92 93 userDupe, err := p.GetUserByEmail(userModel.Email) 94 95 if err != nil && err != sql.ErrNoRows { 96 writeGeneralSQLError(w, method, err) 97 return 98 } 99 100 if userModel.Email == userDupe.Email { 101 addUser = false 102 userID = userDupe.RefID 103 104 log.Info("Dupe user found, will not add") 105 } 106 107 tx, err := request.Db.Beginx() 108 109 if err != nil { 110 writeTransactionError(w, method, err) 111 return 112 } 113 114 p.Context.Transaction = tx 115 116 if addUser { 117 userID = util.UniqueID() 118 userModel.RefID = userID 119 err = p.AddUser(userModel) 120 121 if err != nil { 122 log.IfErr(tx.Rollback()) 123 writeGeneralSQLError(w, method, err) 124 return 125 } 126 127 log.Info("Adding user") 128 } else { 129 attachUserAccounts(p, p.Context.OrgID, &userDupe) 130 131 for _, a := range userDupe.Accounts { 132 if a.OrgID == p.Context.OrgID { 133 addAccount = false 134 log.Info("Dupe account found, will not add") 135 break 136 } 137 } 138 } 139 140 // set up user account for the org 141 if addAccount { 142 var a entity.Account 143 a.UserID = userID 144 a.OrgID = p.Context.OrgID 145 a.Editor = true 146 a.Admin = false 147 accountID := util.UniqueID() 148 a.RefID = accountID 149 150 err = p.AddAccount(a) 151 152 if err != nil { 153 log.IfErr(tx.Rollback()) 154 writeGeneralSQLError(w, method, err) 155 return 156 } 157 } 158 159 log.IfErr(tx.Commit()) 160 161 // If we did not add user or give them access (account) then we error back 162 if !addUser && !addAccount { 163 writeDuplicateError(w, method, "user") 164 return 165 } 166 167 // Invite new user 168 inviter, err := p.GetUser(p.Context.UserID) 169 log.IfErr(err) 170 171 // Prepare invitation email (that contains SSO link) 172 if addUser && addAccount { 173 size := len(requestedPassword) 174 auth := fmt.Sprintf("%s:%s:%s", p.Context.AppURL, userModel.Email, requestedPassword[:size]) 175 encrypted := utility.EncodeBase64([]byte(auth)) 176 177 url := fmt.Sprintf("%s/%s", getAppURL(p.Context, "auth/sso"), url.QueryEscape(string(encrypted))) 178 go mail.InviteNewUser(userModel.Email, inviter.Fullname(), url, userModel.Email, requestedPassword) 179 180 log.Info(fmt.Sprintf("%s invited by %s on %s", userModel.Email, inviter.Email, p.Context.AppURL)) 181 182 } else { 183 go mail.InviteExistingUser(userModel.Email, inviter.Fullname(), getAppURL(p.Context, "")) 184 185 log.Info(fmt.Sprintf("%s is giving access to an existing user %s", inviter.Email, userModel.Email)) 186 } 187 188 // Send back new user record 189 userModel, err = getSecuredUser(p, p.Context.OrgID, userID) 190 191 json, err := json.Marshal(userModel) 192 193 if err != nil { 194 writeJSONMarshalError(w, method, "user", err) 195 return 196 } 197 198 writeSuccessBytes(w, json) 199 } 200 201 // GetOrganizationUsers is the endpoint that allows administrators to view the users in their organisation. 202 func GetOrganizationUsers(w http.ResponseWriter, r *http.Request) { 203 method := "GetUsersForOrganization" 204 p := request.GetPersister(r) 205 206 if !p.Context.Editor && !p.Context.Administrator { 207 writeForbiddenError(w) 208 return 209 } 210 211 users, err := p.GetUsersForOrganization() 212 213 if err != nil && err != sql.ErrNoRows { 214 writeServerError(w, method, err) 215 return 216 } 217 218 for i := range users { 219 attachUserAccounts(p, p.Context.OrgID, &users[i]) 220 } 221 222 json, err := json.Marshal(users) 223 224 if err != nil { 225 writeJSONMarshalError(w, method, "user", err) 226 return 227 } 228 229 writeSuccessBytes(w, json) 230 } 231 232 // GetFolderUsers returns every user within a given space 233 func GetFolderUsers(w http.ResponseWriter, r *http.Request) { 234 method := "GetUsersForSpace" 235 p := request.GetPersister(r) 236 var users []entity.User 237 var err error 238 239 params := mux.Vars(r) 240 folderID := params["folderID"] 241 242 if len(folderID) == 0 { 243 writeBadRequestError(w, method, "missing folderID") 244 return 245 } 246 247 // check to see folder type as it determines user selection criteria 248 folder, err := p.GetLabel(folderID) 249 250 if err != nil && err != sql.ErrNoRows { 251 log.Error(fmt.Sprintf("%s: cannot fetch space %s", method, folderID), err) 252 writeUsers(w, nil) 253 return 254 } 255 256 switch folder.Type { 257 case entity.FolderTypePublic: 258 // return all users for team 259 users, err = p.GetUsersForOrganization() 260 break 261 case entity.FolderTypePrivate: 262 // just me 263 var user entity.User 264 user, err = p.GetUser(p.Context.UserID) 265 users = append(users, user) 266 break 267 case entity.FolderTypeRestricted: 268 users, err = p.GetFolderUsers(folderID) 269 break 270 } 271 272 if err != nil && err != sql.ErrNoRows { 273 log.Error(fmt.Sprintf("%s: cannot fetch users for space %s", method, folderID), err) 274 writeUsers(w, nil) 275 return 276 } 277 278 writeUsers(w, users) 279 } 280 281 // GetUser returns user specified by Id 282 func GetUser(w http.ResponseWriter, r *http.Request) { 283 method := "GetUser" 284 p := request.GetPersister(r) 285 286 params := mux.Vars(r) 287 userID := params["userID"] 288 289 if len(userID) == 0 { 290 writeMissingDataError(w, method, "userId") 291 return 292 } 293 294 if userID != p.Context.UserID { 295 writeBadRequestError(w, method, "User Id mismatch") 296 return 297 } 298 299 user, err := getSecuredUser(p, p.Context.OrgID, userID) 300 301 if err == sql.ErrNoRows { 302 writeNotFoundError(w, method, userID) 303 return 304 } 305 306 if err != nil { 307 writeServerError(w, method, err) 308 return 309 } 310 311 json, err := json.Marshal(user) 312 313 if err != nil { 314 writeJSONMarshalError(w, method, "user", err) 315 return 316 } 317 318 writeSuccessBytes(w, json) 319 } 320 321 // DeleteUser is the endpoint to delete a user specified by userID, the caller must be an Administrator. 322 func DeleteUser(w http.ResponseWriter, r *http.Request) { 323 method := "DeleteUser" 324 p := request.GetPersister(r) 325 326 if !p.Context.Administrator { 327 writeForbiddenError(w) 328 return 329 } 330 331 params := mux.Vars(r) 332 userID := params["userID"] 333 334 if len(userID) == 0 { 335 writeMissingDataError(w, method, "userID") 336 return 337 } 338 339 if userID == p.Context.UserID { 340 writeBadRequestError(w, method, "cannot delete self") 341 return 342 } 343 344 tx, err := request.Db.Beginx() 345 346 if err != nil { 347 writeTransactionError(w, method, err) 348 return 349 } 350 351 p.Context.Transaction = tx 352 353 err = p.DeactiveUser(userID) 354 355 if err != nil { 356 log.IfErr(tx.Rollback()) 357 writeGeneralSQLError(w, method, err) 358 return 359 } 360 361 err = p.ChangeLabelOwner(userID, p.Context.UserID) 362 log.IfErr(err) 363 364 log.IfErr(tx.Commit()) 365 366 writeSuccessString(w, "{}") 367 } 368 369 // UpdateUser is the endpoint to update user information for the given userID. 370 // Note that unless they have admin privildges, a user can only update their own information. 371 // Also, only admins can update user roles in organisations. 372 func UpdateUser(w http.ResponseWriter, r *http.Request) { 373 method := "UpdateUser" 374 p := request.GetPersister(r) 375 376 params := mux.Vars(r) 377 userID := params["userID"] 378 379 if len(userID) == 0 { 380 writeBadRequestError(w, method, "user id must be numeric") 381 return 382 } 383 384 defer utility.Close(r.Body) 385 body, err := ioutil.ReadAll(r.Body) 386 387 if err != nil { 388 writePayloadError(w, method, err) 389 return 390 } 391 392 user := entity.User{} 393 err = json.Unmarshal(body, &user) 394 395 if err != nil { 396 writeJSONMarshalError(w, method, "user", err) 397 return 398 } 399 400 // can only update your own account unless you are an admin 401 if p.Context.UserID != userID && !p.Context.Administrator { 402 writeForbiddenError(w) 403 return 404 } 405 406 // can only update your own account unless you are an admin 407 if len(user.Email) == 0 { 408 writeBadRequestError(w, method, "missing email") 409 return 410 } 411 412 tx, err := request.Db.Beginx() 413 414 if err != nil { 415 writeTransactionError(w, method, err) 416 return 417 } 418 419 p.Context.Transaction = tx 420 421 user.RefID = userID 422 user.Initials = utility.MakeInitials(user.Firstname, user.Lastname) 423 424 err = p.UpdateUser(user) 425 426 if err != nil { 427 log.IfErr(tx.Rollback()) 428 writeGeneralSQLError(w, method, err) 429 return 430 } 431 432 // Now we update user roles for this organization. 433 // That means we have to first find their account record 434 // for this organization. 435 account, err := p.GetUserAccount(userID) 436 437 if err != nil { 438 log.IfErr(tx.Rollback()) 439 writeGeneralSQLError(w, method, err) 440 return 441 } 442 443 account.Editor = user.Editor 444 account.Admin = user.Admin 445 446 err = p.UpdateAccount(account) 447 if err != nil { 448 log.IfErr(tx.Rollback()) 449 writeGeneralSQLError(w, method, err) 450 return 451 } 452 453 log.IfErr(tx.Commit()) 454 455 json, err := json.Marshal(user) 456 457 if err != nil { 458 writeJSONMarshalError(w, method, "user", err) 459 return 460 } 461 462 writeSuccessBytes(w, json) 463 } 464 465 // ChangeUserPassword accepts password change from within the app. 466 func ChangeUserPassword(w http.ResponseWriter, r *http.Request) { 467 method := "ChangeUserPassword" 468 p := request.GetPersister(r) 469 470 params := mux.Vars(r) 471 userID := params["userID"] 472 473 if len(userID) == 0 { 474 writeMissingDataError(w, method, "user id") 475 return 476 } 477 478 defer utility.Close(r.Body) 479 body, err := ioutil.ReadAll(r.Body) 480 481 if err != nil { 482 writePayloadError(w, method, err) 483 return 484 } 485 486 newPassword := string(body) 487 488 // can only update your own account unless you are an admin 489 if userID != p.Context.UserID && !p.Context.Administrator { 490 writeForbiddenError(w) 491 return 492 } 493 494 tx, err := request.Db.Beginx() 495 496 if err != nil { 497 writeTransactionError(w, method, err) 498 return 499 } 500 501 p.Context.Transaction = tx 502 503 user, err := p.GetUser(userID) 504 505 if err != nil { 506 writeGeneralSQLError(w, method, err) 507 return 508 } 509 510 user.Salt = util.GenerateSalt() 511 512 err = p.UpdateUserPassword(userID, user.Salt, util.GeneratePassword(newPassword, user.Salt)) 513 514 if err != nil { 515 writeGeneralSQLError(w, method, err) 516 return 517 } 518 519 log.IfErr(tx.Commit()) 520 521 writeSuccessEmptyJSON(w) 522 } 523 524 // GetUserFolderPermissions returns folder permission for authenticated user. 525 func GetUserFolderPermissions(w http.ResponseWriter, r *http.Request) { 526 method := "ChangeUserPassword" 527 p := request.GetPersister(r) 528 529 params := mux.Vars(r) 530 userID := params["userID"] 531 532 if userID != p.Context.UserID { 533 writeUnauthorizedError(w) 534 return 535 } 536 537 roles, err := p.GetUserLabelRoles() 538 539 if err == sql.ErrNoRows { 540 err = nil 541 roles = []entity.LabelRole{} 542 } 543 544 if err != nil { 545 writeServerError(w, method, err) 546 return 547 } 548 549 json, err := json.Marshal(roles) 550 551 if err != nil { 552 writeJSONMarshalError(w, method, "roles", err) 553 return 554 } 555 556 writeSuccessBytes(w, json) 557 } 558 559 // ForgotUserPassword initiates the change password procedure. 560 // Generates a reset token and sends email to the user. 561 // User has to click link in email and then provide a new password. 562 func ForgotUserPassword(w http.ResponseWriter, r *http.Request) { 563 method := "ForgotUserPassword" 564 p := request.GetPersister(r) 565 566 defer utility.Close(r.Body) 567 body, err := ioutil.ReadAll(r.Body) 568 569 if err != nil { 570 writeBadRequestError(w, method, "cannot ready payload") 571 return 572 } 573 574 user := new(entity.User) 575 err = json.Unmarshal(body, &user) 576 577 if err != nil { 578 writePayloadError(w, method, err) 579 return 580 } 581 582 tx, err := request.Db.Beginx() 583 584 if err != nil { 585 writeTransactionError(w, method, err) 586 return 587 } 588 589 p.Context.Transaction = tx 590 591 token := util.GenerateSalt() 592 593 err = p.ForgotUserPassword(user.Email, token) 594 595 if err != nil && err != sql.ErrNoRows { 596 log.IfErr(tx.Rollback()) 597 writeGeneralSQLError(w, method, err) 598 return 599 } 600 601 if err == sql.ErrNoRows { 602 writeServerError(w, method, fmt.Errorf("User %s not found for password reset process", user.Email)) 603 return 604 } 605 606 log.IfErr(tx.Commit()) 607 608 appURL := getAppURL(p.Context, fmt.Sprintf("auth/reset/%s", token)) 609 610 fmt.Println(appURL) 611 612 go mail.PasswordReset(user.Email, appURL) 613 614 writeSuccessEmptyJSON(w) 615 } 616 617 // ResetUserPassword stores the newly chosen password for the user. 618 func ResetUserPassword(w http.ResponseWriter, r *http.Request) { 619 api.SetJSONResponse(w) 620 p := request.GetPersister(r) 621 622 params := mux.Vars(r) 623 token := params["token"] 624 625 if len(token) == 0 { 626 log.ErrorString("ResetUserPassword - missing password reset token") 627 api.WriteErrorBadRequest(w, "missing password reset token") 628 return 629 } 630 631 defer utility.Close(r.Body) 632 body, err := ioutil.ReadAll(r.Body) 633 634 if err != nil { 635 api.WriteErrorBadRequest(w, "Bad payload") 636 log.Error("ResetUserPassword - failed to read body", err) 637 return 638 } 639 640 newPassword := string(body) 641 642 tx, err := request.Db.Beginx() 643 644 if err != nil { 645 api.WriteError(w, err) 646 log.Error("ResetUserPassword - failed to get DB transaction", err) 647 return 648 } 649 650 p.Context.Transaction = tx 651 652 user, err := p.GetUserByToken(token) 653 654 if err != nil { 655 api.WriteError(w, err) 656 log.Error("ResetUserPassword - unable to retrieve user", err) 657 return 658 } 659 660 user.Salt = util.GenerateSalt() 661 662 err = p.UpdateUserPassword(user.RefID, user.Salt, util.GeneratePassword(newPassword, user.Salt)) 663 664 if err != nil { 665 log.IfErr(tx.Rollback()) 666 api.WriteError(w, err) 667 log.Error("ResetUserPassword - failed to change password", err) 668 return 669 } 670 671 log.IfErr(tx.Commit()) 672 673 _, err = w.Write([]byte("{}")) 674 log.IfErr(err) 675 } 676 677 // Get user object contain associated accounts but credentials are wiped. 678 func getSecuredUser(p request.Persister, orgID, user string) (u entity.User, err error) { 679 u, err = p.GetUser(user) 680 attachUserAccounts(p, orgID, &u) 681 return 682 } 683 684 func attachUserAccounts(p request.Persister, orgID string, user *entity.User) { 685 user.ProtectSecrets() 686 a, err := p.GetUserAccounts(user.RefID) 687 688 if err != nil { 689 log.Error("Unable to fetch user accounts", err) 690 return 691 } 692 693 user.Accounts = a 694 user.Editor = false 695 user.Admin = false 696 697 for _, account := range user.Accounts { 698 if account.OrgID == orgID { 699 user.Admin = account.Admin 700 user.Editor = account.Editor 701 break 702 } 703 } 704 } 705 706 func writeUsers(w http.ResponseWriter, u []entity.User) { 707 if u == nil { 708 u = []entity.User{} 709 } 710 711 j, err := json.Marshal(u) 712 713 if err != nil { 714 log.Error("unable to writeUsers", err) 715 writeServerError(w, "unabe to writeUsers", err) 716 return 717 } 718 719 writeSuccessBytes(w, j) 720 }