created setup and backend structure

This commit is contained in:
z1glr
2025-01-07 00:51:03 +00:00
parent 063f22569d
commit 03b2b0e206
11 changed files with 306 additions and 1 deletions

View File

@@ -0,0 +1,22 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "Go",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "go version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

1
backend/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
config.yaml

72
backend/config.go Normal file
View File

@@ -0,0 +1,72 @@
package main
import (
"bytes"
"fmt"
"os"
"time"
"gopkg.in/yaml.v3"
)
var CONFIG_PATH = "config.yaml"
type ConfigYaml struct {
LogLevel string `yaml:"log_level"`
Database struct {
Host string `yaml:"host"`
User string `yaml:"user"`
Password string `yaml:"password"`
Database string `yaml:"database"`
} `yaml:"database"`
ClientSession struct {
JwtSignature string `yaml:"jwt_signature"`
Expire string `yaml:"expire"`
} `yaml:"client_session"`
}
type CacheConfig struct {
Expiration time.Duration
Purge time.Duration
}
var config ConfigYaml
func loadConfig() ConfigYaml {
config := ConfigYaml{}
yamlFile, err := os.ReadFile(CONFIG_PATH)
if err != nil {
panic(fmt.Sprintf("Error opening config-file: %v", err))
}
reader := bytes.NewReader(yamlFile)
dec := yaml.NewDecoder(reader)
dec.KnownFields(true)
err = dec.Decode(&config)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing config-file: %v", err)
os.Exit(1)
}
return config
}
func writeConfig() {
buf := bytes.Buffer{}
enc := yaml.NewEncoder(&buf)
enc.SetIndent(2)
// Can set default indent here on the encoder
if err := enc.Encode(&config); err != nil {
panic(err)
} else {
if err := os.WriteFile(CONFIG_PATH, buf.Bytes(), 0644); err != nil {
panic(err)
}
}
}
func init() {
config = loadConfig()
}

3
backend/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/johannesbuehl/golunteer/backend
go 1.23.4

118
backend/setup.go Normal file
View File

@@ -0,0 +1,118 @@
package main
import (
"database/sql"
"fmt"
"math/rand/v2"
"os"
"regexp"
"strings"
"github.com/go-sql-driver/mysql"
"golang.org/x/crypto/bcrypt"
)
func createPassword(l int) string {
passwordChars := [...]string{`A`, `B`, `C`, `D`, `E`, `F`, `G`, `H`, `I`, `J`, `K`, `L`, `M`, `N`, `O`, `P`, `Q`, `R`, `S`, `T`, `U`, `V`, `W`, `X`, `Y`, `Z`, `Ä`, `Ö`, `Ü`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, `j`, `k`, `l`, `m`, `n`, `o`, `p`, `q`, `r`, `s`, `t`, `u`, `v`, `w`, `x`, `y`, `z`, `ä`, `ö`, `ü`, `ß`, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `!`, `"`, `§`, `$`, `%`, `&`, `/`, `(`, `)`, `=`, `?`, `@`, `{`, `}`, `[`, `]`, `#`, `+`, `'`, `*`, `,`, `.`, `-`, `;`, `:`, `_`, `<`, `>`, `|`, `°`}
var password string
for ii := 0; ii < l; ii++ {
password += passwordChars[rand.IntN(len(passwordChars))]
}
return password
}
func exit(e error) {
fmt.Printf("%v\n", e)
os.Exit(1)
}
func main() {
fmt.Println("connecting to database")
// connect to the database
sqlConfig := mysql.Config{
AllowNativePasswords: true,
Net: "tcp",
User: config.Database.User,
Passwd: config.Database.Password,
Addr: config.Database.Host,
DBName: config.Database.Database,
}
db, err := sql.Open("mysql", sqlConfig.FormatDSN())
if err != nil {
exit(err)
}
// load the sql-script
fmt.Println(`reading "setup.sql"`)
var sqlScriptCommands []byte
if c, err := os.ReadFile("setup.sql"); err != nil {
exit(err)
} else {
sqlScriptCommands = c
}
// read the currently availabe tables
fmt.Println("reading available tables in database")
if rows, err := db.Query("SHOW TABLES"); err != nil {
exit(err)
} else {
defer rows.Close()
fmt.Println("checking for already existing tables in database")
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
exit(err)
} else {
// check wether for the table there exists a create command
if match, err := regexp.Match(fmt.Sprintf(`(?i)^create table %s`, name), sqlScriptCommands); err != nil {
exit(err)
} else {
if match {
exit(fmt.Errorf("can't setup databases: table %q already exists", name))
}
}
}
}
}
// everything is good (so far), create the tables
fmt.Println("Creating the individual tables:")
for _, cmd := range strings.Split(string(sqlScriptCommands), ";") {
db.Exec(cmd)
}
fmt.Println("Creating admin-password:")
// create an admin-password
const passwordLength = 20
password := createPassword(passwordLength)
// hash the admin-password
if passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost); err != nil {
exit(err)
} else {
fmt.Println("\thashed password")
// create an admin-user
if _, err := db.Exec("INSERT INTO USERS (name, password) VALUES ('admin', ?)", passwordHash); err != nil {
exit(err)
}
fmt.Println("\twrote hashed password to database")
}
fmt.Printf("created user \"admin\" with password %s\n", password)
// create a jwt-signature
config.ClientSession.JwtSignature = createPassword(100)
// write the modified config-file
writeConfig()
}

