Enshi/enshi_back/utils/routesSetup.go
2024-09-29 19:38:22 +03:00

1109 lines
28 KiB
Go

package utils
import (
"context"
"fmt"
"math/rand"
"net/http"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func testRoute1(c *gin.Context) {
testInfo := map[string]interface{}{
"name": "Kyle",
"id": 1,
}
newToken, err := CreateToken(testInfo)
if err != nil {
c.IndentedJSON(401, gin.H{"error": err.Error()})
return
}
c.IndentedJSON(200, gin.H{"token": newToken})
}
func testRoute2(c *gin.Context) {
type content struct {
Email string
Name string
}
// Check correct type of receiving data
if c.ContentType() != "application/json" {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "content type should by 'application/json'"})
return
}
var body content
if err := c.BindJSON(&body); err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "invalid body of request" + err.Error()})
return
}
// Get data from token
temp, err := c.Get("claims")
if !err {
c.IndentedJSON(http.StatusBadRequest, gin.H{"Error": "your token does not contain information needed"})
return
}
c.IndentedJSON(http.StatusOK, gin.H{"1": temp, "2": body})
}
func getRecipeInformation(c *gin.Context) {
recipe_id, err := strconv.Atoi(strings.Trim(c.Param("recipe_id"), "/"))
if err != nil {
c.IndentedJSON(404, gin.H{"err": err.Error()})
return
}
returnData := map[string]interface{}{}
recipe, err := Dbx.Query(context.Background(), "select * from recipes where recipe_id = $1", recipe_id)
if err != nil {
c.IndentedJSON(500, gin.H{"err": err.Error()})
return
}
isMore := recipe.Next()
recipeFields := recipe.FieldDescriptions()
recipeValues, err := recipe.Values()
if err != nil {
c.IndentedJSON(500, gin.H{"err": err.Error()})
return
}
for i, recipeField := range recipeFields {
returnData[recipeField.Name] = recipeValues[i]
}
if isMore {
fmt.Println("there is more than one items with this id: ", recipe_id)
}
recipe.Close()
//
// Adding ingredients
//
ingredients, err := Dbx.Query(context.Background(),
"select a.ingredient_id, a.quantity, a.unit, b.name from recipe_ingredients a join "+
"ingredients b on a.recipe_id = $1 and "+
"a.ingredient_id = b.ingredient_id", recipe_id)
if err != nil {
c.IndentedJSON(500, gin.H{"err": err.Error()})
return
}
ingredientsSlice := []map[string]interface{}{}
for ingredients.Next() {
ingredientsFields := ingredients.FieldDescriptions()
ingredientsValues, err := ingredients.Values()
if err != nil {
c.IndentedJSON(500, gin.H{"err": err.Error()})
return
}
tempMap := map[string]interface{}{}
for i, ingredient := range ingredientsFields {
tempMap[ingredient.Name] = ingredientsValues[i]
}
ingredientsSlice = append(ingredientsSlice, tempMap)
}
returnData["proportions"] = ingredientsSlice
ingredients.Close()
//
// End of adding ingredients
//
//
// Start adding steps
//
stepSlice := []map[string]interface{}{}
steps, err := Dbx.Query(context.Background(), "select * from instructions where recipe_id = $1", recipe_id)
if err != nil {
c.IndentedJSON(500, gin.H{"err": err.Error()})
return
}
for steps.Next() {
tempStep := map[string]interface{}{}
stepFields := steps.FieldDescriptions()
stepValues, err := steps.Values()
if err != nil {
c.IndentedJSON(500, gin.H{"err": err.Error()})
return
}
for i, step := range stepFields {
tempStep[step.Name] = stepValues[i]
}
stepSlice = append(stepSlice, tempStep)
}
returnData["steps"] = stepSlice
steps.Close()
//
// End adding steps
//
c.IndentedJSON(200, returnData)
}
// Register new user in the system and return JWT-token if
// all went well
func registerUser(c *gin.Context) {
type content struct {
Password string
Name string
Username string
}
if c.ContentType() != "application/json" {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "content type should by 'application/json'"})
return
}
var body = content{}
if err := c.BindJSON(&body); err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
newUuid := uuid.New().ID()
hashedPassword, err := Argon2Hasher.HashGen([]byte(body.Password), []byte{})
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
rowsToClose, errr := Dbx.Query(context.Background(), "INSERT INTO users "+
"(user_id, username, user_name, user_password) "+
"VALUES($1, $2, $3, $4);", newUuid, body.Username, body.Name, hashedPassword.stringToStore)
if errr != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": errr.Error()})
return
}
rowsToClose.Close()
newToken, err := CreateToken(map[string]interface{}{"id": newUuid, "name": body.Name})
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Header("Authorization", newToken)
c.IndentedJSON(200, gin.H{"newToken": newToken})
}
// Returns all available diets and ids of them
func getAllDiets(c *gin.Context) {
diets, err := Dbx.Query(context.Background(), "select * from diets")
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
sliceOfDiets := []map[string]interface{}{}
for diets.Next() {
temp := map[string]interface{}{}
dietsRows := diets.FieldDescriptions()
dietsValues, err := diets.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
for i, value := range dietsRows {
temp[value.Name] = dietsValues[i]
}
sliceOfDiets = append(sliceOfDiets, temp)
}
c.IndentedJSON(http.StatusOK, sliceOfDiets)
}
// Returns slice of cuisines and they ids
func getAllCuisines(c *gin.Context) {
cuisines, err := Dbx.Query(context.Background(), "select * from cuisines")
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
cuisinesSlice := []map[string]interface{}{}
for cuisines.Next() {
cuisinesFields := cuisines.FieldDescriptions()
cuisinesValues, err := cuisines.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
temp := map[string]interface{}{}
for i, cuisine := range cuisinesFields {
temp[cuisine.Name] = cuisinesValues[i]
}
cuisinesSlice = append(cuisinesSlice, temp)
}
c.IndentedJSON(http.StatusOK, cuisinesSlice)
}
// Returns all ingredients with they ids
func getAllIngredients(c *gin.Context) {
cuisines, err := Dbx.Query(context.Background(), "select * from ingredients")
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
ingredientsSlice := []map[string]interface{}{}
for cuisines.Next() {
ingredientsFields := cuisines.FieldDescriptions()
ingredientsValues, err := cuisines.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
temp := map[string]interface{}{}
for i, cuisine := range ingredientsFields {
temp[cuisine.Name] = ingredientsValues[i]
}
ingredientsSlice = append(ingredientsSlice, temp)
}
c.IndentedJSON(http.StatusOK, ingredientsSlice)
}
func getRecipesByIngredient(c *gin.Context) {
ingredientId, err := strconv.Atoi(strings.Trim(c.Param("ingredientId"), "/"))
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipes, err := Dbx.Query(context.Background(),
"select a.recipe_id, a.name, a.description, a.servings, a.prep_time, a.cook_time, a.image_url, a.source_url, a.author from recipes a join (select * from ingredients "+
" b join recipe_ingredients c on b.ingredient_id = $1 where b.ingredient_id = c.ingredient_id) d "+
" on a.recipe_id = d.recipe_id",
ingredientId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipesSlice := []map[string]interface{}{}
for recipes.Next() {
temp := map[string]interface{}{}
recipeFields := recipes.FieldDescriptions()
recipeValues, err := recipes.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
for i, field := range recipeFields {
temp[field.Name] = recipeValues[i]
}
recipesSlice = append(recipesSlice, temp)
}
c.IndentedJSON(http.StatusOK, recipesSlice)
}
func getRecipesByCuisine(c *gin.Context) {
cuisineId, err := strconv.Atoi(strings.Trim(c.Param("cuisineId"), "/"))
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipes, err := Dbx.Query(context.Background(),
"select a.recipe_id, a.name, a.description, a.servings, a.prep_time, a.cook_time, a.image_url, a.source_url, a.author from recipes a join (select * from cuisines "+
" b join recipe_cuisines c on b.cuisine_id = $1 where b.cuisine_id = c.cuisine_id) d "+
" on a.recipe_id = d.recipe_id",
cuisineId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
cuisinesSlice := []map[string]interface{}{}
for recipes.Next() {
temp := map[string]interface{}{}
recipeFields := recipes.FieldDescriptions()
recipeValues, err := recipes.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
for i, field := range recipeFields {
temp[field.Name] = recipeValues[i]
}
cuisinesSlice = append(cuisinesSlice, temp)
}
c.IndentedJSON(http.StatusOK, cuisinesSlice)
}
func conditionalRollback(b *bool) {
if *b {
_, err := Dbx.Exec(context.Background(),
"ROLLBACK;")
if err != nil {
fmt.Println("Failed to rollback. Data in database could be invalid.")
return
}
fmt.Println(RedColor + strings.ToUpper("Some things went wrong. Rollback.") + ResetColor)
}
}
func addRecipe(c *gin.Context) {
type ingredient struct {
IngredientId uint32
Name string
Quantity float64
Unit string
}
type instruction struct {
InstructionId uint32
Step_number uint16
InstructionText string
InstructionTime string
}
type cuisine struct {
CuisineId uint32
Name string
}
type diet struct {
DietId uint32
Name string
}
type content struct {
// Recipe information we receive from client
Name string
Description string
Servings uint8
Prep_time uint16
Cook_time uint16
Image_url string
Source_url string
// Ingredient list
IngredientList []ingredient // Done
// Instruction list
InstructionList []instruction // Done
// Other information
Cuisines []cuisine // Client side
Diets []diet // Client side
}
usrID, idExists := c.Get("id")
if !idExists {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in token"})
return
}
// Id of user that created recipe
userId, err := strconv.Atoi(usrID.(string))
if err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in body of the request"})
return
}
var body content
err = c.BindJSON(&body)
if err != nil {
fmt.Println(err.Error())
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in body of the request " + err.Error()})
return
}
recipeUuid := uuid.New()
// New recipe uuid
var recipeUuidInt = recipeUuid.ID()
// Set author ID as user ID request came from
// Set new uuid for recipe
// Ingredient to be added to the db
newIngredients := []ingredient{}
needToRollback := false
_, err = Dbx.Exec(context.Background(),
"BEGIN;")
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": "failed to begin transaction"})
return
}
defer conditionalRollback(&needToRollback)
// Check if ingredient already in database
// if not we give it a uuid and add to slice to add it to db later
// Also we change name of ingredient to lower case
for i, ingredient := range body.IngredientList {
temp, err := Dbx.Query(context.Background(),
"select find_id_in_the_table_by_name_ingredient($1)",
strings.ToLower(ingredient.Name))
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
needToRollback = true
return
}
temp.Next()
if t, err := temp.Values(); err == nil && t[0].(int64) < 0 {
uid := uuid.New()
body.IngredientList[i].IngredientId = uid.ID()
body.IngredientList[i].Name = strings.ToLower(body.IngredientList[i].Name)
newIngredients = append(newIngredients, body.IngredientList[i])
} else if err == nil && t[0].(int64) > 0 {
ttemp := t[0].(int64)
body.IngredientList[i].IngredientId = uint32(ttemp)
body.IngredientList[i].Name = strings.ToLower(body.IngredientList[i].Name)
} else if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error in loop": err.Error()})
needToRollback = true
return
}
temp.Close()
}
// Give every instruction uuid
for i := range body.InstructionList {
body.InstructionList[i].InstructionId = uuid.New().ID()
}
// Adding new ingredients to db
for _, newIngredient := range newIngredients {
_, err := Dbx.Exec(context.Background(),
"INSERT INTO ingredients "+
`(ingredient_id, "name") `+
"VALUES($1, $2);",
newIngredient.IngredientId, newIngredient.Name)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
needToRollback = true
return
}
}
// Adding recipe with it information
_, err = Dbx.Exec(context.Background(),
"INSERT INTO recipes "+
`(recipe_id, "name", description, servings, prep_time, cook_time, image_url, source_url, author) `+
"VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9);",
recipeUuidInt, body.Name, body.Description, body.Servings, body.Prep_time, body.Cook_time, body.Image_url, body.Source_url, userId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error adding recipe": err.Error() + fmt.Sprint(userId)})
needToRollback = true
return
}
var counter = 0
// Adding recipe steps to db
for _, instruction := range body.InstructionList {
counter++
_, err := Dbx.Exec(context.Background(),
"INSERT INTO instructions "+
"(instruction_id, recipe_id, step_number, instruction_text, instruction_time) "+
"VALUES($1, $2, $3, $4, $5);",
instruction.InstructionId, recipeUuidInt, instruction.Step_number, instruction.InstructionText, instruction.InstructionTime)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error adding recipe step": err.Error() + fmt.Sprint(counter)})
needToRollback = true
return
}
}
// Link this recipe with stuff
// Link recipe with ingredients
for _, ingredient := range body.IngredientList {
_, err := Dbx.Exec(context.Background(),
"INSERT INTO recipe_ingredients "+
"(recipe_id, ingredient_id, quantity, unit) "+
"VALUES($1, $2, $3, $4);",
recipeUuidInt, ingredient.IngredientId, ingredient.Quantity, ingredient.Unit)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error() + fmt.Sprint(recipeUuidInt, ingredient.IngredientId)})
needToRollback = true
return
}
}
// Link with cuisines
for _, cuisine := range body.Cuisines {
_, err := Dbx.Exec(context.Background(),
"INSERT INTO recipe_cuisines "+
"(recipe_id, cuisine_id) "+
"VALUES($1, $2);",
recipeUuidInt, cuisine.CuisineId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
needToRollback = true
return
}
}
// Link with diets
for _, diet := range body.Diets {
_, err := Dbx.Exec(context.Background(),
"INSERT INTO recipe_diets "+
"(recipe_id, diet_id) "+
"VALUES($1, $2);",
recipeUuidInt, diet.DietId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
needToRollback = true
return
}
}
//
//Todo: Add transactions, so bad could not pass to db
_, err = Dbx.Exec(context.Background(),
"COMMIT;")
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": "Failed to COMMIT " + err.Error()})
needToRollback = true
return
}
c.IndentedJSON(http.StatusOK, gin.H{"message": "all good"})
}
func findRecipesByIngredients(c *gin.Context) {
type content struct {
Ingredients []string
}
if c.ContentType() != "application/json" {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "content_type is not 'application/json'"})
return
}
var body content
if err := c.BindJSON(&body); err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error 1": `Invalid body of the request`})
return
}
recipe_ids, err := Dbx.Query(context.Background(),
`select recipe_id from
recipe_ingredients ri
join ingredients i on i.ingredient_id = ri.ingredient_id
where i.name in ('`+strings.Join(body.Ingredients[:], "','")+`')
group by recipe_id
having count(distinct name) = `+strconv.Itoa(len(body.Ingredients)))
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error 2": err.Error()})
return
}
ids := []uint32{}
for recipe_ids.Next() {
values, err := recipe_ids.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error 3": err.Error()})
return
}
ids = append(ids, uint32(values[0].(int64)))
}
c.IndentedJSON(http.StatusOK, gin.H{"ids": ids})
}
func getRandomRecipes(c *gin.Context) {
recipes, err := Dbx.Query(context.Background(),
`select * from recipes`)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipeNumber := 15
recipesToReturn := make([]map[string]interface{}, recipeNumber)
recipeCounter := 0
r := rand.New(rand.NewSource(time.Now().Unix()))
for recipes.Next() {
b := r.Intn(10)
if b >= 9 {
temp := map[string]interface{}{}
fields := recipes.FieldDescriptions()
val, err := recipes.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
for i, field := range fields {
temp[field.Name] = val[i]
}
recipesToReturn[recipeCounter] = temp
recipeCounter++
if recipeCounter >= recipeNumber {
break
}
}
}
recipes.Close()
c.IndentedJSON(http.StatusOK, recipesToReturn)
}
func isAuth(c *gin.Context) {
_, err := ValidateToken(c.GetHeader("Authorization"))
if err != nil {
c.IndentedJSON(http.StatusUnauthorized, gin.H{"message": "invalid token"})
return
}
c.IndentedJSON(http.StatusOK, gin.H{"message": "valid token"})
}
func addFavoriteRecipe(c *gin.Context) {
usrID, exists := c.Get("id")
if !exists {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in token"})
return
}
recipeId, err := strconv.Atoi(strings.Trim(c.Param("recipeId"), "/"))
if err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing recipe id"})
return
}
_, err = Dbx.Exec(context.Background(), `INSERT INTO user_favorite_recipe
(user_id, recipe_id)
VALUES($1, $2);`, usrID, recipeId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error/inserting": err.Error()})
return
}
c.IndentedJSON(http.StatusOK, gin.H{"message": "all good"})
}
func removeFavoriteRecipe(c *gin.Context) {
usrID, exists := c.Get("id")
if !exists {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in token"})
return
}
recipeId, err := strconv.Atoi(strings.Trim(c.Param("recipeId"), "/"))
if err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing recipe id"})
return
}
_, err = Dbx.Exec(context.Background(), `DELETE from user_favorite_recipe where
user_id = $1 and recipe_id = $2`, usrID, recipeId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error/inserting": err.Error()})
return
}
c.IndentedJSON(http.StatusOK, gin.H{"message": "all good"})
}
func getAllFavoriteRecipes(c *gin.Context) {
usrID, exists := c.Get("id")
if !exists {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in token"})
return
}
recipeIdsRows, err := Dbx.Query(context.Background(), `select * from recipes r
join user_favorite_recipe ufr on r.recipe_id = ufr.recipe_id
where user_id = $1`, usrID)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error/selecting": err.Error()})
return
}
recipeIds := make([]any, 0)
for recipeIdsRows.Next() {
fieldNames := recipeIdsRows.FieldDescriptions()
temp, err := recipeIdsRows.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error/selecting": err.Error()})
return
}
tempMap := map[string]any{}
for i, fieldName := range fieldNames {
tempMap[fieldName.Name] = temp[i]
}
recipeIds = append(recipeIds, tempMap)
}
c.IndentedJSON(http.StatusOK, gin.H{"values": recipeIds})
}
func isFavorite(c *gin.Context) {
usrID, exists := c.Get("id")
if !exists {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "missing required data in token"})
return
}
recipeId, err := strconv.Atoi(strings.Trim(c.Param("recipeId"), "/"))
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
rows, err := Dbx.Query(context.Background(), `SELECT user_id, recipe_id
FROM user_favorite_recipe where user_id = $1 and recipe_id = $2`, usrID, recipeId)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error/selecting": err.Error()})
return
}
flag := false
for rows.Next() {
flag = true
}
c.IndentedJSON(http.StatusOK, flag)
}
func getRecipesByName(c *gin.Context) {
recipeName := strings.Trim(c.Param("recipeName"), "/")
rows, err := Dbx.Query(context.Background(), `SELECT *
FROM recipes where "name" LIKE $1;`, fmt.Sprint(`%`, recipeName, `%`))
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error in select (getRecipesByName)": err.Error()})
return
}
recipesToReturn := []map[string]any{}
for rows.Next() {
fields := rows.FieldDescriptions()
values, err := rows.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipeInfo := map[string]any{}
for i, field := range fields {
recipeInfo[field.Name] = values[i]
}
recipesToReturn = append(recipesToReturn, recipeInfo)
}
c.IndentedJSON(http.StatusOK, recipesToReturn)
}
func deleteRecipe(c *gin.Context) {
fmt.Println(c.Param("recipe_id"))
recipe_id, err := strconv.Atoi(strings.Trim(c.Param("recipe_id"), "/"))
if err != nil {
c.IndentedJSON(404, gin.H{"err": err.Error()})
return
}
userID, exists := c.Get("id")
if !exists {
c.IndentedJSON(404, gin.H{"err": "no valid token provided"})
return
}
var count int
Dbx.QueryRow(context.Background(), `select count(*) from recipes where author = $1 and recipe_id = $2`, userID, recipe_id).Scan(&count)
if count > 0 {
_, err := Dbx.Exec(context.Background(), `DELETE FROM recipes
WHERE recipe_id = $1`, recipe_id)
if err != nil {
c.IndentedJSON(404, gin.H{"err": err.Error()})
return
}
} else {
c.IndentedJSON(http.StatusUnauthorized, gin.H{"message": "Could not delete recipe. ID: " + strconv.Itoa(recipe_id)})
return
}
c.IndentedJSON(http.StatusOK, gin.H{"message": "Successfully deleted recipe. ID: " + strconv.Itoa(recipe_id)})
}
func getAllUserRecipes(c *gin.Context) {
userID, exists := c.Get("id")
if !exists {
c.IndentedJSON(404, gin.H{"err": "no valid token provided"})
return
}
rows, err := Dbx.Query(context.Background(), `select * from recipes where author = $1`, userID)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipesToReturn := []map[string]any{}
for rows.Next() {
fields := rows.FieldDescriptions()
values, err := rows.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
recipeInfo := map[string]any{}
for i, field := range fields {
recipeInfo[field.Name] = values[i]
}
recipesToReturn = append(recipesToReturn, recipeInfo)
}
c.IndentedJSON(http.StatusOK, recipesToReturn)
}
func SetupRotes(g *gin.Engine) error {
g.Use(CORSMiddleware())
freeGroup := g.Group("/")
// Free group routes
freeGroup.GET("recipe_info/:recipe_id", getRecipeInformation)
freeGroup.GET("get_all_diets", getAllDiets)
freeGroup.GET("get_all_cuisines", getAllCuisines)
freeGroup.GET("get_all_ingredients", getAllIngredients)
freeGroup.GET("get_recipes_by_ingredient/:ingredientId", getRecipesByIngredient)
freeGroup.GET("get_recipes_by_cuisine/:cuisineId", getRecipesByCuisine)
freeGroup.GET("get_recipes_by_name/:recipeName", getRecipesByName)
freeGroup.GET("getRandomRecipes", getRandomRecipes)
freeGroup.GET("isAuth", isAuth)
freeGroup.POST("register_user", registerUser)
freeGroup.POST("login", login)
freeGroup.POST("get_recipes_by_ingredients", findRecipesByIngredients)
authGroup := g.Group("/")
authGroup.Use(AuthMiddleware())
// Auth group routes
authGroup.GET("test1", testRoute1)
authGroup.GET("addToFavorite/:recipeId", addFavoriteRecipe)
authGroup.GET("removeFromFavorite/:recipeId", removeFavoriteRecipe)
authGroup.GET("getAllFavorite", getAllFavoriteRecipes)
authGroup.GET("isFavorite/:recipeId", isFavorite)
authGroup.GET("getAllUserRecipes", getAllUserRecipes)
authGroup.POST("test2", testRoute2)
authGroup.POST("add_recipe", addRecipe)
authGroup.DELETE("deleteRecipe/:recipe_id", deleteRecipe)
return nil
}
func login(c *gin.Context) {
type content struct {
Nickname string
Password string
}
var body content
err := c.BindJSON(&body)
if err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error 1st": err.Error()})
return
}
hash, err := Dbx.Query(context.Background(),
"select * from users where username = $1;",
body.Nickname)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error 2nd": err.Error()})
return
}
hash.Next()
values, err := hash.Values()
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
user_id := strconv.FormatInt(values[0].(int64), 10)
user_name := values[2].(string)
user_hash := values[3].(string)
hash.Close()
user_hash_, salt, err := DecodeArgon2String(user_hash)
if err != nil {
c.IndentedJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = Argon2Hasher.Compare(user_hash_, salt, []byte(body.Password))
if err != nil {
c.IndentedJSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
}
user_info := map[string]interface{}{
"id": user_id,
"name": user_name,
}
token, err := CreateToken(user_info)
if err != nil {
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Header("Authorization", token)
c.IndentedJSON(http.StatusOK, gin.H{"token": token})
}
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, authorization, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
c.Writer.Header().Set("Access-Control-Expose-Headers", "Access-Token, Uid, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
claims, err := ValidateToken(token)
if err != nil {
c.IndentedJSON(http.StatusUnauthorized, gin.H{"error auth": err.Error()})
c.Abort()
return
}
// Claims -> data stored in token
c.Set("id", claims["id"])
c.Set("claims", claims)
c.Next()
}
}