first docker container version
This commit is contained in:
12
.dockerignore
Normal file
12
.dockerignore
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.git
|
||||||
|
|
||||||
|
backend/.devcontainer
|
||||||
|
backend/.vscode
|
||||||
|
backend/.gitignore
|
||||||
|
backend/logs
|
||||||
|
backend/config.yaml
|
||||||
|
|
||||||
|
client/node_modules
|
||||||
|
client/.gitignore
|
||||||
|
client/out
|
||||||
|
client/.next
|
||||||
47
Dockerfile
Normal file
47
Dockerfile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# build the backend
|
||||||
|
FROM golang:1.23-alpine AS backend-builder
|
||||||
|
|
||||||
|
# set the workdir
|
||||||
|
WORKDIR /usr/src/backend
|
||||||
|
|
||||||
|
# install the dependencies
|
||||||
|
COPY backend/go.mod backend/go.sum ./
|
||||||
|
RUN go mod download && go mod verify
|
||||||
|
|
||||||
|
# build the source-code
|
||||||
|
COPY backend .
|
||||||
|
RUN go build -ldflags "-s -w" -o dist/backend
|
||||||
|
|
||||||
|
# build the frontend
|
||||||
|
FROM node:current AS client-builder
|
||||||
|
|
||||||
|
WORKDIR /usr/src/client
|
||||||
|
|
||||||
|
COPY client/package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY client .
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
WORKDIR /usr/bin/app
|
||||||
|
|
||||||
|
# copy the backend
|
||||||
|
COPY --from=backend-builder /usr/src/backend/dist/backend backend
|
||||||
|
|
||||||
|
# copy the client-html
|
||||||
|
COPY --from=client-builder /usr/src/client/out html
|
||||||
|
|
||||||
|
# Create a group and user
|
||||||
|
RUN addgroup -S golunteer && adduser -S golunteer -G golunteer
|
||||||
|
|
||||||
|
EXPOSE 61016
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Tell docker that all future commands should run as the appuser user
|
||||||
|
USER golunteer
|
||||||
|
|
||||||
|
# run the app
|
||||||
|
CMD ["app"]
|
||||||
@@ -22,8 +22,8 @@ func init() {
|
|||||||
DB.MustExec("PRAGMA foreign_keys = ON")
|
DB.MustExec("PRAGMA foreign_keys = ON")
|
||||||
|
|
||||||
// create the tables if they don't exist
|
// create the tables if they don't exist
|
||||||
if dbSetupInstructions, err := os.ReadFile("setup.sql"); err != nil {
|
if dbSetupInstructions, err := os.ReadFile("tables.sql"); err != nil {
|
||||||
panic("can't read database-setup")
|
panic("can't read database-tables-setup")
|
||||||
} else {
|
} else {
|
||||||
DB.MustExec(string(dbSetupInstructions))
|
DB.MustExec(string(dbSetupInstructions))
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,13 @@ func setup() {
|
|||||||
// create a jwt-signature
|
// create a jwt-signature
|
||||||
config.ClientSession.JwtSignature = createPassword(100)
|
config.ClientSession.JwtSignature = createPassword(100)
|
||||||
|
|
||||||
|
// setp the database
|
||||||
|
if dbSetupInstructions, err := os.ReadFile("setup.sql"); err != nil {
|
||||||
|
panic("can't read database-setup")
|
||||||
|
} else {
|
||||||
|
DB.MustExec(string(dbSetupInstructions))
|
||||||
|
}
|
||||||
|
|
||||||
// write the modified config-file
|
// write the modified config-file
|
||||||
WriteConfig()
|
WriteConfig()
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,3 @@
|
|||||||
CREATE TABLE IF NOT EXISTS TASKS (
|
INSERT INTO TASKS (taskName) VALUES ("Audio"), ("Video");
|
||||||
taskID INTEGER PRIMARY KEY,
|
|
||||||
taskName varchar(64) NOT NULL,
|
|
||||||
enabled BOOL DEFAULT 1
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS AVAILABILITIES (
|
INSERT INTO AVAILABILITIES (availabilityName, color) VALUES ("Yes", "Green"), ("No", "Red");
|
||||||
availabilityID INTEGER PRIMARY KEY,
|
|
||||||
availabilityName varchar(32) NOT NULL,
|
|
||||||
color varchar(7) NOT NULL,
|
|
||||||
enabled BOOL DEFAULT 1
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS USERS (
|
|
||||||
userName varchar(64) PRIMARY KEY,
|
|
||||||
password BLOB NOT NULL,
|
|
||||||
admin BOOL NOT NULL DEFAULT(false),
|
|
||||||
tokenID varchar(36) NOT NULL,
|
|
||||||
CHECK (length(password) = 60),
|
|
||||||
CHECK (length(tokenID) = 36)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS USER_TASKS (
|
|
||||||
userName varchar(64),
|
|
||||||
taskID INTEGER,
|
|
||||||
PRIMARY KEY (userName, taskID),
|
|
||||||
FOREIGN KEY (userName) REFERENCES USERS(userName) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (taskID) REFERENCES TASKS(taskID) ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS EVENTS (
|
|
||||||
eventID INTEGER PRIMARY KEY,
|
|
||||||
date DATETIME NOT NULL,
|
|
||||||
description TEXT DEFAULT ""
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS USER_AVAILABILITIES (
|
|
||||||
userName varchar(64) NOT NULL,
|
|
||||||
eventID INTEGER NOT NULL,
|
|
||||||
availabilityID INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY (userName, eventID),
|
|
||||||
FOREIGN KEY (userName) REFERENCES USERS(userName) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (eventID) REFERENCES EVENTS(eventID) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (availabilityID) REFERENCES AVAILABILITIES(availabilityID) ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS USER_ASSIGNMENTS (
|
|
||||||
eventID INTEGER NOT NULL,
|
|
||||||
taskID INTEGER NOT NULL,
|
|
||||||
userName varchar(64),
|
|
||||||
PRIMARY KEY (eventID, taskID),
|
|
||||||
FOREIGN KEY (eventID) REFERENCES EVENTS(eventID) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (userName) REFERENCES USERS(userName) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (taskID) REFERENCES TASKS(taskID) ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
55
backend/tables.sql
Normal file
55
backend/tables.sql
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS TASKS (
|
||||||
|
taskID INTEGER PRIMARY KEY,
|
||||||
|
taskName varchar(64) NOT NULL,
|
||||||
|
enabled BOOL DEFAULT 1
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS AVAILABILITIES (
|
||||||
|
availabilityID INTEGER PRIMARY KEY,
|
||||||
|
availabilityName varchar(32) NOT NULL,
|
||||||
|
color varchar(7) NOT NULL,
|
||||||
|
enabled BOOL DEFAULT 1
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS USERS (
|
||||||
|
userName varchar(64) PRIMARY KEY,
|
||||||
|
password BLOB NOT NULL,
|
||||||
|
admin BOOL NOT NULL DEFAULT(false),
|
||||||
|
tokenID varchar(36) NOT NULL,
|
||||||
|
CHECK (length(password) = 60),
|
||||||
|
CHECK (length(tokenID) = 36)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS USER_TASKS (
|
||||||
|
userName varchar(64),
|
||||||
|
taskID INTEGER,
|
||||||
|
PRIMARY KEY (userName, taskID),
|
||||||
|
FOREIGN KEY (userName) REFERENCES USERS(userName) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (taskID) REFERENCES TASKS(taskID) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS EVENTS (
|
||||||
|
eventID INTEGER PRIMARY KEY,
|
||||||
|
date DATETIME NOT NULL,
|
||||||
|
description TEXT DEFAULT ""
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS USER_AVAILABILITIES (
|
||||||
|
userName varchar(64) NOT NULL,
|
||||||
|
eventID INTEGER NOT NULL,
|
||||||
|
availabilityID INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (userName, eventID),
|
||||||
|
FOREIGN KEY (userName) REFERENCES USERS(userName) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (eventID) REFERENCES EVENTS(eventID) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (availabilityID) REFERENCES AVAILABILITIES(availabilityID) ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS USER_ASSIGNMENTS (
|
||||||
|
eventID INTEGER NOT NULL,
|
||||||
|
taskID INTEGER NOT NULL,
|
||||||
|
userName varchar(64),
|
||||||
|
PRIMARY KEY (eventID, taskID),
|
||||||
|
FOREIGN KEY (eventID) REFERENCES EVENTS(eventID) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (userName) REFERENCES USERS(userName) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (taskID) REFERENCES TASKS(taskID) ON UPDATE CASCADE
|
||||||
|
);
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// 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"
|
|
||||||
}
|
|
||||||
2
setup/.gitignore
vendored
2
setup/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
config.yaml
|
|
||||||
passwords
|
|
||||||
15
setup/go.mod
15
setup/go.mod
@@ -1,15 +0,0 @@
|
|||||||
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
|
|
||||||
github.com/google/uuid v1.6.0
|
|
||||||
github.com/jmoiron/sqlx v1.4.0
|
|
||||||
golang.org/x/crypto v0.32.0
|
|
||||||
)
|
|
||||||
15
setup/go.sum
15
setup/go.sum
@@ -1,15 +0,0 @@
|
|||||||
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=
|
|
||||||
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/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
|
||||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
|
||||||
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=
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../backend/pkg/config/configYAML.go
|
|
||||||
124
setup/setup.go
124
setup/setup.go
@@ -1,124 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand/v2"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
|
|
||||||
"github.com/go-sql-driver/mysql"
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
_config "github.com/johannesbuehl/golunteer/setup/pkg/config"
|
|
||||||
"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() {
|
|
||||||
config := &_config.YamlConfig
|
|
||||||
|
|
||||||
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 := sqlx.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
|
|
||||||
tokenId := uuid.NewString()
|
|
||||||
if _, err := db.Exec("INSERT INTO USERS (name, password, tokenID) VALUES ('admin', ?, ?)", passwordHash, tokenId); 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
|
|
||||||
_config.WriteConfig()
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
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 (
|
|
||||||
name varchar(64) PRIMARY KEY,
|
|
||||||
password binary(60) NOT NULL,
|
|
||||||
admin BOOL NOT NULL DEFAULT(false),
|
|
||||||
tokenID varchar(64) NOT NULL,
|
|
||||||
CHECK (CHAR_LENGTH(password) = 60),
|
|
||||||
CHECK (CHAR_LENGTH(tokenID) = 36)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE EVENTS (
|
|
||||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
date DATETIME NOT NULL,
|
|
||||||
description TEXT DEFAULT("")
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE USER_AVAILABILITIES (
|
|
||||||
userName varchar(64) NOT NULL,
|
|
||||||
eventID INTEGER NOT NULL,
|
|
||||||
availabilityID INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY (userName, eventID),
|
|
||||||
FOREIGN KEY (userName) REFERENCES USERS(name) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (eventID) REFERENCES EVENTS(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (availabilityID) REFERENCES AVAILABILITIES(id) ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE USER_ASSIGNMENTS (
|
|
||||||
eventID INTEGER NOT NULL,
|
|
||||||
taskID INTEGER NOT NULL,
|
|
||||||
userName varchar(64),
|
|
||||||
PRIMARY KEY (eventID, taskID),
|
|
||||||
FOREIGN KEY (eventID) REFERENCES EVENTS(id) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (userName) REFERENCES USERS(name) ON DELETE CASCADE ON UPDATE CASCADE,
|
|
||||||
FOREIGN KEY (taskID) REFERENCES TASKS(id) ON UPDATE CASCADE
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user