View File

@@ -13,7 +13,7 @@
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
"postCreateCommand": "cd client && npm install"
"postCreateCommand": "npm install"
// Configure tool-specific properties.
// "customizations": {},

View File

@@ -0,0 +1,22 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "Go",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "go version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

1
setup/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
config.yaml

13
setup/go.mod Normal file
View File

@@ -0,0 +1,13 @@
module github.com/johannesbuehl/golunteer/setup
go 1.23.4
require (
github.com/go-sql-driver/mysql v1.8.1
gopkg.in/yaml.v3 v3.0.1
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
golang.org/x/crypto v0.32.0
)

9
setup/go.sum Normal file
View File

@@ -0,0 +1,9 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

44
setup/setup.sql Normal file
View File

@@ -0,0 +1,44 @@
CREATE TABLE TASKS (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
text varchar(64) NOT NULL,
disabled BOOL DEFAULT(false)
);
CREATE TABLE AVAILABILITIES (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
text varchar(32) NOT NULL,
disabled BOOL DEFAULT(false)
);
CREATE TABLE USERS (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name varchar(64) NOT NULL,
password binary(60) NOT NULL,
admin BOOL NOT NULL DEFAULT(false)
);
CREATE TABLE EVENTS (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
date DATETIME NOT NULL,
description TEXT DEFAULT("")
);
CREATE TABLE USER_AVAILABILITIES (
userID INTEGER NOT NULL,
eventID INTEGER NOT NULL,
availabilityID INTEGER NOT NULL,
PRIMARY KEY (userID, eventID),
FOREIGN KEY (userID) REFERENCES USERS(id) ON DELETE CASCADE,
FOREIGN KEY (eventID) REFERENCES EVENTS(id) ON DELETE CASCADE,
FOREIGN KEY (avaibID) REFERENCES AVAILABILITIES(id) ON DELETE RESTRICT,
);
CREATE TABLE USER_ASSIGNMENTS (
eventID INTEGER NOT NULL,
taskID INTEGER NOT NULL,
userID INTEGER NOT NULL,
PRIMARY KEY (eventID, taskID),
FOREIGN KEY (userID) REFERENCES USERS(id) ON DELETE CASCADE,
FOREIGN KEY (taskID) REFERENCES TASKS(id) ON DELETE RESTRICT,
FOREIGN KEY (eventID) REFERENCES EVENTS(id) ON DELETE CASCADE
);