init
This commit is contained in:
parent
b250fbc77e
commit
ab3f6d4313
46
.air.toml
Normal file
46
.air.toml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "./tmp/main"
|
||||
cmd = "go build -o ./tmp/main ./cmd"
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go"]
|
||||
exclude_unchanged = false
|
||||
follow_symlink = false
|
||||
full_bin = ""
|
||||
include_dir = []
|
||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||
include_file = []
|
||||
kill_delay = "0s"
|
||||
log = "build-errors.log"
|
||||
poll = false
|
||||
poll_interval = 0
|
||||
post_cmd = []
|
||||
pre_cmd = []
|
||||
rerun = false
|
||||
rerun_delay = 500
|
||||
send_interrupt = false
|
||||
stop_on_error = false
|
||||
|
||||
[color]
|
||||
app = ""
|
||||
build = "yellow"
|
||||
main = "magenta"
|
||||
runner = "green"
|
||||
watcher = "cyan"
|
||||
|
||||
[log]
|
||||
main_only = false
|
||||
time = false
|
||||
|
||||
[misc]
|
||||
clean_on_exit = false
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = false
|
||||
keep_scroll = true
|
||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
bin
|
||||
coverage.out
|
||||
coverage
|
||||
.env
|
||||
tmp
|
||||
build
|
||||
5
cmd/main.go
Normal file
5
cmd/main.go
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
||||
37
compose.db.yaml
Normal file
37
compose.db.yaml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
ports:
|
||||
- 5422:5432
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=secret
|
||||
- POSTGRES_USER=root
|
||||
- POSTGRES_DB=gh
|
||||
networks:
|
||||
- app
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U root -d gh"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
migrate:
|
||||
image: migrate/migrate
|
||||
volumes:
|
||||
- ./db/migrations:/migrations
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
command:
|
||||
[
|
||||
"-path",
|
||||
"/migrations",
|
||||
"-database",
|
||||
"postgresql://root:secret@postgres:5432/gh?sslmode=disable",
|
||||
"up",
|
||||
]
|
||||
networks:
|
||||
- app
|
||||
|
||||
networks:
|
||||
app:
|
||||
driver: bridge
|
||||
74
db/migrations/000001_fortune.down.sql
Normal file
74
db/migrations/000001_fortune.down.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- Drop tables that depend on service_type_setting
|
||||
DROP TABLE IF EXISTS service_type_setting;
|
||||
|
||||
-- Drop product-related tables and types
|
||||
DROP TABLE IF EXISTS product;
|
||||
DROP TYPE IF EXISTS tier_group;
|
||||
|
||||
-- Drop onboarding-related tables and types
|
||||
DROP TABLE IF EXISTS verification_key;
|
||||
DROP TABLE IF EXISTS onboarding_user;
|
||||
DROP TYPE IF EXISTS verification_status;
|
||||
DROP TYPE IF EXISTS onboarding_status;
|
||||
|
||||
-- Drop staff-related tables and types
|
||||
DROP TABLE IF EXISTS staff_session;
|
||||
DROP TABLE IF EXISTS user_agent;
|
||||
DROP TABLE IF EXISTS staff;
|
||||
DROP TYPE IF EXISTS password_status;
|
||||
|
||||
-- Drop mobile app-related tables and types
|
||||
DROP TABLE IF EXISTS user_devices;
|
||||
DROP TABLE IF EXISTS user_session;
|
||||
DROP TABLE IF EXISTS linked_accounts;
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP TYPE IF EXISTS device_type;
|
||||
DROP TYPE IF EXISTS registeration_type;
|
||||
DROP TYPE IF EXISTS customer_group;
|
||||
|
||||
-- Drop linked accounts and beneficiary tables and types
|
||||
DROP TABLE IF EXISTS beneficiary;
|
||||
DROP TYPE IF EXISTS fund_destination;
|
||||
|
||||
-- Drop maker checker-related tables and types
|
||||
DROP TABLE IF EXISTS workflow;
|
||||
DROP TYPE IF EXISTS approval_status;
|
||||
DROP TYPE IF EXISTS action_type;
|
||||
DROP TYPE IF EXISTS context_type;
|
||||
|
||||
-- Drop authorization-related tables and types
|
||||
DROP TRIGGER IF EXISTS enforce_unique_array ON policy;
|
||||
DROP FUNCTION IF EXISTS check_unique_array;
|
||||
DROP TABLE IF EXISTS policy;
|
||||
DROP TABLE IF EXISTS roles;
|
||||
DROP TYPE IF EXISTS policy_action;
|
||||
DROP TYPE IF EXISTS policy_object;
|
||||
|
||||
-- Drop bank-related tables and types
|
||||
DROP TABLE IF EXISTS bank;
|
||||
DROP TABLE IF EXISTS flagged_users;
|
||||
|
||||
-- Drop transaction-related tables and types
|
||||
DROP TABLE IF EXISTS transaction_daily;
|
||||
DROP TABLE IF EXISTS system_limits;
|
||||
DROP TABLE IF EXISTS transactions;
|
||||
DROP TYPE IF EXISTS payment_status;
|
||||
DROP TYPE IF EXISTS service_type;
|
||||
DROP TYPE IF EXISTS channel;
|
||||
DROP TYPE IF EXISTS transaction_category;
|
||||
DROP TYPE IF EXISTS registration_type;
|
||||
|
||||
-- Drop branches and related tables
|
||||
DROP TABLE IF EXISTS branches;
|
||||
DROP TABLE IF EXISTS cities;
|
||||
DROP TABLE IF EXISTS districts;
|
||||
DROP TABLE IF EXISTS regions;
|
||||
|
||||
-- Drop activity logs
|
||||
DROP TABLE IF EXISTS activity;
|
||||
|
||||
-- Drop ussd account and related enums
|
||||
DROP TABLE IF EXISTS ussd_account;
|
||||
DROP TYPE IF EXISTS ua_pin_status;
|
||||
DROP TYPE IF EXISTS ua_status;
|
||||
DROP TYPE IF EXISTS ua_registaration_type;
|
||||
12
db/migrations/000001_fortune.up.sql
Normal file
12
db/migrations/000001_fortune.up.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
CREATE TABLE users (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
first_name VARCHAR(255) NOT NULL,
|
||||
last_name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
phone_number VARCHAR(20) UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
role VARCHAR(50) NOT NULL,
|
||||
verified BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP ,
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
16
db/query/user.sql
Normal file
16
db/query/user.sql
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
-- name: CreateUser :one
|
||||
INSERT INTO users (first_name, last_name, email, phone_number, password, role, verified)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetUserByID :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- name: GetAllUsers :many
|
||||
SELECT * FROM users;
|
||||
|
||||
-- name: UpdateUser :exec
|
||||
UPDATE users SET first_name = $2, last_name = $3, email = $4, phone_number = $5, password = $6, role = $7, verified = $8, updated_at = CURRENT_TIMESTAMP WHERE id = $1;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = $1;
|
||||
32
gen/db/db.go
Normal file
32
gen/db/db.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.26.0
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
||||
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
||||
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
||||
22
gen/db/models.go
Normal file
22
gen/db/models.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.26.0
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64
|
||||
FirstName string
|
||||
LastName string
|
||||
Email string
|
||||
PhoneNumber string
|
||||
Password string
|
||||
Role string
|
||||
Verified pgtype.Bool
|
||||
CreatedAt pgtype.Timestamp
|
||||
UpdatedAt pgtype.Timestamp
|
||||
}
|
||||
149
gen/db/user.sql.go
Normal file
149
gen/db/user.sql.go
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.26.0
|
||||
// source: user.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const CreateUser = `-- name: CreateUser :one
|
||||
INSERT INTO users (first_name, last_name, email, phone_number, password, role, verified)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, first_name, last_name, email, phone_number, password, role, verified, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
Email string
|
||||
PhoneNumber string
|
||||
Password string
|
||||
Role string
|
||||
Verified pgtype.Bool
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
|
||||
row := q.db.QueryRow(ctx, CreateUser,
|
||||
arg.FirstName,
|
||||
arg.LastName,
|
||||
arg.Email,
|
||||
arg.PhoneNumber,
|
||||
arg.Password,
|
||||
arg.Role,
|
||||
arg.Verified,
|
||||
)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.FirstName,
|
||||
&i.LastName,
|
||||
&i.Email,
|
||||
&i.PhoneNumber,
|
||||
&i.Password,
|
||||
&i.Role,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const DeleteUser = `-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteUser, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetAllUsers = `-- name: GetAllUsers :many
|
||||
SELECT id, first_name, last_name, email, phone_number, password, role, verified, created_at, updated_at FROM users
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllUsers(ctx context.Context) ([]User, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllUsers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []User
|
||||
for rows.Next() {
|
||||
var i User
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.FirstName,
|
||||
&i.LastName,
|
||||
&i.Email,
|
||||
&i.PhoneNumber,
|
||||
&i.Password,
|
||||
&i.Role,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetUserByID = `-- name: GetUserByID :one
|
||||
SELECT id, first_name, last_name, email, phone_number, password, role, verified, created_at, updated_at FROM users WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
|
||||
row := q.db.QueryRow(ctx, GetUserByID, id)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.FirstName,
|
||||
&i.LastName,
|
||||
&i.Email,
|
||||
&i.PhoneNumber,
|
||||
&i.Password,
|
||||
&i.Role,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateUser = `-- name: UpdateUser :exec
|
||||
UPDATE users SET first_name = $2, last_name = $3, email = $4, phone_number = $5, password = $6, role = $7, verified = $8, updated_at = CURRENT_TIMESTAMP WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateUserParams struct {
|
||||
ID int64
|
||||
FirstName string
|
||||
LastName string
|
||||
Email string
|
||||
PhoneNumber string
|
||||
Password string
|
||||
Role string
|
||||
Verified pgtype.Bool
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateUser,
|
||||
arg.ID,
|
||||
arg.FirstName,
|
||||
arg.LastName,
|
||||
arg.Email,
|
||||
arg.PhoneNumber,
|
||||
arg.Password,
|
||||
arg.Role,
|
||||
arg.Verified,
|
||||
)
|
||||
return err
|
||||
}
|
||||
14
go.mod
Normal file
14
go.mod
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module github.com/SamuelTariku/FortuneBet-Backend
|
||||
|
||||
go 1.24.1
|
||||
|
||||
require github.com/jackc/pgx/v5 v5.7.4
|
||||
|
||||
require (
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
)
|
||||
28
go.sum
Normal file
28
go.sum
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
|
||||
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
1
internal/domain/auth.go
Normal file
1
internal/domain/auth.go
Normal file
|
|
@ -0,0 +1 @@
|
|||
package domain
|
||||
12
internal/domain/user.go
Normal file
12
internal/domain/user.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package domain
|
||||
|
||||
type User struct {
|
||||
ID int64
|
||||
FirstName string
|
||||
LastName string
|
||||
Email string
|
||||
PhoneNumber string
|
||||
Password string
|
||||
Role string
|
||||
Verified bool
|
||||
}
|
||||
41
internal/repository/store.go
Normal file
41
internal/repository/store.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
queries *dbgen.Queries
|
||||
conn *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewStore(conn *pgxpool.Pool) *Store {
|
||||
|
||||
queries := dbgen.New(conn)
|
||||
return &Store{
|
||||
queries: queries,
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
func OpenDB(url string) (*pgxpool.Pool, func(), error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
conn, err := pgxpool.New(ctx, url)
|
||||
if err != nil {
|
||||
return nil, func() {}, err
|
||||
}
|
||||
|
||||
if err := conn.Ping(ctx); err != nil {
|
||||
return nil, func() {}, err
|
||||
}
|
||||
|
||||
return conn, func() {
|
||||
conn.Close()
|
||||
}, nil
|
||||
}
|
||||
81
internal/repository/user.go
Normal file
81
internal/repository/user.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
func (s *Store) CreateUser(ctx context.Context, firstName, lastName, email, phoneNumber, password, role string, verified bool) (domain.User, error) {
|
||||
user, err := s.queries.CreateUser(ctx, dbgen.CreateUserParams{
|
||||
FirstName: firstName,
|
||||
LastName: lastName,
|
||||
Email: email,
|
||||
PhoneNumber: phoneNumber,
|
||||
Password: password,
|
||||
Role: role,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.User{}, err
|
||||
}
|
||||
return domain.User{
|
||||
ID: user.ID,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Email: user.Email,
|
||||
PhoneNumber: user.PhoneNumber,
|
||||
Password: user.Password,
|
||||
Role: user.Role,
|
||||
}, nil
|
||||
|
||||
}
|
||||
func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
|
||||
user, err := s.queries.GetUserByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.User{}, err
|
||||
}
|
||||
return domain.User{
|
||||
ID: user.ID,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Email: user.Email,
|
||||
PhoneNumber: user.PhoneNumber,
|
||||
Password: user.Password,
|
||||
Role: user.Role,
|
||||
}, nil
|
||||
}
|
||||
func (s *Store) GetAllUsers(ctx context.Context) ([]domain.User, error) {
|
||||
users, err := s.queries.GetAllUsers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []domain.User
|
||||
for _, user := range users {
|
||||
result = append(result, domain.User{
|
||||
ID: user.ID,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Email: user.Email,
|
||||
PhoneNumber: user.PhoneNumber,
|
||||
Password: user.Password,
|
||||
Role: user.Role,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
func (s *Store) UpdateUser(ctx context.Context, id int64, firstName, lastName, email, phoneNumber, password, role string, verified bool) error {
|
||||
err := s.queries.UpdateUser(ctx, dbgen.UpdateUserParams{
|
||||
ID: id,
|
||||
FirstName: firstName,
|
||||
LastName: lastName,
|
||||
Email: email,
|
||||
PhoneNumber: phoneNumber,
|
||||
Password: password,
|
||||
Role: role,
|
||||
})
|
||||
return err
|
||||
}
|
||||
func (s *Store) DeleteUser(ctx context.Context, id int64) error {
|
||||
return s.queries.DeleteUser(ctx, id)
|
||||
}
|
||||
15
internal/services/user/port.go
Normal file
15
internal/services/user/port.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
type UserStore interface {
|
||||
CreateUser(ctx context.Context, CfirstName, lastName, email, phoneNumber, password, role string, verified bool) (domain.User, error)
|
||||
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||
GetAllUsers(ctx context.Context) ([]domain.User, error)
|
||||
UpdateUser(ctx context.Context, id int64, firstName, lastName, email, phoneNumber, password, role string, verified bool) error
|
||||
DeleteUser(ctx context.Context, id int64) error
|
||||
}
|
||||
33
internal/services/user/service.go
Normal file
33
internal/services/user/service.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
userStore UserStore
|
||||
}
|
||||
|
||||
func NewService(userStore UserStore) *Service {
|
||||
return &Service{
|
||||
userStore: userStore,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) CreateUser(ctx context.Context, firstName, lastName, email, phoneNumber, password, role string, verified bool) (domain.User, error) {
|
||||
return s.userStore.CreateUser(ctx, firstName, lastName, email, phoneNumber, password, role, verified)
|
||||
}
|
||||
func (s *Service) GetUserByID(ctx context.Context, id int64) (domain.User, error) {
|
||||
return s.userStore.GetUserByID(ctx, id)
|
||||
}
|
||||
func (s *Service) GetAllUsers(ctx context.Context) ([]domain.User, error) {
|
||||
return s.userStore.GetAllUsers(ctx)
|
||||
}
|
||||
func (s *Service) UpdateUser(ctx context.Context, id int64, firstName, lastName, email, phoneNumber, password, role string, verified bool) error {
|
||||
return s.userStore.UpdateUser(ctx, id, firstName, lastName, email, phoneNumber, password, role, verified)
|
||||
}
|
||||
func (s *Service) DeleteUser(ctx context.Context, id int64) error {
|
||||
return s.userStore.DeleteUser(ctx, id)
|
||||
}
|
||||
76
internal/web_server/server.go
Normal file
76
internal/web_server/server.go
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package httpserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
port int
|
||||
Router *http.ServeMux
|
||||
logger *slog.Logger
|
||||
notificationSecret string
|
||||
}
|
||||
|
||||
func NewApp(
|
||||
port int, logger *slog.Logger,
|
||||
notificationSecret string,
|
||||
|
||||
) *App {
|
||||
a := &App{
|
||||
Router: http.NewServeMux(),
|
||||
logger: logger,
|
||||
port: port,
|
||||
notificationSecret: notificationSecret,
|
||||
}
|
||||
a.initAppRoutes()
|
||||
return a
|
||||
}
|
||||
func (a *App) Run() error {
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: fmt.Sprintf(":%s", strconv.Itoa(a.port)),
|
||||
Handler: a.Router,
|
||||
IdleTimeout: time.Minute,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
shutdownError := make(chan error)
|
||||
go func() {
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
<-quit
|
||||
|
||||
a.logger.Info("shutting down server")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
shutdownError <- srv.Shutdown(ctx)
|
||||
}()
|
||||
err := srv.ListenAndServe()
|
||||
|
||||
if !errors.Is(err, http.ErrServerClosed) {
|
||||
return err
|
||||
}
|
||||
|
||||
err = <-shutdownError
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.logger.Info("server stopped")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) initAppRoutes() {
|
||||
// a.Router.HandleFunc("/users",)
|
||||
}
|
||||
32
makefile
Normal file
32
makefile
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
include .env
|
||||
.PHONY: test
|
||||
test:
|
||||
go test ./app
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
mkdir -p coverage
|
||||
go test -coverprofile=coverage.out ./internal/... ;
|
||||
go tool cover -func=coverage.out -o coverage/coverage.txt
|
||||
.PHONY: build
|
||||
build:
|
||||
go build -ldflags="-s" -o ./bin/web ./
|
||||
.PHONY: run
|
||||
run:
|
||||
echo "Running Go application"; \
|
||||
go run ./cmd/main.go
|
||||
.PHONY: air
|
||||
air:
|
||||
echo "Running air"; \
|
||||
air -c .air.toml
|
||||
.PHONY: migrations/up
|
||||
migrations/new:
|
||||
@echo 'Creating migration files for DB_URL'
|
||||
migrate create -seq -ext=.sql -dir=./db/migrations $(name)
|
||||
.PHONY: migrations/up
|
||||
migrations/up:
|
||||
@echo 'Running up migrations...'
|
||||
migrate -path ./db/migrations -database $(DB_URL) up
|
||||
|
||||
.PHONY: swagger
|
||||
swagger:
|
||||
swag init -g cmd/main.go
|
||||
18
sqlc.yaml
Normal file
18
sqlc.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
version: "2"
|
||||
sql:
|
||||
- schema: "./db/migrations/"
|
||||
queries: "./db/query/"
|
||||
engine: "postgresql"
|
||||
gen:
|
||||
go:
|
||||
package: "dbgen"
|
||||
sql_package: "pgx/v5"
|
||||
out: "./gen/db"
|
||||
emit_exported_queries: true
|
||||
emit_json_tags: false
|
||||
overrides:
|
||||
- db_type: "uuid"
|
||||
go_type: "github.com/google/uuid.UUID"
|
||||
- db_type: "uuid"
|
||||
go_type: "github.com/google/uuid.NullUUID"
|
||||
nullable: true
|
||||
Loading…
Reference in New Issue
Block a user