//ChangePwd is used to change a user's password func ChangePwd(w http.ResponseWriter, r *http.Request) { //gather inputs userId := r.FormValue("userId") userIdInt, _ := strconv.ParseInt(userId, 10, 64) password1 := r.FormValue("pass1") password2 := r.FormValue("pass2") //make sure passwords match if doStringsMatch(password1, password2) == false { output.Error(ErrPasswordsDoNotMatch, "The passwords you provided to not match.", w, r) return } //make sure password is long enough if len(password1) < minPwdLength { output.Error(ErrPasswordTooShort, "The password you provided is too short. It must be at least "+strconv.FormatInt(minPwdLength, 10)+" characters.", w, r) return } //hash the password hashedPwd := pwds.Create(password1) //get user data c := appengine.NewContext(r) userData, err := Find(c, userIdInt) if err != nil { output.Error(err, "Error while retreiving user data to update user's password.", w, r) return } //set new password userData.Password = hashedPwd //clear memcache for this userID & username err = memcacheutils.Delete(c, userId) err1 := memcacheutils.Delete(c, userData.Username) if err != nil { output.Error(err, "Error clearing cache for user id.", w, r) return } else if err1 != nil { output.Error(err1, "Error clearing cache for username.", w, r) return } //generate full datastore key for user fullKey := getUserKeyFromId(c, userIdInt) //save user _, err = saveUser(c, fullKey, userData) if err != nil { output.Error(err, "Error saving user to database after password change.", w, r) return } //done output.Success("userChangePassword", nil, w) return }
//UpdatePermissions is used to save changes to a user's permissions (access rights) //super-admin "administrator" account cannot be edited...this user always has full permissions //you can not edit your own permissions so you don't lock yourself out of the app func UpdatePermissions(w http.ResponseWriter, r *http.Request) { //gather form values userId := r.FormValue("userId") userIdInt, _ := strconv.ParseInt(userId, 10, 64) addCards, _ := strconv.ParseBool(r.FormValue("addCards")) removeCards, _ := strconv.ParseBool(r.FormValue("removeCards")) chargeCards, _ := strconv.ParseBool(r.FormValue("chargeCards")) viewReports, _ := strconv.ParseBool(r.FormValue("reports")) isAdmin, _ := strconv.ParseBool(r.FormValue("admin")) isActive, _ := strconv.ParseBool(r.FormValue("active")) //check if the logged in user is an admin //user updating another user's permission must be an admin //failsafe/second check since non-admins would not see the settings panel anyway session := sessionutils.Get(r) if session.IsNew { output.Error(ErrSessionMismatch, "An error occured. Please log out and log back in.", w, r) return } //get user data to update c := appengine.NewContext(r) userData, err := Find(c, userIdInt) if err != nil { output.Error(err, "We could not retrieve this user's information. This user could not be updates.", w, r) return } //check if the logged in user is trying to update their own permissions //you cannot edit your own permissions no matter what if session.Values["username"].(string) == userData.Username { output.Error(ErrCannotUpdateSelf, "You cannot edit your own permissions. Please contact another administrator.", w, r) return } //check if user is editing the super admin user if userData.Username == adminUsername { output.Error(ErrCannotUpdateSuperAdmin, "You cannot update the 'administrator' user. The account is locked.", w, r) return } //update the user userData.AddCards = addCards userData.RemoveCards = removeCards userData.ChargeCards = chargeCards userData.ViewReports = viewReports userData.Administrator = isAdmin userData.Active = isActive //clear memcache err = memcacheutils.Delete(c, userId) err1 := memcacheutils.Delete(c, userData.Username) if err != nil { output.Error(err, "Error clearing cache for user id.", w, r) return } else if err1 != nil { output.Error(err1, "Error clearing cache for username.", w, r) return } //generate complete key for user completeKey := getUserKeyFromId(c, userIdInt) //resave user //saves to datastore and memcache //save user _, err = saveUser(c, completeKey, userData) if err != nil { output.Error(err, "Error saving user to database after updating permission.", w, r) return } //done output.Success("userUpdatePermissins", nil, w) return }
//Add saves a new user to the app func Add(w http.ResponseWriter, r *http.Request) { //get form values username := r.FormValue("username") password1 := r.FormValue("password1") password2 := r.FormValue("password2") addCards, _ := strconv.ParseBool(r.FormValue("addCards")) removeCards, _ := strconv.ParseBool(r.FormValue("removeCards")) chargeCards, _ := strconv.ParseBool(r.FormValue("chargeCards")) viewReports, _ := strconv.ParseBool(r.FormValue("reports")) isAdmin, _ := strconv.ParseBool(r.FormValue("admin")) isActive, _ := strconv.ParseBool(r.FormValue("active")) //check if this user already exists c := appengine.NewContext(r) _, _, err := exists(c, username) if err == nil { //user already exists //notify client output.Error(ErrUserAlreadyExists, "This username already exists. Please choose a different username.", w, r) return } //make sure passwords match if doStringsMatch(password1, password2) == false { output.Error(ErrPasswordsDoNotMatch, "The passwords you provided to not match.", w, r) return } //make sure password is long enough if len(password1) < minPwdLength { output.Error(ErrPasswordTooShort, "The password you provided is too short. It must be at least "+strconv.FormatInt(minPwdLength, 10)+" characters.", w, r) return } //hash the password hashedPwd := pwds.Create(password1) //create the user u := User{ Username: username, Password: hashedPwd, AddCards: addCards, RemoveCards: removeCards, ChargeCards: chargeCards, ViewReports: viewReports, Administrator: isAdmin, Active: isActive, Created: timestamps.ISO8601(), } //save to datastore incompleteKey := createNewUserKey(c) _, err = saveUser(c, incompleteKey, u) if err != nil { fmt.Fprint(w, err) return } //clear list of users saved in memcache since a new user was added memcacheutils.Delete(c, listOfUsersKey) //respond to client with success message output.Success("addNewUser", nil, w) return }
//Add adds a new card the the app engine datastore //this is done by validating the provided inputs, sending the card token to stripe, and saving the data to the datastore //the card token was generaged client side by the stipe-js // this is done so the card number and security code is never sent to the server // the server has no way of "touching" the card number for security //when the card token is sent to stripe, stripe generates a customer token which we store and use to process payments func Add(w http.ResponseWriter, r *http.Request) { //get form values customerId := r.FormValue("customerId") //a unique key, not the datastore id or stripe customer id customerName := r.FormValue("customerName") //user provided, could be company name/client name/may be same as cardholder cardholder := r.FormValue("cardholder") //name on card as it appears cardToken := r.FormValue("cardToken") //from stripejs cardExp := r.FormValue("cardExp") //from stripejs, not from html input cardLast4 := r.FormValue("cardLast4") //from stripejs, not from html input //make sure all form values were given if len(customerName) == 0 { output.Error(ErrMissingCustomerName, "You did not provide the customer's name.", w, r) return } if len(cardholder) == 0 { output.Error(ErrMissingCustomerName, "You did not provide the cardholer's name.", w, r) return } if len(cardToken) == 0 { output.Error(ErrMissingCardToken, "A serious error occured; the card token is missing. Please refresh the page and try again.", w, r) return } if len(cardExp) == 0 { output.Error(ErrMissingExpiration, "The card's expiration date is missing from Stripe. Please refresh the page and try again.", w, r) return } if len(cardLast4) == 0 { output.Error(ErrMissingLast4, "The card's last four digits are missing from Stripe. Please refresh the page and try again.", w, r) return } //init context c := appengine.NewContext(r) //if customerId was given, make sure it is unique //this id should be unique in the user's company's crm //the customerId is used to autofill the charge card panel when performing the api-like semi-automated charges if len(customerId) != 0 { _, err := FindByCustId(c, customerId) if err == nil { //customer already exists output.Error(ErrCustIdAlreadyExists, "This customer ID is already in use. Please double check your records or remove the customer with this customer ID first.", w, r) return } else if err != ErrCustomerNotFound { output.Error(err, "An error occured while verifying this customer ID does not already exist. Please try again or leave the customer ID blank.", w, r) return } } //init stripe sc := createAppengineStripeClient(c) //create the customer on stripe //assigns the card via the cardToken to this customer //this card is used when making charges to this customer custParams := &stripe.CustomerParams{Desc: customerName} custParams.SetSource(cardToken) cust, err := sc.Customers.New(custParams) if err != nil { stripeErr := err.(*stripe.Error) stripeErrMsg := stripeErr.Msg output.Error(ErrStripe, stripeErrMsg, w, r) return } //get username of logged in user //used for tracking who added a card, just for diagnostics session := sessionutils.Get(r) username := session.Values["username"].(string) //save customer & card data to datastore newCustKey := createNewCustomerKey(c) newCustomer := CustomerDatastore{ CustomerId: customerId, CustomerName: customerName, Cardholder: cardholder, CardExpiration: cardExp, CardLast4: cardLast4, StripeCustomerToken: cust.ID, DatetimeCreated: timestamps.ISO8601(), AddedByUser: username, } _, err = save(c, newCustKey, newCustomer) if err != nil { output.Error(err, "There was an error while saving this customer. Please try again.", w, r) return } //customer saved //return to client output.Success("createCustomer", nil, w) //resave list of cards in memcache //since a card was added, memcache is stale //clients will retreive new list when refreshing page/app memcacheutils.Delete(c, listOfCardsKey) return }