2024-12-06 10:38:37 +01:00
package cmd
import (
2024-12-10 11:36:25 +01:00
"crypto/sha256"
2024-12-06 13:55:01 +01:00
"database/sql"
2024-12-10 11:36:25 +01:00
"encoding/hex"
2024-12-06 10:38:37 +01:00
"fmt"
2024-12-06 13:55:01 +01:00
"log"
2024-12-06 10:38:37 +01:00
"net/http"
2024-12-12 11:25:22 +01:00
"strconv"
2024-12-06 10:38:37 +01:00
"github.com/gin-gonic/gin"
2024-12-06 13:55:01 +01:00
_ "github.com/lib/pq"
2024-12-06 10:38:37 +01:00
"github.com/spf13/viper"
)
var (
ListenPort = "8080"
2024-12-06 13:55:01 +01:00
2024-12-09 10:42:31 +01:00
db * sql . DB
2024-12-06 13:55:01 +01:00
DB_Host string
DB_Port string
DB_User string
DB_Pass string
DB_Name string
2024-12-06 10:38:37 +01:00
)
2024-12-06 13:55:01 +01:00
func server ( ) {
log . SetPrefix ( "[DRAHOOT] " )
setPort ( )
if err := getDBInfo ( ) ; err != nil {
2024-12-09 10:42:31 +01:00
log . Fatalf ( "INVALID DB INFO: %v\nPlease refer to the example configuration file in the repo at https://git.bulgariu.xyz/raul/drahoot/src/branch/main/sample-config (default config path = ~/.config/drahoot/drahoot.toml)" , err )
}
if err := openDB ( ) ; err != nil {
2024-12-11 18:10:25 +01:00
log . Fatalf ( "Error happened trying to connect to database: %v" , err )
2024-12-06 13:55:01 +01:00
}
gin . SetMode ( gin . ReleaseMode )
2024-12-06 10:38:37 +01:00
r := gin . Default ( )
2024-12-12 12:34:54 +01:00
r . GET ( "/api/ping" , ping )
2024-12-12 11:29:46 +01:00
//r.GET("/", helloWorld)
2024-12-09 10:42:31 +01:00
// TODO: Have fun creating new endpoints
2024-12-10 11:36:25 +01:00
r . GET ( "/api/user" , getUsers )
2024-12-09 17:21:03 +01:00
r . GET ( "/api/user/:userid" , getUser )
2024-12-10 11:36:25 +01:00
r . POST ( "/api/user" , createUser )
2024-12-11 18:10:25 +01:00
r . DELETE ( "/api/user/:userid" , deleteUser )
2024-12-12 12:34:54 +01:00
r . PUT ( "/api/user/:userid" , modifyUser )
2024-12-06 10:38:37 +01:00
r . Run ( ":" + ListenPort )
}
2024-12-12 12:34:54 +01:00
func modifyUser ( c * gin . Context ) {
id := c . Param ( "userid" )
dynStmt := ` UPDATE usuarios SET email=$1,nombre=$2,apellido1=$3,apellido2=$4,password=$5 WHERE id_usuario = $6 `
2024-12-10 11:36:25 +01:00
2024-12-12 12:34:54 +01:00
_ , err := strconv . Atoi ( id )
if err != nil {
e := fmt . Sprintf ( "Invalid identifier" )
c . IndentedJSON ( http . StatusNotFound , setResponse ( e , false ) )
return
}
user := user { }
if err := c . BindJSON ( & user ) ; err != nil {
e := fmt . Sprintf ( "Something went wrong updating the user: %v" , err )
log . Println ( e )
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
return
}
_ , err = db . Exec ( dynStmt , user . Email , user . Name , user . Surname1 , user . Surname2 , hashPW ( user . Password ) , id )
if err != nil {
e := fmt . Sprintf ( "Something went wrong trying to modify the user: %v" , err )
log . Println ( e , user . Email , user . Name , user . Surname1 , user . Surname2 , hashPW ( user . Password ) , id )
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
return
}
c . IndentedJSON ( http . StatusOK , setResponse ( user , true ) )
2024-12-10 11:36:25 +01:00
}
2024-12-11 18:10:25 +01:00
func deleteUser ( c * gin . Context ) {
id := c . Param ( "userid" )
dynStmt := ` DELETE FROM usuarios WHERE id_usuario = $1 `
2024-12-12 11:25:22 +01:00
_ , err := strconv . Atoi ( id )
if err != nil {
e := fmt . Sprintf ( "Invalid identifier" )
c . IndentedJSON ( http . StatusNotFound , setResponse ( e , false ) )
return
}
_ , err = db . Exec ( dynStmt , id )
2024-12-11 18:10:25 +01:00
if err != nil {
e := fmt . Sprintf ( "Something went wrong trying to delete the user: %v" , err )
log . Println ( e )
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
return
}
e := fmt . Sprintf ( "User successfully deleted" )
c . IndentedJSON ( http . StatusOK , setResponse ( e , true ) )
}
2024-12-10 11:36:25 +01:00
func createUser ( c * gin . Context ) {
newuser := user { }
if err := c . BindJSON ( & newuser ) ; err != nil {
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "Something went wrong creating the user: %v" , err )
log . Println ( e )
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
2024-12-10 11:36:25 +01:00
return
}
2024-12-12 12:34:54 +01:00
2024-12-10 11:36:25 +01:00
var dynStmt string
2024-12-10 13:52:59 +01:00
if newuser . AccountType != "estudiante" && newuser . AccountType != "profesor" {
if newuser . AccountType == "admin" {
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "Nice try (https://xkcd.com/327/)" )
c . IndentedJSON ( http . StatusTeapot , setResponse ( e , false ) )
2024-12-10 13:52:59 +01:00
return
}
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "Invalid account type\n" )
c . IndentedJSON ( http . StatusNotFound , setResponse ( e , false ) )
2024-12-10 13:52:59 +01:00
return
2024-12-10 11:36:25 +01:00
}
2024-12-10 13:52:59 +01:00
dynStmt = ` INSERT INTO usuarios(nombre, apellido1, apellido2, email, password, rol) values($1, $2, $3, $4, $5, $6) `
2024-12-12 12:34:54 +01:00
_ , err := db . Exec ( dynStmt , newuser . Name , newuser . Surname1 , newuser . Surname2 , newuser . Email , hashPW ( newuser . Password ) , newuser . AccountType )
2024-12-10 11:36:25 +01:00
if err != nil {
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "Something went wrong trying to create the user: %v" , err )
log . Println ( e )
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
2024-12-10 11:36:25 +01:00
return
}
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "User %v has been created!" , newuser . Name )
c . IndentedJSON ( http . StatusOK , setResponse ( e , true ) )
2024-12-10 11:36:25 +01:00
}
2024-12-11 12:36:02 +01:00
func setResponse ( content any , success bool ) response {
msg := response { Contents : content , Success : success }
return msg
}
2024-12-09 17:21:03 +01:00
func getUser ( c * gin . Context ) {
id := c . Param ( "userid" )
2024-12-12 11:25:22 +01:00
_ , err := strconv . Atoi ( id )
if err != nil {
e := fmt . Sprintf ( "Invalid identifier" )
c . IndentedJSON ( http . StatusNotFound , setResponse ( e , false ) )
return
}
2024-12-09 17:21:03 +01:00
user := user { }
2024-12-11 12:36:02 +01:00
dynStmt := ` SELECT id_usuario,nombre,apellido1,apellido2,email,rol FROM usuarios WHERE id_usuario = $1 `
2024-12-12 11:25:22 +01:00
err = db . QueryRow ( dynStmt , id ) . Scan ( & user . Id , & user . Name , & user . Surname1 , & user . Surname2 , & user . Email , & user . AccountType )
2024-12-09 17:21:03 +01:00
if err != nil {
2024-12-09 17:58:26 +01:00
if err == sql . ErrNoRows {
2024-12-11 12:36:02 +01:00
c . IndentedJSON ( http . StatusNotFound , setResponse ( "User not found" , false ) )
2024-12-09 17:58:26 +01:00
return
}
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "SOMETHING BAD HAPPENED QUERYING THE DATABASE: %v" , err )
log . Println ( e )
2024-12-11 12:36:02 +01:00
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
2024-12-09 17:21:03 +01:00
return
}
2024-12-11 12:36:02 +01:00
c . IndentedJSON ( http . StatusOK , setResponse ( user , true ) )
2024-12-09 17:21:03 +01:00
}
2024-12-09 10:42:31 +01:00
func getUsers ( c * gin . Context ) {
users := [ ] user { }
2024-12-11 12:36:02 +01:00
rows , err := db . Query ( "SELECT id_usuario,nombre,apellido1,apellido2,email,rol FROM usuarios" )
2024-12-06 13:55:01 +01:00
if err != nil {
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "SOMETHING BAD HAPPENED QUERYING THE DATABASE: %v" , err )
log . Println ( e )
2024-12-11 12:36:02 +01:00
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
2024-12-06 13:55:01 +01:00
return
}
2024-12-09 10:42:31 +01:00
defer rows . Close ( )
for rows . Next ( ) {
user := user { }
2024-12-11 12:36:02 +01:00
err = rows . Scan ( & user . Id , & user . Name , & user . Surname1 , & user . Surname2 , & user . Email , & user . AccountType )
2024-12-09 10:42:31 +01:00
if err != nil {
2024-12-11 18:10:25 +01:00
e := fmt . Sprintf ( "SOMETHING BAD HAPPENED SCANNING THE ROWS: %v" , err )
log . Println ( e )
2024-12-11 12:36:02 +01:00
c . IndentedJSON ( http . StatusInternalServerError , setResponse ( e , false ) )
2024-12-09 10:42:31 +01:00
return
}
users = append ( users , user )
2024-12-06 13:55:01 +01:00
}
2024-12-11 12:36:02 +01:00
c . IndentedJSON ( http . StatusOK , setResponse ( users , true ) )
2024-12-06 13:55:01 +01:00
}
2024-12-12 11:29:46 +01:00
func ping ( c * gin . Context ) {
c . IndentedJSON ( http . StatusOK , setResponse ( "Pong!" , true ) )
2024-12-06 10:38:37 +01:00
}
2024-12-12 12:34:54 +01:00
func hashPW ( plain string ) string {
hashedPW := sha256 . New ( )
hashedPW . Write ( [ ] byte ( plain ) )
sha256hash := hex . EncodeToString ( hashedPW . Sum ( nil ) )
return sha256hash
}
func getDBInfo ( ) error {
dbhost := viper . GetString ( "Server.DB_Host" )
if dbhost == "" {
e := fmt . Errorf ( "No database IP address present in config file!\n" )
return e
} else {
DB_Host = dbhost
}
dbport := viper . GetString ( "Server.DB_Port" )
if dbport == "" {
e := fmt . Errorf ( "No database port present in config file!\n" )
return e
} else {
DB_Port = dbport
}
dbuser := viper . GetString ( "Server.DB_User" )
if dbuser == "" {
e := fmt . Errorf ( "No database username present in config file!\n" )
return e
} else {
DB_User = dbuser
}
dbpass := viper . GetString ( "Server.DB_Pass" )
if dbpass == "" {
e := fmt . Errorf ( "No database password present in config file!\n" )
return e
} else {
DB_Pass = dbpass
}
dbname := viper . GetString ( "Server.DB_Name" )
if dbname == "" {
e := fmt . Errorf ( "No database name present in config file!\n" )
return e
} else {
DB_Name = dbname
}
return nil
}
func openDB ( ) error {
psqlconn := fmt . Sprintf ( "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable" , DB_Host , DB_Port , DB_User , DB_Pass , DB_Name )
dba , err := sql . Open ( "postgres" , psqlconn )
if err != nil {
return err
}
db = dba
return nil
}
func setPort ( ) {
p := viper . GetString ( "Server.Port" )
if p != "" {
ListenPort = p
}
}