Initial commit
This commit is contained in:
0
.gitignore
vendored
Normal file
0
.gitignore
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
12
.idea/dataSources.xml
generated
Normal file
12
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="database.db" uuid="0e462ae0-ce8a-4670-ab47-9f0bf5101c63">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/database.db</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/discord.xml
generated
Normal file
7
.idea/discord.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/shap-planner-backend.iml" filepath="$PROJECT_DIR$/.idea/shap-planner-backend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/shap-planner-backend.iml
generated
Normal file
9
.idea/shap-planner-backend.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
7
.idea/sqldialects.xml
generated
Normal file
7
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/storage/storage.go" dialect="GenericSQL" />
|
||||
<file url="PROJECT" dialect="SQLite" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
0
database.db
Normal file
0
database.db
Normal file
9
go.mod
Normal file
9
go.mod
Normal file
@@ -0,0 +1,9 @@
|
||||
module shap-planner-backend
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/mattn/go-sqlite3 v1.14.34
|
||||
golang.org/x/crypto v0.48.0
|
||||
)
|
||||
6
go.sum
Normal file
6
go.sum
Normal file
@@ -0,0 +1,6 @@
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
|
||||
github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
50
handlers/account.go
Normal file
50
handlers/account.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"shap-planner-backend/models"
|
||||
"shap-planner-backend/storage"
|
||||
"shap-planner-backend/utils"
|
||||
)
|
||||
|
||||
func Register(w http.ResponseWriter, r *http.Request) {
|
||||
var user models.User
|
||||
_ = json.NewDecoder(r.Body).Decode(&user)
|
||||
hashed, _ := utils.HashPassword(user.Password)
|
||||
user.Password = hashed
|
||||
user.ID = utils.GenerateUUID()
|
||||
|
||||
err := storage.AddUser(user)
|
||||
if err != nil {
|
||||
http.Error(w, "User exists", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
func Login(w http.ResponseWriter, r *http.Request) {
|
||||
var creds struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
_ = json.NewDecoder(r.Body).Decode(&creds)
|
||||
|
||||
user, err := storage.GetUserByUsername(creds.Username)
|
||||
if err != nil {
|
||||
http.Error(w, "User not found", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.CheckPasswordHash(creds.Password, user.Password) {
|
||||
http.Error(w, "Wrong password", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: JWT oder Session-Token erzeugen
|
||||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
21
main.go
Normal file
21
main.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package shap_planner_backend
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"shap-planner-backend/handlers"
|
||||
"shap-planner-backend/storage"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := storage.InitDB("database.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
http.HandleFunc("/register", handlers.Register)
|
||||
http.HandleFunc("/login", handlers.Login)
|
||||
|
||||
log.Println("Server läuft auf :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
16
models/models.go
Normal file
16
models/models.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package models
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type Expense struct {
|
||||
ID string `json:"id"`
|
||||
Amount int `json:"amt"`
|
||||
Description string `json:"desc"`
|
||||
|
||||
Payer User `json:"payer"`
|
||||
Debtors []User `json:"debtors"`
|
||||
}
|
||||
55
storage/storage.go
Normal file
55
storage/storage.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "database/sql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"shap-planner-backend/models"
|
||||
_ "shap-planner-backend/models"
|
||||
)
|
||||
|
||||
var DB *sql.DB
|
||||
|
||||
func InitDB(filepath string) error {
|
||||
var err error
|
||||
DB, err = sql.Open("sqlite3", filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Create Users-Table
|
||||
_, err = DB.Exec(`CREATE TABLE IF NOT EXISTS users(
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT UNIQUE,
|
||||
password TEXT
|
||||
);`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Create Expenses-Table
|
||||
_, err = DB.Exec(`CREATE TABLE IF NOT EXISTS expenses(
|
||||
id TEXT PRIMARY KEY
|
||||
|
||||
)`)
|
||||
return err
|
||||
}
|
||||
|
||||
func AddUser(user models.User) error {
|
||||
_, err := DB.Exec("INSERT INTO users(id, username, password) VALUES (?, ?, ?)", user.ID, user.Username, user.Password)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetUserByUsername(username string) (models.User, error) {
|
||||
row := DB.QueryRow("SELECT * FROM users WHERE username = ?", username)
|
||||
var user models.User
|
||||
err := row.Scan(&user.ID, &user.Username, &user.Password)
|
||||
return user, err
|
||||
}
|
||||
|
||||
func GetUserById(id string) (models.User, error) {
|
||||
row := DB.QueryRow("SELECT * FROM users WHERE id = ?", id)
|
||||
var user models.User
|
||||
err := row.Scan(&user.ID, &user.Username, &user.Password)
|
||||
return user, err
|
||||
}
|
||||
20
utils/util.go
Normal file
20
utils/util.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func HashPassword(password string) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func CheckPasswordHash(password, hash string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func GenerateUUID() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
Reference in New Issue
Block a user