created setup and backend structure
This commit is contained in:
22
backend/.devcontainer/devcontainer.json
Normal file
22
backend/.devcontainer/devcontainer.json
Normal 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
1
backend/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
config.yaml
|
||||||
72
backend/config.go
Normal file
72
backend/config.go
Normal 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
3
backend/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/johannesbuehl/golunteer/backend
|
||||||
|
|
||||||
|
go 1.23.4
|
||||||
118
backend/setup.go
Normal file
118
backend/setup.go
Normal 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()
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
// "postCreateCommand": "yarn install",
|
// "postCreateCommand": "yarn install",
|
||||||
"postCreateCommand": "cd client && npm install"
|
"postCreateCommand": "npm install"
|
||||||
|
|
||||||
// Configure tool-specific properties.
|
// Configure tool-specific properties.
|
||||||
// "customizations": {},
|
// "customizations": {},
|
||||||
22
setup/.devcontainer/devcontainer.json
Normal file
22
setup/.devcontainer/devcontainer.json
Normal 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
1
setup/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
config.yaml
|
||||||
13
setup/go.mod
Normal file
13
setup/go.mod
Normal 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
9
setup/go.sum
Normal 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
44
setup/setup.sql
Normal 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
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user