How to match all user_name with password in golang? - go

Using a struct, I'm saving the data in the JSON form to collection like so:
type SignUp struct {
Id int `json:"_id" bson:"_id"`
UserName string `json:"user_name" bson:"user_name"`
EmailId string `json:"email_id" bson:"email_id"`
Password string `json:"password" bson:"password"`
}
type SignUps []SignUp
And retrieved the data from the collection of mongodb using function
func Login(c *gin.Context) {
response := ResponseControllerList{}
conditions := bson.M{}
data, err := GetAllUser(conditions)
fmt.Println(data)
fmt.Println(err)
Matching(data)
return
}
func GetAllUser(blogQuery interface{}) (result SignUps, err error) {
mongoSession := config.ConnectDb()
sessionCopy := mongoSession.Copy()
defer sessionCopy.Close()
getCollection := mongoSession.DB("sign").C("signup")
err = getCollection.Find(blogQuery).Select(bson.M{}).All(&result)
if err != nil {
return result, err
}
return result, nil
}
But the data retrieved without its keys like shown below:-
[{1 puneet puneet#gmail.com puneet} {2 Rohit abc#gmail.com puneet}]
Issue is that I want to collect all the existing EmailId and Password
and match them with userid and password entered by the user in fucntion given bellow:-
func Matching(data Signups){
userid="abc#gmail.com"
password="puneet"
//match?
}
How can I match the userid and password with the EmailId and Password fields?

This is not answering your question directly, but is very important nonetheless. It seems that you are saving the passwords of your users in plain text in the database. This is very careless and you should add some encryption like bcrypt: https://godoc.org/golang.org/x/crypto/bcrypt
When you have added some encryption, your matching would be quite different than all given answers. This depends on the used encryption package. But please ignore the other answers. They might work, but only for plain text passwords.

You can give an if condition to check if the userid or email is empty or not on your Matching function like:
....
if data.userid != "" {
data.username = data.userid
}
data.password
....
You can create new struct for the query and use it to create your Matching function.

for _, signup := range data {
if userId == signup.Id && password == signup.Password {
println("Match!")
}
}

Related

how do i validate the body structure of rest api request in golang

I am trying to ensure the body of a post request for example contains exact structure of the body and if not ahould throw an error
for example i have the following function
func UpdatePassword(c *fiber.Ctx) error {
type UpdatePasswordData struct {
Password string `json:"password" form:"password"`
NewPassword string `json:"new_password" form:"new_password"`
NewPasswordConfirm string `json:"new_password_confirm" form:"new_password_confirm"`
}
data := UpdatePasswordData{}
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
if data.NewPassword != data.NewPasswordConfirm {
c.Status(400)
return c.JSON(fiber.Map{
"message": "passwords do not match",
})
}
email, _ := middlewares.GetUserEmail(c)
newPassword := models.HashPassword(data.NewPassword)
database.DB.Model(&user).Select("Password").Where("email = ?", email).Updates(map[string]interface{}{"Password": newPassword})
return c.JSON(user)
}
the POST request should be looking for body with this structure
{
"password": "oldpassword",
"new_password": "newpassword",
"new_password_confirm": "newpassword",
}
but currently this endpoint accepts body that does not have this exact structure. So how do i enforce the structure in the body of request, so that if structure does not match, i throw an error?
do not like gin, fiber has not builtin validate package
use go-playground/validator
go get github.com/go-playground/validator
example
type UpdatePasswordData struct {
Password string `json:"password" validate:"required,min=8,max=32"`
NewPassword string `json:"new_password" validate:"required,min=8,max=32"`
NewPasswordConfirm string `json:"new_password_confirm" validate:"eqfield=NewPassword"`
}
func UpdatePassword(c *fiber.Ctx) error {
var body UpdatePasswordData
if err := c.BodyParser(&body); err != nil {
return err
}
validate := validator.New()
if err := validate.Struct(body); err != nil {
return err
}
// do others
// get current user, check password == hash(body.password)
// save new passworld
}
or you can see fiber office docs https://docs.gofiber.io/guide/validation#validator-package
We can use struct tag
`validate:"required"`
to ensure that all the mandatory fields are there in the request payload.
Moreover we can validate the fields with the provided tags of the validator package and for additional validations we can implement custom validators and register them like this:
validate := validator.New()
validate.RegisterValidation("password-validator", PasswordValidator)

Partial updates of objects

I want to enable update functionality for my User object in my fiber/gorm backend. It works fine when I update all fields together using the Save function. However, when I do not have all fields present in the update request (for example only the Birthday field but not the Phone field) it overwrites the rest of the fields with their respective null values.
func UserUpdateByID(c *fiber.Ctx) error {
db := database.DBConn
// Parse the body to fit user entity
user := entities.User{}
if err := c.BodyParser(&user); err != nil {
return c.Status(500).SendString(err.Error())
}
// Update record
record := db.Save(&user)
if record.Error != nil {
return c.Status(500).SendString(record.Error.Error())
}
return c.JSON(record.Value)
When I change the line with record := db.Save(&user) to
mappedData, _ := StructToMap(user)
record := db.Model(&entities.User{}).Update(mappedData)
I receive the error that Update can not handle map of interfaces: sql: converting argument $10 type: unsupported type map[string]interface {}, a map
Update 1:
The mentioned StructToMap function looks like this:
func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
data, err := json.Marshal(obj)
if err != nil {
return
}
err = json.Unmarshal(data, &newMap) // Convert to a map
return
}
Update 2:
The User object looks like:
type User struct {
gorm.Model
Identity string
Birthday time.Time
Phone string
City string
...
ActivityData []Activity
}
Looking, on gorm doc(https://gorm.io/docs/update.html), you can do something like this :
Use the Updates instead of Update.
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
You can also use a db.Debug, to show the final query that gorm made, and see if matches with what are you expecting.

how to fetch name/key in from datastore

Couldn't find any existing Go specific answer so creating a new one.
Our datastore consist of following columns/attributes
Name/ID Email UserID UserName
Now, I want to retrieve these values into my Go struct. Here is what i have written
type UserDetails struct {
NameID string
Email string `datastore:"Email"`
UserID string `datastore:"UserID"`
UserName string `datastore:UserName`
}
Now, when i am fetching this entity (based on kind), I am manually setting the NameID i.e.,
func (c DataStoreClient) GetUserDetailsByOrg(ctx context.Context, orgName string) ([]*UserDetails, error) {
var userDetails []*UserDetails
q := datastore.NewQuery(userDetailsKind).
Namespace(orgName)
keys, err := c.client.GetAll(ctx, q, &userDetails)
for i, key := range keys {
userDetails[i].NameID = key.Name
}
return userDetails, err
}
Now, the question that i want to ask that is this the correct approach to retrieve Name/ID or can i retrieve it by specifying datastore:Name/ID in struct?
Implement the KeyLoader interface to set the field during entity load.
type UserDetails struct {
NameID string `datastore:"-"`
Email string `datastore:"Email"`
UserID string `datastore:"UserID"`
UserName string `datastore:UserName`
}
func (ud *UserDetails) LoadKey(k *datastore.Key) error {
ud.NameID = k.Name
return nil
}
func (ud *UserDetails) Load(ps []datastore.Property) error {
return datastore.LoadStruct(ud, ps)
}
func (ud *UserDetails) Save() ([]datastore.Property, error) {
return datastore.SaveStruct(ud)
}
Use it like this:
func (c DataStoreClient) GetUserDetailsByOrg(ctx context.Context, orgName string) ([]*UserDetails, error) {
var userDetails []*UserDetails
q := datastore.NewQuery(userDetailsKind).
Namespace(orgName)
_, err := c.client.GetAll(ctx, q, &userDetails)
return userDetails, err
}
The approach in the question works. The advantage of the KeyLoader implementation is that it saves a couple of lines of code wherever the application queries for or gets an entity.
Set the NameID datastore name to "-" so that the property loader and saver ignores the field.
Your approach is fine. However, because you have NameID without any tag, there will be a datastore entity property with that name set to nothing. It's an unnecessary property to store. So, you could make it "NameID string datastore:"-" so datastore ignores it. Alternatively, if you are not exporting this field outside the package or via JSON, you can use a lower case name like "nameID".
Another approach you have is to automatically get the entire key by having a "key" field. You can learn more about it in Key Field
https://godoc.org/cloud.google.com/go/datastore#hdr-Key_Field

Reuse or cast structs for validation, API results, and DB saves in Go

I'm trying to write an API that will do different things with the data depending on its purpose.
API results - The API should expose certain fields to the user
Validation - Validation should handle different schemas e.g. login form doesn't require Name, but register does
Database - The database should save everything, including password etc. - if I try using the same struct for the API and DB with json:"-" or un-exporting the field the database save also ignores the field
Some sample code is below with a couple of comments in capitals to show where I ideally need to type cast to change the data. As they are different structs, they cannot be type cast, so I get an error. How can I fix this?
Alternatively, what is a better way of doing different things with the data without having lots of similar structs?
// IDValidation for uuids
type IDValidation struct {
ID string `json:"id" validate:"required,uuid"`
}
// RegisterValidation for register form
type RegisterValidation struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
}
// UserModel to save in DB
type UserModel struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
Active bool `json:"active,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
jwt.StandardClaims
}
// UserAPI data to display to user
type UserAPI struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
Active bool `json:"active,omitempty"`
}
// register a user
func register(c echo.Context) error {
u := new(UserModel)
if err := c.Bind(u); err != nil {
return err
}
// NEED TO CAST TO RegisterValidation HERE?
if err := c.Validate(u); err != nil {
return err
}
token, err := u.Register()
if err != nil {
return err
}
return c.JSON(http.StatusOK, lib.JSON{"token": token})
}
// retrieve a user
func retrieve(c echo.Context) error {
u := IDValidation{
ID: c.Param("id"),
}
if err := c.Validate(u); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
// NEED TO CAST USER TO UserAPI?
user, err := userModel.GetByID(u.ID)
if err != nil {
return err
}
return c.JSON(200, lib.JSON{"message": "User found", "user": user})
}

How to decode query parameter in golang

i have parameter
id_user
phone_number
I want to decode to my struct
type User struct{
IDUser int `json:"id_user"`
PhoneNumber string `json:"phone_number"`
}
is it possible to decode into struct? I use gorilla schema. My Code:
func User(w http.ResponseWriter, r *http.Request){
var decoder = schema.NewDecoder()
var user User
if err := r.ParseForm(); err != nil {
fmt.Println(err)
}
err := decoder.Decode(&user, r.PostForm)
if err != nil {
fmt.Println(err)
}
respBody, err := json.Marshal(user)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(respBody)
}
i input id_user = 1 and phone_number = qwerty. But the result is id_user = 0 and phone_number = "".
If your mentioned two fields are query params you can directly read it like this way:
func User(w http.ResponseWriter, r *http.Request) {
idUser := r.URL.Query().Get("id_user")
phoneNumber := r.URL.Query().Get("phone_number")
var user User
id, err := strconv.Atoi(idUser)
if err != nil {
fmt.Println("error converting string to int")
return
}
user.IDUser = id
user.PhoneNumber = phoneNumber
respBody, _ := json.Marshal(user)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(respBody)
}
Otherwise you can directly pass the User struct in api payload and directly do the payLoad decoding like this
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
fmt.Println("error decoding api payload")
return
}
I think you should fix your tags from this:
type User struct{
IDUser int `json:id_user`
PhoneNumber string `json:phone_number`
}
to this:
type User struct{
IDUser int `json:"id_user"`
PhoneNumber string `json:"phone_number"`
}
So, you should use quotes in tag names.
If you want to decode them directly into a structure without getting the values of the fields one by one then you can use github.com/gorilla/schema. Refer to this question.
This answer may not be suitable for the question since the op was seeking help of using gorilla/schema package.
However, if someone were looking for a package to decode HTTP query params into a struct in Go, I will recommend an awesome package here:
ggicci/httpin
Disclaimer: I'm the creator and maintainer of this package.
httpin helps you easily decoding HTTP request data from
Query parameters, e.g. ?name=john&is_member=true
Headers, e.g. Authorization: xxx
Form data, e.g. username=john&password=******
JSON/XML Body, e.g. POST {"name":"john"}
Path variables, e.g. /users/{username}
File uploads
How to use?
type ListUsersInput struct {
Page int `in:"query=page"`
PerPage int `in:"query=per_page"`
IsMember bool `in:"query=is_member"`
}
func ListUsers(rw http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*ListUsersInput)
if input.IsMember {
// Do sth.
}
// Do sth.
}
httpin is:
well documented: at https://ggicci.github.io/httpin/
well tested: coverage over 98%
open integrated: with net/http, go-chi/chi, gorilla/mux, gin-gonic/gin, etc.
extensible (advanced feature): by adding your custom directives. Read httpin - custom directives for more details.
awesome mentioned: https://github.com/avelino/awesome-go#forms

Resources