From bf78edeec04c44cee655dc1e76c83a297e7c99e5 Mon Sep 17 00:00:00 2001 From: "Josepablo C." Date: Sun, 7 Dec 2025 08:51:10 -0600 Subject: [PATCH] initial commit, adding SQL connection and a simple testing on main --- .gitignore | 64 + app/go.mod | 29 + app/go.sum | 61 + app/libs/database/db.go | 42 + app/libs/database/schemas/rbac/rbac.go | 124 ++ app/main.go | 34 + app/openapi.yaml | 182 +++ db/.gitignore | 1 + db/Dockerfile | 23 + db/Models/assets/RBAC_model.svg | 1474 ++++++++++++++++++++++++ db/Models/model.mwb | Bin 0 -> 16094 bytes db/Models/sql_generated/db_init.sql | 55 + db/Models/sql_generated/schema.sql | 174 +++ db/README.md | 20 + db/scripts/migrate.sh | 12 + db/scripts/run.sh | 111 ++ 16 files changed, 2406 insertions(+) create mode 100644 .gitignore create mode 100644 app/go.mod create mode 100644 app/go.sum create mode 100644 app/libs/database/db.go create mode 100644 app/libs/database/schemas/rbac/rbac.go create mode 100644 app/main.go create mode 100644 app/openapi.yaml create mode 100644 db/.gitignore create mode 100644 db/Dockerfile create mode 100644 db/Models/assets/RBAC_model.svg create mode 100644 db/Models/model.mwb create mode 100644 db/Models/sql_generated/db_init.sql create mode 100644 db/Models/sql_generated/schema.sql create mode 100644 db/README.md create mode 100644 db/scripts/migrate.sh create mode 100644 db/scripts/run.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbc2b15 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Binaries for programs and plugins +*.exe +*.exec +*.exe~ +*.dll +*.so +*.dylib +*.test + +# Build output (common names) +/bin/ +/dist/ +/build/ +*.out +coverage.out + +# Go tooling +go.work +# Uncomment if you don't commit vendored deps +# vendor/ + +# Dependency manager files (optional) +Gopkg.lock +glide.lock + +# Generated code +gen/ +generated/ + +# Environment / secrets +.env +.env.* +*.key +*.pem + +# Logs +*.log + +# Editor directories and files +.idea/ +.vscode/ +*.iml +*.sublime-project +*.sublime-workspace + +# Swap/backup files +*~ +*.swp +*.swo +.#* + +# macOS / Windows +.DS_Store +Thumbs.db + +# Container / OS artifacts +docker-compose.override.yml + +# CI artifacts +coverage/ +reports/ + +# Misc +node_modules/ \ No newline at end of file diff --git a/app/go.mod b/app/go.mod new file mode 100644 index 0000000..317a053 --- /dev/null +++ b/app/go.mod @@ -0,0 +1,29 @@ +module cloud.etaviaporte.com/api + +go 1.23.2 + +require ( + github.com/joho/godotenv v1.5.1 + github.com/spf13/viper v1.21.0 + gorm.io/driver/mysql v1.6.0 + gorm.io/gorm v1.31.1 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.28.0 // indirect +) diff --git a/app/go.sum b/app/go.sum new file mode 100644 index 0000000..c1be72d --- /dev/null +++ b/app/go.sum @@ -0,0 +1,61 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +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/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/app/libs/database/db.go b/app/libs/database/db.go new file mode 100644 index 0000000..08c8fda --- /dev/null +++ b/app/libs/database/db.go @@ -0,0 +1,42 @@ +package database + +import ( + "log" + + "github.com/joho/godotenv" + "github.com/spf13/viper" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +var shared_db_connection *gorm.DB + +func initDB() *gorm.DB { + // load .env into environment (so viper can read them) + if err := godotenv.Load(); err != nil { + log.Println(".env not found or could not be loaded; proceeding with existing environment variables") + } + + viper.AutomaticEnv() // read from environment + + sql_dsn := viper.GetString("SQL_DSN") + + if sql_dsn == "" { + log.Fatal("SQL_DSN must be set in .env or environment") + } + + db, err := gorm.Open(mysql.Open(sql_dsn), &gorm.Config{}) + if err != nil { + log.Fatalf("failed to connect to MySQL Server: %v", err) + } + + log.Println("connected to MySQL Server") + return db +} + +func Init() *gorm.DB { + if shared_db_connection == nil { + shared_db_connection = initDB() + } + return shared_db_connection +} diff --git a/app/libs/database/schemas/rbac/rbac.go b/app/libs/database/schemas/rbac/rbac.go new file mode 100644 index 0000000..b0c5192 --- /dev/null +++ b/app/libs/database/schemas/rbac/rbac.go @@ -0,0 +1,124 @@ +/** + * @file schema.rbac.go + * @brief RBAC schema models for GORM + * + * This file defines the base database models used by the RBAC + * (Role-Based Access Control) system. Models map to the following + * tables: user_types, users, auth_identities, auth_credentials, + * roles, permissions, role_permissions and user_roles. + * + * The structs include GORM tags for column names and relationships: + * - UserType: types of users. + * - User: main user record; links to UserType, AuthIdentity and UserRole. + * - AuthIdentity: external identity providers; links to AuthCredential. + * - AuthCredential: stored credentials for an identity. + * - Role: role definitions and their permissions and assigned users. + * - Permission: permission definitions. + * - RolePermission: join table between Role and Permission. + * - UserRole: join table between User and Role with optional expiration. + * + * These models are intended for use with GORM to perform ORM operations + * against the RBAC schema. + */ + +package rbac + +import ( + "time" +) + +type UserType struct { + ID uint `gorm:"primaryKey;column:id"` + Name string `gorm:"type:text;column:name"` + Description *string `gorm:"type:text;column:description"` +} + +func (UserType) TableName() string { return "user_types" } + +type User struct { + ID uint `gorm:"primaryKey;column:id"` + UserTypeID uint `gorm:"column:user_type"` + Name string `gorm:"type:text;column:name"` + LastName string `gorm:"type:text;column:last_name"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` + + UserType UserType `gorm:"foreignKey:UserTypeID;references:ID"` + AuthIdentities []AuthIdentity `gorm:"foreignKey:UserID;references:ID"` + UserRoles []UserRole `gorm:"foreignKey:UserID;references:ID"` +} + +func (User) TableName() string { return "users" } + +type AuthIdentity struct { + ID uint `gorm:"primaryKey;column:id"` + UserID uint `gorm:"column:user_id"` + Provider string `gorm:"type:text;column:provider"` + Identifier string `gorm:"type:text;column:identifier"` + IsPrimary bool `gorm:"column:is_primary"` + IsVerified bool `gorm:"column:is_verified"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` + + User User `gorm:"foreignKey:UserID;references:ID"` + Credentials []AuthCredential `gorm:"foreignKey:IdentityID;references:ID"` +} + +func (AuthIdentity) TableName() string { return "auth_identities" } + +type AuthCredential struct { + ID uint `gorm:"primaryKey;column:id"` + IdentityID uint `gorm:"column:identity_id"` + Password string `gorm:"type:text;column:password"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` + + Identity AuthIdentity `gorm:"foreignKey:IdentityID;references:ID"` +} + +func (AuthCredential) TableName() string { return "auth_credentials" } + +type Role struct { + ID uint `gorm:"primaryKey;column:id"` + Name string `gorm:"type:text;column:name"` + Description *string `gorm:"type:text;column:description"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` + RolePermissions []RolePermission `gorm:"foreignKey:RoleID;references:ID"` + UserRoles []UserRole `gorm:"foreignKey:RoleID;references:ID"` +} + +func (Role) TableName() string { return "roles" } + +type Permission struct { + ID uint `gorm:"primaryKey;column:id"` + Name string `gorm:"type:text;column:name"` + Description *string `gorm:"type:text;column:description"` + RolePermissions []RolePermission `gorm:"foreignKey:PermissionID;references:ID"` +} + +func (Permission) TableName() string { return "permissions" } + +type RolePermission struct { + ID uint `gorm:"primaryKey;column:id"` + RoleID uint `gorm:"column:role_id"` + PermissionID uint `gorm:"column:permission_id"` + + Role Role `gorm:"foreignKey:RoleID;references:ID"` + Permission Permission `gorm:"foreignKey:PermissionID;references:ID"` +} + +func (RolePermission) TableName() string { return "role_permissions" } + +type UserRole struct { + ID uint `gorm:"primaryKey;column:id"` + UserID uint `gorm:"column:user_id"` + RoleID uint `gorm:"column:role_id"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` + ExpiresAt *time.Time `gorm:"column:expires_at"` + + User User `gorm:"foreignKey:UserID;references:ID"` + Role Role `gorm:"foreignKey:RoleID;references:ID"` +} + +func (UserRole) TableName() string { return "user_roles" } diff --git a/app/main.go b/app/main.go new file mode 100644 index 0000000..3340aca --- /dev/null +++ b/app/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + + database "cloud.etaviaporte.com/api/libs/database" + rbac "cloud.etaviaporte.com/api/libs/database/schemas/rbac" +) + +func main() { + var connection = database.Init() + + // Prepare a variable to hold the fetched user record. + // Replace rbac.User with the actual struct name if different. + var user rbac.User + + // Fetch the user whose primary key is 1. + // GORM's First method, when given a numeric id as the second argument, queries by primary key. + result := connection.First(&user, 1) + + // result.Error holds any error from the DB operation (including "record not found"). + // result.RowsAffected tells how many rows were returned. + if result.Error != nil { + // Handle the error (could be gorm.ErrRecordNotFound or a DB/connection error). + // For learning purposes we print the error and exit main. + fmt.Printf("failed to fetch user with id=1: %v\n", result.Error) + return + } + + // If no error, user now contains the row from the database. + // Print the struct with field names and values to inspect the loaded data. + fmt.Printf("User fetched: %+v\n", user) + +} diff --git a/app/openapi.yaml b/app/openapi.yaml new file mode 100644 index 0000000..d784ba2 --- /dev/null +++ b/app/openapi.yaml @@ -0,0 +1,182 @@ +openapi: 3.0.3 +info: + title: Authorization API + version: "1.0.0" + description: Simple authorization endpoints for login, refresh, logout and getting current user info. +servers: + - url: http://localhost:8080 + description: Local development server + +paths: + /auth/login: + post: + summary: Obtain access and refresh tokens + tags: + - Auth + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginRequest' + responses: + '200': + description: Tokens issued + content: + application/json: + schema: + $ref: '#/components/schemas/TokenResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + /auth/refresh: + post: + summary: Refresh access token using a refresh token + tags: + - Auth + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RefreshRequest' + responses: + '200': + description: New tokens + content: + application/json: + schema: + $ref: '#/components/schemas/TokenResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + /auth/logout: + post: + summary: Revoke refresh token / logout + tags: + - Auth + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RevokeRequest' + responses: + '204': + description: Successfully logged out (no content) + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + /auth/me: + get: + summary: Get current authenticated user + tags: + - Auth + security: + - bearerAuth: [] + responses: + '200': + description: Current user profile + content: + application/json: + schema: + $ref: '#/components/schemas/UserProfile' + '401': + $ref: '#/components/responses/Unauthorized' + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + + schemas: + LoginRequest: + type: object + required: + - username + - password + properties: + username: + type: string + example: user@example.com + password: + type: string + format: password + example: secret123 + + TokenResponse: + type: object + properties: + accessToken: + type: string + example: eyJhbGciOi... + refreshToken: + type: string + example: dummyr3fr3sht0k3n + expiresIn: + type: integer + description: Seconds until access token expiration + example: 3600 + + RefreshRequest: + type: object + required: + - refreshToken + properties: + refreshToken: + type: string + + RevokeRequest: + type: object + required: + - refreshToken + properties: + refreshToken: + type: string + + UserProfile: + type: object + properties: + id: + type: string + example: "123e4567-e89b-12d3-a456-426614174000" + username: + type: string + example: user@example.com + email: + type: string + example: user@example.com + + Error: + type: object + properties: + code: + type: string + example: invalid_request + message: + type: string + example: "Detailed error message" + + responses: + BadRequest: + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + Unauthorized: + description: Authentication failed or missing credentials + content: + application/json: + schema: + $ref: '#/components/schemas/Error' diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..751553b --- /dev/null +++ b/db/.gitignore @@ -0,0 +1 @@ +*.bak diff --git a/db/Dockerfile b/db/Dockerfile new file mode 100644 index 0000000..4a03601 --- /dev/null +++ b/db/Dockerfile @@ -0,0 +1,23 @@ +# Original author : https://github.com/yobasystems/alpine-mariadb.git +FROM alpine:latest + +ARG BUILD_DATE +ARG VCS_REF + +RUN apk add --no-cache mariadb mysql-client mariadb-server-utils pwgen && \ + rm -f /var/cache/apk/* + +RUN mkdir /schemas +COPY schemas /schemas + +ADD scripts/run.sh /scripts/run.sh +RUN mkdir /docker-entrypoint-initdb.d && \ + mkdir /scripts/pre-exec.d && \ + mkdir /scripts/pre-init.d && \ + chmod -R 755 /scripts + +EXPOSE 3306 + +VOLUME ["/var/lib/mysql"] + +ENTRYPOINT ["/scripts/run.sh"] diff --git a/db/Models/assets/RBAC_model.svg b/db/Models/assets/RBAC_model.svg new file mode 100644 index 0000000..2f7c5d1 --- /dev/null +++ b/db/Models/assets/RBAC_model.svg @@ -0,0 +1,1474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/db/Models/model.mwb b/db/Models/model.mwb new file mode 100644 index 0000000000000000000000000000000000000000..f2170271aed6424ff90eb0f0a23533aef47efca9 GIT binary patch literal 16094 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 root + +-- Creation of basic roles +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("root","Root role with no restricted access",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_admin","System Level Admin",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_developer","System Level Developer",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_reader","System Level Read Only",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_staff","System Level staff member",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_owner","Unrestricted access to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_manager","Access as manager to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_staff","Access as staff to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_driver","Simple access to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_observer","Limited access to company resources",NOW(),NOW()); + +-- Creation of basic permissions +INSERT INTO permissions (name, description) VALUES ("root","Root role with no restricted access"); +INSERT INTO permissions (name, description) VALUES ("system.admin","System Level Admin"); +INSERT INTO permissions (name, description) VALUES ("system.developer","System Level Developer"); +INSERT INTO permissions (name, description) VALUES ("system.reader","System Level Reader"); +INSERT INTO permissions (name, description) VALUES ("system.staff","System Level Staff Member"); +INSERT INTO permissions (name, description) VALUES ("company.owner","Unrestricted access to company resources"); +INSERT INTO permissions (name, description) VALUES ("company.manager","Admin access to company resources"); +INSERT INTO permissions (name, description) VALUES ("company.staff","Staff access to company resources"); +INSERT INTO permissions (name, description) VALUES ("company.driver","Driver with simple access to company resources"); +INSERT INTO permissions (name, description) VALUES ("company.observer","Observer with simple access to company resources"); + +-- Link of basic roles with its permissions +INSERT INTO role_permissions (role_id, permission_id) VALUES( 1, 1 ); -- root -> root +INSERT INTO role_permissions (role_id, permission_id) VALUES( 2, 2 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 3, 3 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 4, 4 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 5, 5 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 6, 6 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 7, 7 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 8, 8 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 9, 9 ); +INSERT INTO role_permissions (role_id, permission_id) VALUES( 10, 10 ); + +-- Link of Root User with its role + +INSERT INTO user_roles (user_id, role_id, created_at ) VALUES (1,1,NOW()); -- root -> root + +-- Create Root Auth Identity and credentials + +INSERT INTO auth_identities (user_id, provider, identifier, is_primary, is_verified, created_at, updated_at ) VALUES (1,"email","josepablo134@gmail.com",1,1,NOW(),NOW()); -- root access with email +INSERT INTO auth_credentials (identity_id, password, created_at, updated_at) VALUES (1, "PasswordGoesHere", NOW(), NOW()); diff --git a/db/Models/sql_generated/schema.sql b/db/Models/sql_generated/schema.sql new file mode 100644 index 0000000..d0dde57 --- /dev/null +++ b/db/Models/sql_generated/schema.sql @@ -0,0 +1,174 @@ +-- MySQL Script generated by MySQL Workbench +-- Sun Dec 7 08:38:42 2025 +-- Model: New Model Version: 1.0 +-- MySQL Workbench Forward Engineering + +SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; +SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; +SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; + +-- ----------------------------------------------------- +-- Schema u947463964_etaviaporte +-- ----------------------------------------------------- + +-- ----------------------------------------------------- +-- Schema u947463964_etaviaporte +-- ----------------------------------------------------- +CREATE SCHEMA IF NOT EXISTS `u947463964_etaviaporte` DEFAULT CHARACTER SET utf8 ; +USE `u947463964_etaviaporte` ; + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`user_types` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_types` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `name` TEXT NOT NULL, + `description` TEXT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`users` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`users` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_type` INT UNSIGNED NOT NULL, + `name` TEXT NOT NULL, + `last_name` TEXT NOT NULL, + `created_at` DATETIME NOT NULL, + `updated_at` DATETIME NOT NULL, + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, + PRIMARY KEY (`id`), + INDEX `fk_users_user_types1_idx` (`user_type` ASC) VISIBLE, + CONSTRAINT `fk_users_user_types1` + FOREIGN KEY (`user_type`) + REFERENCES `u947463964_etaviaporte`.`user_types` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`auth_identities` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`auth_identities` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT UNSIGNED NOT NULL, + `provider` TEXT NOT NULL, + `identifier` TEXT NOT NULL COMMENT 'email, phone google, facebook, etc.', + `is_primary` TINYINT NOT NULL DEFAULT 0, + `is_verified` TINYINT NOT NULL DEFAULT 0, + `created_at` DATETIME NOT NULL, + `updated_at` DATETIME NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, + INDEX `fk_auth_identities_users_idx` (`user_id` ASC) VISIBLE, + CONSTRAINT `fk_auth_identities_users` + FOREIGN KEY (`user_id`) + REFERENCES `u947463964_etaviaporte`.`users` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`auth_credentials` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`auth_credentials` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `identity_id` INT UNSIGNED NOT NULL, + `password` TEXT NOT NULL, + `created_at` DATETIME NOT NULL, + `updated_at` DATETIME NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, + INDEX `fk_auth_credentials_auth_identities1_idx` (`identity_id` ASC) VISIBLE, + CONSTRAINT `fk_auth_credentials_auth_identities1` + FOREIGN KEY (`identity_id`) + REFERENCES `u947463964_etaviaporte`.`auth_identities` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`roles` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`roles` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `name` TEXT NOT NULL, + `description` TEXT NULL, + `created_at` DATETIME NOT NULL, + `updated_at` DATETIME NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`permissions` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`permissions` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `name` TEXT NOT NULL, + `description` TEXT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`role_permissions` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`role_permissions` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `role_id` INT UNSIGNED NOT NULL, + `permission_id` INT UNSIGNED NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, + INDEX `fk_role_permissions_roles1_idx` (`role_id` ASC) VISIBLE, + INDEX `fk_role_permissions_permissions1_idx` (`permission_id` ASC) VISIBLE, + CONSTRAINT `fk_role_permissions_roles1` + FOREIGN KEY (`role_id`) + REFERENCES `u947463964_etaviaporte`.`roles` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION, + CONSTRAINT `fk_role_permissions_permissions1` + FOREIGN KEY (`permission_id`) + REFERENCES `u947463964_etaviaporte`.`permissions` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`user_roles` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_roles` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT UNSIGNED NOT NULL, + `role_id` INT UNSIGNED NOT NULL, + `created_at` DATETIME NOT NULL, + `expires_at` DATETIME NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, + INDEX `fk_user_roles_users1_idx` (`user_id` ASC) VISIBLE, + INDEX `fk_user_roles_roles1_idx` (`role_id` ASC) VISIBLE, + CONSTRAINT `fk_user_roles_users1` + FOREIGN KEY (`user_id`) + REFERENCES `u947463964_etaviaporte`.`users` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION, + CONSTRAINT `fk_user_roles_roles1` + FOREIGN KEY (`role_id`) + REFERENCES `u947463964_etaviaporte`.`roles` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +SET SQL_MODE=@OLD_SQL_MODE; +SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; +SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; diff --git a/db/README.md b/db/README.md new file mode 100644 index 0000000..26ada2f --- /dev/null +++ b/db/README.md @@ -0,0 +1,20 @@ +# ETAv2SQL + +# MySQL Databse schema + +![etaviaporte](./Models/assets/Modelv2.0.0.png) + +# Docker + +## Build Docker image + +docker buildx build -t eta/eta-db + +## Run Docker container + +```{.sh} +docker run --name eta-db -d -p3306:3306 eta/eta-db +docker logs -f eta-db +``` + +Container will generate automatically a SQL root password diff --git a/db/scripts/migrate.sh b/db/scripts/migrate.sh new file mode 100644 index 0000000..bf512ac --- /dev/null +++ b/db/scripts/migrate.sh @@ -0,0 +1,12 @@ +#! /bin/bash + +# This script does not avoid invalid queries while applying changes +USER=developer +HOST=127.0.0.2 +PASS=Password1234 +DBNAME=etaviaporte + +mysqldump -h$HOST -u$USER -p$PASS $DBNAME > temp_copy.sql + +mysql -h$HOST -u$USER -p$PASS < model.sql +mysql -h$HOST -u$USER -p$PASS < model_init.sql diff --git a/db/scripts/run.sh b/db/scripts/run.sh new file mode 100644 index 0000000..cc5b9e9 --- /dev/null +++ b/db/scripts/run.sh @@ -0,0 +1,111 @@ +#!/bin/sh + +# execute any pre-init scripts +for i in /scripts/pre-init.d/*sh +do + if [ -e "${i}" ]; then + echo "[i] pre-init.d - processing $i" + . "${i}" + fi +done + +if [ -d "/run/mysqld" ]; then + echo "[i] mysqld already present, skipping creation" + chown -R mysql:mysql /run/mysqld +else + echo "[i] mysqld not found, creating...." + mkdir -p /run/mysqld + chown -R mysql:mysql /run/mysqld +fi + +if [ -d /var/lib/mysql/mysql ]; then + echo "[i] MySQL directory already present, skipping creation" + chown -R mysql:mysql /var/lib/mysql + + echo "[i] MySQL root Password:" $(cat /schemas/password.txt) +else + echo "[i] MySQL data directory not found, creating initial DBs" + + chown -R mysql:mysql /var/lib/mysql + + mysql_install_db --user=mysql --ldata=/var/lib/mysql > /dev/null + + if [ "$MYSQL_ROOT_PASSWORD" = "" ]; then + MYSQL_ROOT_PASSWORD=`pwgen 16 1` + echo "[i] MySQL root Password: $MYSQL_ROOT_PASSWORD" + fi + + MYSQL_DATABASE=${MYSQL_DATABASE:-""} + MYSQL_USER=${MYSQL_USER:-""} + MYSQL_PASSWORD=${MYSQL_PASSWORD:-""} + + tfile=`mktemp` + if [ ! -f "$tfile" ]; then + return 1 + fi + + cat << EOF > $tfile +USE mysql; +FLUSH PRIVILEGES ; +GRANT ALL ON *.* TO 'root'@'%' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ; +GRANT ALL ON *.* TO 'root'@'localhost' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ; +SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ; +DROP DATABASE IF EXISTS test ; +FLUSH PRIVILEGES ; +EOF + + if [ "$MYSQL_DATABASE" != "" ]; then + echo "[i] Creating database: $MYSQL_DATABASE" + if [ "$MYSQL_CHARSET" != "" ] && [ "$MYSQL_COLLATION" != "" ]; then + echo "[i] with character set [$MYSQL_CHARSET] and collation [$MYSQL_COLLATION]" + echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` CHARACTER SET $MYSQL_CHARSET COLLATE $MYSQL_COLLATION;" >> $tfile + else + echo "[i] with character set: 'utf8' and collation: 'utf8_general_ci'" + echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` CHARACTER SET utf8 COLLATE utf8_general_ci;" >> $tfile + fi + + if [ "$MYSQL_USER" != "" ]; then + echo "[i] Creating user: $MYSQL_USER with password $MYSQL_PASSWORD" + echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* to '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';" >> $tfile + fi + fi + + /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < $tfile + rm -f $tfile + + for f in /docker-entrypoint-initdb.d/*; do + case "$f" in + *.sql) echo "$0: running $f"; /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < "$f"; echo ;; + *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < "$f"; echo ;; + *) echo "$0: ignoring or entrypoint initdb empty $f" ;; + esac + echo + done + + echo + echo 'MySQL init process done. Ready for start up.' + echo + + echo "exec /usr/bin/mysqld --user=mysql --console --skip-name-resolve --skip-networking=0" "$@" + + # Saving plain password + echo $MYSQL_ROOT_PASSWORD > /schemas/password.txt + + # # After 5 seconds (once mysql is up) create schema. + # $(sleep 5 && /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/wincify.sql &&\ + # /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/wincify_zones.sql &&\ + # /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/wincify_categories.sql &&\ + # /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/system.sql &&\ + # /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD wincify_system < /schemas/wincifySystem_init.sql ) &\ +fi + +# execute any pre-exec scripts +for i in /scripts/pre-exec.d/*sh +do + if [ -e "${i}" ]; then + echo "[i] pre-exec.d - processing $i" + . ${i} + fi +done + +exec /usr/bin/mysqld --user=mysql --console --skip-name-resolve --skip-networking=0 $@