afro SMS and partial ArifPay Payment Gateway integrations
This commit is contained in:
parent
2bc43f5076
commit
47d70b029f
95
cmd/main.go
95
cmd/main.go
|
|
@ -11,10 +11,14 @@ import (
|
||||||
"Yimaru-Backend/internal/repository"
|
"Yimaru-Backend/internal/repository"
|
||||||
"Yimaru-Backend/internal/services/arifpay"
|
"Yimaru-Backend/internal/services/arifpay"
|
||||||
"Yimaru-Backend/internal/services/authentication"
|
"Yimaru-Backend/internal/services/authentication"
|
||||||
"Yimaru-Backend/internal/services/currency"
|
issuereporting "Yimaru-Backend/internal/services/issue_reporting"
|
||||||
|
"Yimaru-Backend/internal/services/messenger"
|
||||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||||
"Yimaru-Backend/internal/services/recommendation"
|
"Yimaru-Backend/internal/services/recommendation"
|
||||||
referralservice "Yimaru-Backend/internal/services/referal"
|
"Yimaru-Backend/internal/services/settings"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
// referralservice "Yimaru-Backend/internal/services/referal"
|
||||||
"Yimaru-Backend/internal/services/transaction"
|
"Yimaru-Backend/internal/services/transaction"
|
||||||
"Yimaru-Backend/internal/services/user"
|
"Yimaru-Backend/internal/services/user"
|
||||||
httpserver "Yimaru-Backend/internal/web_server"
|
httpserver "Yimaru-Backend/internal/web_server"
|
||||||
|
|
@ -71,14 +75,14 @@ func main() {
|
||||||
v := customvalidator.NewCustomValidator(validator.New())
|
v := customvalidator.NewCustomValidator(validator.New())
|
||||||
|
|
||||||
// Initialize services
|
// Initialize services
|
||||||
// settingRepo := repository.NewSettingStore(store)
|
settingRepo := repository.NewSettingStore(store)
|
||||||
|
|
||||||
// if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil {
|
if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil {
|
||||||
// log.Fatalf("failed to ensure settings: %v", err)
|
log.Fatalf("failed to ensure settings: %v", err)
|
||||||
// }
|
}
|
||||||
// settingSvc := settings.NewService(settingRepo)
|
settingSvc := settings.NewService(settingRepo)
|
||||||
|
|
||||||
// messengerSvc := messenger.NewService(settingSvc, cfg)
|
messengerSvc := messenger.NewService(settingSvc, cfg)
|
||||||
// statSvc := stats.NewService(
|
// statSvc := stats.NewService(
|
||||||
// repository.NewCompanyStatStore(store),
|
// repository.NewCompanyStatStore(store),
|
||||||
// repository.NewBranchStatStore(store),
|
// repository.NewBranchStatStore(store),
|
||||||
|
|
@ -92,7 +96,7 @@ func main() {
|
||||||
userSvc := user.NewService(
|
userSvc := user.NewService(
|
||||||
repository.NewUserStore(store),
|
repository.NewUserStore(store),
|
||||||
repository.NewOTPStore(store),
|
repository.NewOTPStore(store),
|
||||||
// messengerSvc,
|
messengerSvc,
|
||||||
cfg,
|
cfg,
|
||||||
)
|
)
|
||||||
// leagueSvc := league.New(repository.NewLeagueStore(store))
|
// leagueSvc := league.New(repository.NewLeagueStore(store))
|
||||||
|
|
@ -146,8 +150,8 @@ func main() {
|
||||||
// logger,
|
// logger,
|
||||||
// )
|
// )
|
||||||
|
|
||||||
branchSvc := branch.NewService(repository.NewBranchStore(store))
|
// branchSvc := branch.NewService(repository.NewBranchStore(store))
|
||||||
companySvc := company.NewService(repository.NewCompanyStore(store))
|
// companySvc := company.NewService(repository.NewCompanyStore(store))
|
||||||
|
|
||||||
// ticketSvc := ticke.NewService(
|
// ticketSvc := ticke.NewService(
|
||||||
// repository.NewTicketStore(store),
|
// repository.NewTicketStore(store),
|
||||||
|
|
@ -184,25 +188,25 @@ func main() {
|
||||||
// *userSvc,
|
// *userSvc,
|
||||||
// )
|
// )
|
||||||
|
|
||||||
bonusSvc := bonus.NewService(
|
// bonusSvc := bonus.NewService(
|
||||||
repository.NewBonusStore(store),
|
// repository.NewBonusStore(store),
|
||||||
settingSvc,
|
// settingSvc,
|
||||||
notificationSvc,
|
// notificationSvc,
|
||||||
domain.MongoDBLogger,
|
// domain.MongoDBLogger,
|
||||||
)
|
// )
|
||||||
// virtualGamesRepo := repository.NewVirtualGameRepository(store)
|
// virtualGamesRepo := repository.NewVirtualGameRepository(store)
|
||||||
recommendationRepo := repository.NewRecommendationRepository(store)
|
recommendationRepo := repository.NewRecommendationRepository(store)
|
||||||
|
|
||||||
referalSvc := referralservice.New(
|
// referalSvc := referralservice.New(
|
||||||
repository.NewReferralStore(store),
|
// repository.NewReferralStore(store),
|
||||||
*settingSvc,
|
// *settingSvc,
|
||||||
cfg,
|
// cfg,
|
||||||
logger,
|
// logger,
|
||||||
domain.MongoDBLogger,
|
// domain.MongoDBLogger,
|
||||||
)
|
// )
|
||||||
raffleSvc := raffle.NewService(
|
// raffleSvc := raffle.NewService(
|
||||||
repository.NewRaffleStore(store),
|
// repository.NewRaffleStore(store),
|
||||||
)
|
// )
|
||||||
// virtualGameSvc := virtualgameservice.New(virtualGamesRepo,, store, cfg, logger)
|
// virtualGameSvc := virtualgameservice.New(virtualGamesRepo,, store, cfg, logger)
|
||||||
// aleaService := alea.NewAleaPlayService(virtualGamesRepo,, cfg, logger)
|
// aleaService := alea.NewAleaPlayService(virtualGamesRepo,, cfg, logger)
|
||||||
// veliCLient := veli.NewClient(cfg)
|
// veliCLient := veli.NewClient(cfg)
|
||||||
|
|
@ -224,15 +228,14 @@ func main() {
|
||||||
// chapaClient,
|
// chapaClient,
|
||||||
// )
|
// )
|
||||||
|
|
||||||
currRepo := repository.NewCurrencyPostgresRepository(store)
|
// currRepo := repository.NewCurrencyPostgresRepository(store)
|
||||||
|
|
||||||
fixerFertcherSvc := currency.NewFixerFetcher(
|
// fixerFertcherSvc := currency.NewFixerFetcher(
|
||||||
cfg.FIXER_API_KEY,
|
// cfg.FIXER_API_KEY,
|
||||||
cfg.FIXER_BASE_URL,
|
// cfg.FIXER_BASE_URL,
|
||||||
)
|
// )
|
||||||
transactionSvc := transaction.NewService(
|
transactionSvc := transaction.NewService(
|
||||||
repository.NewTransactionStore(store),
|
repository.NewTransactionStore(store),
|
||||||
*branchSvc,
|
|
||||||
*userSvc,
|
*userSvc,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -263,8 +266,8 @@ func main() {
|
||||||
// go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop")
|
// go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop")
|
||||||
// go httpserver.ProcessBetCashback(context.TODO(), betSvc)
|
// go httpserver.ProcessBetCashback(context.TODO(), betSvc)
|
||||||
|
|
||||||
bankRepository := repository.NewBankRepository(store)
|
// bankRepository := repository.NewBankRepository(store)
|
||||||
instSvc := institutions.New(bankRepository)
|
// instSvc := institutions.New(bankRepository)
|
||||||
// Initialize report worker with CSV exporter
|
// Initialize report worker with CSV exporter
|
||||||
// csvExporter := infrastructure.CSVExporter{
|
// csvExporter := infrastructure.CSVExporter{
|
||||||
// ExportPath: cfg.ReportExportPath, // Make sure to add this to your config
|
// ExportPath: cfg.ReportExportPath, // Make sure to add this to your config
|
||||||
|
|
@ -297,11 +300,11 @@ func main() {
|
||||||
// 5*time.Minute,
|
// 5*time.Minute,
|
||||||
// )
|
// )
|
||||||
|
|
||||||
currSvc := currency.NewService(
|
// currSvc := currency.NewService(
|
||||||
currRepo,
|
// currRepo,
|
||||||
cfg.BASE_CURRENCY,
|
// cfg.BASE_CURRENCY,
|
||||||
fixerFertcherSvc,
|
// fixerFertcherSvc,
|
||||||
)
|
// )
|
||||||
|
|
||||||
// exchangeWorker := currency.NewExchangeRateWorker(fixerFertcherSvc, logger, cfg)
|
// exchangeWorker := currency.NewExchangeRateWorker(fixerFertcherSvc, logger, cfg)
|
||||||
// exchangeWorker.Start(context.Background())
|
// exchangeWorker.Start(context.Background())
|
||||||
|
|
@ -330,13 +333,8 @@ func main() {
|
||||||
|
|
||||||
// Initialize and start HTTP server
|
// Initialize and start HTTP server
|
||||||
app := httpserver.NewApp(
|
app := httpserver.NewApp(
|
||||||
// directdeposit,
|
|
||||||
// telebirrSvc,
|
|
||||||
arifpaySvc,
|
arifpaySvc,
|
||||||
// santimpaySvc,
|
|
||||||
issueReportingSvc,
|
issueReportingSvc,
|
||||||
instSvc,
|
|
||||||
currSvc,
|
|
||||||
cfg.Port,
|
cfg.Port,
|
||||||
v,
|
v,
|
||||||
settingSvc,
|
settingSvc,
|
||||||
|
|
@ -347,16 +345,9 @@ func main() {
|
||||||
JwtAccessExpiry: cfg.AccessExpiry,
|
JwtAccessExpiry: cfg.AccessExpiry,
|
||||||
},
|
},
|
||||||
userSvc,
|
userSvc,
|
||||||
// chapaSvc,
|
|
||||||
transactionSvc,
|
transactionSvc,
|
||||||
branchSvc,
|
|
||||||
companySvc,
|
|
||||||
notificationSvc,
|
notificationSvc,
|
||||||
referalSvc,
|
|
||||||
raffleSvc,
|
|
||||||
bonusSvc,
|
|
||||||
recommendationSvc,
|
recommendationSvc,
|
||||||
statSvc,
|
|
||||||
cfg,
|
cfg,
|
||||||
domain.MongoDBLogger,
|
domain.MongoDBLogger,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ VALUES
|
||||||
'Sarah',
|
'Sarah',
|
||||||
'Connor',
|
'Connor',
|
||||||
'SarahC',
|
'SarahC',
|
||||||
'sarah.connor@yimaru.com',
|
'yaredyemane1@gmail.com',
|
||||||
NULL,
|
NULL,
|
||||||
crypt('password@123', gen_salt('bf'))::bytea,
|
crypt('password@123', gen_salt('bf'))::bytea,
|
||||||
'SUPER_ADMIN',
|
'SUPER_ADMIN',
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
-- =========================================
|
||||||
|
-- Notifications
|
||||||
|
-- =========================================
|
||||||
|
DROP TABLE IF EXISTS global_settings;
|
||||||
|
|
||||||
-- =========================================
|
-- =========================================
|
||||||
-- Notifications
|
-- Notifications
|
||||||
-- =========================================
|
-- =========================================
|
||||||
|
|
@ -48,4 +53,4 @@ DROP TABLE IF EXISTS otps;
|
||||||
-- =========================================
|
-- =========================================
|
||||||
-- Users
|
-- Users
|
||||||
-- =========================================
|
-- =========================================
|
||||||
DROP TABLE IF EXISTS users;
|
DROP TABLE IF EXISTS users;
|
||||||
|
|
@ -192,4 +192,4 @@ CREATE TABLE IF NOT EXISTS reported_issues (
|
||||||
metadata JSONB,
|
metadata JSONB,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
DROP TABLE IF EXISTS referrals;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS referral_settings;
|
|
||||||
|
|
||||||
DROP TYPE IF EXISTS ReferralStatus;
|
|
||||||
|
|
||||||
ALTER TABLE users
|
|
||||||
DROP COLUMN referral_code;
|
|
||||||
|
|
||||||
ALTER TABLE users
|
|
||||||
DROP COLUMN referred_by;
|
|
||||||
|
|
||||||
ALTER TABLE wallet
|
|
||||||
DROP COLUMN bonus_balance;
|
|
||||||
|
|
||||||
ALTER TABLE wallet
|
|
||||||
DROP COLUMN cash_balance;
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS referral_codes (
|
|
||||||
id BIGSERIAL PRIMARY KEY,
|
|
||||||
code VARCHAR(12) NOT NULL UNIQUE,
|
|
||||||
|
|
||||||
referrer_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
||||||
|
|
||||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
||||||
max_uses INT,
|
|
||||||
current_uses INT NOT NULL DEFAULT 0,
|
|
||||||
|
|
||||||
incentive_type TEXT NOT NULL CHECK (
|
|
||||||
incentive_type IN (
|
|
||||||
'course_access',
|
|
||||||
'discount',
|
|
||||||
'certificate_unlock',
|
|
||||||
'feature_unlock'
|
|
||||||
)
|
|
||||||
),
|
|
||||||
|
|
||||||
incentive_value TEXT, -- e.g. course_id, percentage, feature_key
|
|
||||||
|
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX idx_referral_codes_referrer_id
|
|
||||||
ON referral_codes (referrer_id);
|
|
||||||
|
|
||||||
CREATE INDEX idx_referral_codes_code
|
|
||||||
ON referral_codes (code);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS user_referrals (
|
|
||||||
id BIGSERIAL PRIMARY KEY,
|
|
||||||
|
|
||||||
referrer_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
||||||
referred_user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
||||||
|
|
||||||
referral_code_id BIGINT NOT NULL REFERENCES referral_codes(id) ON DELETE CASCADE,
|
|
||||||
|
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
UNIQUE (referred_user_id),
|
|
||||||
UNIQUE (referrer_id, referred_user_id)
|
|
||||||
);
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
DROP TABLE IF EXISTS reported_issues;
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS reported_issues (
|
|
||||||
id BIGSERIAL PRIMARY KEY,
|
|
||||||
user_id BIGINT NOT NULL REFERENCES users(id),
|
|
||||||
user_role VARCHAR(255) NOT NULL,
|
|
||||||
subject TEXT NOT NULL,
|
|
||||||
description TEXT NOT NULL,
|
|
||||||
issue_type TEXT NOT NULL,
|
|
||||||
-- e.g., "deposit", "withdrawal", "bet", "technical"
|
|
||||||
status TEXT NOT NULL DEFAULT 'pending',
|
|
||||||
-- pending, in_progress, resolved, rejected
|
|
||||||
metadata JSONB,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
|
|
@ -1,14 +1,3 @@
|
||||||
-- name: GetUserByEmailPhone :one
|
|
||||||
SELECT *
|
|
||||||
FROM users
|
|
||||||
WHERE (
|
|
||||||
email = $1
|
|
||||||
OR phone_number = $2
|
|
||||||
)
|
|
||||||
AND (
|
|
||||||
organization_id = sqlc.narg('organization_id')
|
|
||||||
OR sqlc.narg('organization_id') IS NULL
|
|
||||||
);
|
|
||||||
-- name: CreateRefreshToken :exec
|
-- name: CreateRefreshToken :exec
|
||||||
INSERT INTO refresh_tokens (user_id, token, expires_at, created_at, revoked)
|
INSERT INTO refresh_tokens (user_id, token, expires_at, created_at, revoked)
|
||||||
VALUES ($1, $2, $3, $4, $5);
|
VALUES ($1, $2, $3, $4, $5);
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,37 @@
|
||||||
-- -- name: CreateReportedIssue :one
|
-- name: CreateReportedIssue :one
|
||||||
-- INSERT INTO reported_issues (
|
INSERT INTO reported_issues (
|
||||||
-- user_id,
|
user_id,
|
||||||
-- user_role,
|
user_role,
|
||||||
-- subject,
|
subject,
|
||||||
-- description,
|
description,
|
||||||
-- issue_type,
|
issue_type,
|
||||||
-- metadata
|
metadata
|
||||||
-- )
|
)
|
||||||
-- VALUES ($1, $2, $3, $4, $5, $6)
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
-- RETURNING *;
|
RETURNING *;
|
||||||
-- -- name: ListReportedIssues :many
|
-- name: ListReportedIssues :many
|
||||||
-- SELECT *
|
SELECT *
|
||||||
-- FROM reported_issues
|
FROM reported_issues
|
||||||
-- ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
-- LIMIT $1 OFFSET $2;
|
LIMIT $1 OFFSET $2;
|
||||||
-- -- name: ListReportedIssuesByUser :many
|
-- name: ListReportedIssuesByUser :many
|
||||||
-- SELECT *
|
SELECT *
|
||||||
-- FROM reported_issues
|
FROM reported_issues
|
||||||
-- WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
-- ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
-- LIMIT $2 OFFSET $3;
|
LIMIT $2 OFFSET $3;
|
||||||
-- -- name: CountReportedIssues :one
|
-- name: CountReportedIssues :one
|
||||||
-- SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
-- FROM reported_issues;
|
FROM reported_issues;
|
||||||
-- -- name: CountReportedIssuesByUser :one
|
-- name: CountReportedIssuesByUser :one
|
||||||
-- SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
-- FROM reported_issues
|
FROM reported_issues
|
||||||
-- WHERE user_id = $1;
|
WHERE user_id = $1;
|
||||||
-- -- name: UpdateReportedIssueStatus :exec
|
-- name: UpdateReportedIssueStatus :exec
|
||||||
-- UPDATE reported_issues
|
UPDATE reported_issues
|
||||||
-- SET status = $2,
|
SET status = $2,
|
||||||
-- updated_at = NOW()
|
updated_at = NOW()
|
||||||
-- WHERE id = $1;
|
WHERE id = $1;
|
||||||
-- -- name: DeleteReportedIssue :exec
|
-- name: DeleteReportedIssue :exec
|
||||||
-- DELETE FROM reported_issues
|
DELETE FROM reported_issues
|
||||||
-- WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
@ -1,99 +1,72 @@
|
||||||
-- -- name: CreateNotification :one
|
-- name: CreateNotification :one
|
||||||
-- INSERT INTO notifications (
|
INSERT INTO notifications (
|
||||||
-- id,
|
user_id,
|
||||||
-- recipient_id,
|
type,
|
||||||
-- type,
|
level,
|
||||||
-- level,
|
channel,
|
||||||
-- error_severity,
|
title,
|
||||||
-- reciever,
|
message,
|
||||||
-- is_read,
|
payload
|
||||||
-- delivery_status,
|
)
|
||||||
-- delivery_channel,
|
VALUES (
|
||||||
-- payload,
|
$1,
|
||||||
-- priority,
|
$2,
|
||||||
-- timestamp,
|
$3,
|
||||||
-- expires,
|
$4,
|
||||||
-- img,
|
$5,
|
||||||
-- metadata
|
$6,
|
||||||
-- )
|
$7
|
||||||
-- VALUES (
|
)
|
||||||
-- $1,
|
RETURNING *;
|
||||||
-- $2,
|
|
||||||
-- $3,
|
|
||||||
-- $4,
|
|
||||||
-- $5,
|
|
||||||
-- $6,
|
|
||||||
-- $7,
|
|
||||||
-- $8,
|
|
||||||
-- $9,
|
|
||||||
-- $10,
|
|
||||||
-- $11,
|
|
||||||
-- $12,
|
|
||||||
-- $13,
|
|
||||||
-- $14,
|
|
||||||
-- $15
|
|
||||||
-- )
|
|
||||||
-- RETURNING *;
|
|
||||||
-- -- name: GetNotification :one
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM notifications
|
|
||||||
-- WHERE id = $1
|
|
||||||
-- LIMIT 1;
|
|
||||||
-- -- name: GetAllNotifications :many
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM notifications
|
|
||||||
-- ORDER BY timestamp DESC
|
|
||||||
-- LIMIT $1 OFFSET $2;
|
|
||||||
-- -- name: GetTotalNotificationCount :one
|
|
||||||
-- SELECT COUNT(*)
|
|
||||||
-- FROM notifications;
|
|
||||||
-- -- name: GetUserNotifications :many
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM notifications
|
|
||||||
-- WHERE recipient_id = $1
|
|
||||||
-- ORDER BY timestamp DESC
|
|
||||||
-- LIMIT $2 OFFSET $3;
|
|
||||||
-- -- name: GetUserNotificationCount :one
|
|
||||||
-- SELECT COUNT(*)
|
|
||||||
-- FROM notifications
|
|
||||||
-- WHERE recipient_id = $1;
|
|
||||||
-- -- name: CountUnreadNotifications :one
|
|
||||||
-- SELECT count(id)
|
|
||||||
-- FROM notifications
|
|
||||||
-- WHERE recipient_id = $1
|
|
||||||
-- AND is_read = false;
|
|
||||||
-- -- name: UpdateNotificationStatus :one
|
|
||||||
-- UPDATE notifications
|
|
||||||
-- SET delivery_status = $2,
|
|
||||||
-- is_read = $3,
|
|
||||||
-- metadata = $4
|
|
||||||
-- WHERE id = $1
|
|
||||||
-- RETURNING *;
|
|
||||||
-- -- name: ListFailedNotifications :many
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM notifications
|
|
||||||
-- WHERE delivery_status = 'failed'
|
|
||||||
-- AND timestamp < NOW() - INTERVAL '1 hour'
|
|
||||||
-- ORDER BY timestamp ASC
|
|
||||||
-- LIMIT $1;
|
|
||||||
-- -- name: ListRecipientIDsByReceiver :many
|
|
||||||
-- SELECT recipient_id
|
|
||||||
-- FROM notifications
|
|
||||||
-- WHERE reciever = $1;
|
|
||||||
-- -- name: GetNotificationCounts :many
|
|
||||||
-- SELECT COUNT(*) as total,
|
|
||||||
-- COUNT(
|
|
||||||
-- CASE
|
|
||||||
-- WHEN is_read = true THEN 1
|
|
||||||
-- END
|
|
||||||
-- ) as read,
|
|
||||||
-- COUNT(
|
|
||||||
-- CASE
|
|
||||||
-- WHEN is_read = false THEN 1
|
|
||||||
-- END
|
|
||||||
-- ) as unread
|
|
||||||
-- FROM notifications;
|
|
||||||
|
|
||||||
-- -- name: DeleteOldNotifications :exec
|
-- name: GetNotification :one
|
||||||
-- DELETE FROM notifications
|
SELECT *
|
||||||
-- WHERE expires < now();
|
FROM notifications
|
||||||
|
WHERE id = $1
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: GetAllNotifications :many
|
||||||
|
SELECT *
|
||||||
|
FROM notifications
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $1 OFFSET $2;
|
||||||
|
|
||||||
|
-- name: GetTotalNotificationCount :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM notifications;
|
||||||
|
|
||||||
|
-- name: GetUserNotifications :many
|
||||||
|
SELECT *
|
||||||
|
FROM notifications
|
||||||
|
WHERE user_id = $1
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $2 OFFSET $3;
|
||||||
|
|
||||||
|
-- name: GetUserNotificationCount :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM notifications
|
||||||
|
WHERE user_id = $1;
|
||||||
|
|
||||||
|
-- name: CountUnreadNotifications :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM notifications
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND is_read = FALSE;
|
||||||
|
|
||||||
|
-- name: MarkNotificationAsRead :one
|
||||||
|
UPDATE notifications
|
||||||
|
SET is_read = TRUE,
|
||||||
|
read_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: MarkAllUserNotificationsAsRead :exec
|
||||||
|
UPDATE notifications
|
||||||
|
SET is_read = TRUE,
|
||||||
|
read_at = NOW()
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND is_read = FALSE;
|
||||||
|
|
||||||
|
-- name: DeleteUserNotifications :exec
|
||||||
|
DELETE FROM notifications
|
||||||
|
WHERE user_id = $1;
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,17 @@
|
||||||
-- -- name: InsertGlobalSetting :exec
|
-- name: InsertGlobalSetting :exec
|
||||||
-- INSERT INTO global_settings (key, value)
|
INSERT INTO global_settings (key, value)
|
||||||
-- VALUES ($1, $2) ON CONFLICT (key) DO
|
VALUES ($1, $2) ON CONFLICT (key) DO
|
||||||
-- UPDATE
|
UPDATE
|
||||||
-- SET value = EXCLUDED.value;
|
SET value = EXCLUDED.value;
|
||||||
-- -- name: GetGlobalSettings :many
|
-- name: GetGlobalSettings :many
|
||||||
-- SELECT *
|
SELECT *
|
||||||
-- FROM global_settings;
|
FROM global_settings;
|
||||||
-- -- name: GetGlobalSetting :one
|
-- name: GetGlobalSetting :one
|
||||||
-- SELECT *
|
SELECT *
|
||||||
-- FROM global_settings
|
FROM global_settings
|
||||||
-- WHERE key = $1;
|
WHERE key = $1;
|
||||||
-- -- name: UpdateGlobalSetting :exec
|
-- name: UpdateGlobalSetting :exec
|
||||||
-- UPDATE global_settings
|
UPDATE global_settings
|
||||||
-- SET value = $2,
|
SET value = $2,
|
||||||
-- updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
-- WHERE key = $1;
|
WHERE key = $1;
|
||||||
-- -- name: InsertCompanySetting :exec
|
|
||||||
-- INSERT INTO company_settings (company_id, key, value)
|
|
||||||
-- VALUES ($1, $2, $3) ON CONFLICT (company_id, key) DO
|
|
||||||
-- UPDATE
|
|
||||||
-- SET value = EXCLUDED.value;
|
|
||||||
-- -- name: GetAllCompanySettings :many
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM company_settings;
|
|
||||||
-- -- name: GetCompanySetting :many
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM company_settings
|
|
||||||
-- WHERE company_id = $1;
|
|
||||||
-- -- name: GetCompanySettingsByKey :many
|
|
||||||
-- SELECT *
|
|
||||||
-- FROM company_settings
|
|
||||||
-- WHERE key = $1;
|
|
||||||
-- -- name: GetOverrideSettings :many
|
|
||||||
-- SELECT gs.key,
|
|
||||||
-- gs.created_at,
|
|
||||||
-- gs.updated_at,
|
|
||||||
-- COALESCE(cs.value, gs.value) AS value
|
|
||||||
-- FROM global_settings gs
|
|
||||||
-- LEFT JOIN company_settings cs ON cs.key = gs.key
|
|
||||||
-- AND cs.company_id = $1;
|
|
||||||
-- -- name: DeleteCompanySetting :exec
|
|
||||||
-- DELETE FROM company_settings
|
|
||||||
-- WHERE company_id = $1
|
|
||||||
-- AND key = $2;
|
|
||||||
-- -- name: DeleteAllCompanySetting :exec
|
|
||||||
-- DELETE FROM company_settings
|
|
||||||
-- WHERE company_id = $1;
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,9 @@ SELECT *
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
-- name: GetAllUsers :many
|
-- name: GetAllUsers :many
|
||||||
SELECT id,
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
|
id,
|
||||||
first_name,
|
first_name,
|
||||||
last_name,
|
last_name,
|
||||||
nick_name,
|
nick_name,
|
||||||
|
|
@ -81,29 +83,30 @@ SELECT id,
|
||||||
suspended_at,
|
suspended_at,
|
||||||
organization_id
|
organization_id
|
||||||
FROM users
|
FROM users
|
||||||
wHERE (
|
WHERE (
|
||||||
role = $1
|
role = $1
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
organization_id = $2
|
organization_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
first_name ILIKE '%' || sqlc.narg('query') || '%'
|
first_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||||
OR last_name ILIKE '%' || sqlc.narg('query') || '%'
|
OR last_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||||
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
||||||
OR sqlc.narg('query') IS NULL
|
OR sqlc.narg('query') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > sqlc.narg('created_before')
|
created_at > sqlc.narg('created_before')
|
||||||
OR sqlc.narg('created_before') IS NULL
|
OR sqlc.narg('created_before') IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at < sqlc.narg('created_after')
|
created_at < sqlc.narg('created_after')
|
||||||
OR sqlc.narg('created_after') IS NULL
|
OR sqlc.narg('created_after') IS NULL
|
||||||
)
|
)
|
||||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
LIMIT sqlc.narg('limit')
|
||||||
|
OFFSET sqlc.narg('offset');
|
||||||
-- name: GetTotalUsers :one
|
-- name: GetTotalUsers :one
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM users
|
FROM users
|
||||||
|
|
@ -159,12 +162,6 @@ WHERE id = $4;
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET organization_id = $1
|
SET organization_id = $1
|
||||||
WHERE id = $2;
|
WHERE id = $2;
|
||||||
-- name: SuspendUser :exec
|
|
||||||
UPDATE users
|
|
||||||
SET suspended = $1,
|
|
||||||
suspended_at = $2,
|
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = $3;
|
|
||||||
-- name: DeleteUser :exec
|
-- name: DeleteUser :exec
|
||||||
DELETE FROM users
|
DELETE FROM users
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
||||||
|
|
@ -183,14 +180,16 @@ SELECT EXISTS (
|
||||||
AND users.email IS NOT NULL
|
AND users.email IS NOT NULL
|
||||||
AND users.organization_id = $2
|
AND users.organization_id = $2
|
||||||
) AS email_exists;
|
) AS email_exists;
|
||||||
-- name: GetUserByEmail :one
|
-- name: GetUserByEmailPhone :one
|
||||||
SELECT id,
|
SELECT
|
||||||
|
id,
|
||||||
first_name,
|
first_name,
|
||||||
last_name,
|
last_name,
|
||||||
nick_name,
|
nick_name,
|
||||||
email,
|
email,
|
||||||
phone_number,
|
phone_number,
|
||||||
role,
|
role,
|
||||||
|
password, -- added this line
|
||||||
age,
|
age,
|
||||||
education_level,
|
education_level,
|
||||||
country,
|
country,
|
||||||
|
|
@ -203,30 +202,12 @@ SELECT id,
|
||||||
suspended_at,
|
suspended_at,
|
||||||
organization_id
|
organization_id
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1
|
WHERE organization_id = $3
|
||||||
AND organization_id = $2;
|
AND (
|
||||||
-- name: GetUserByPhone :one
|
(email = $1 AND $1 IS NOT NULL)
|
||||||
SELECT id,
|
OR (phone_number = $2 AND $2 IS NOT NULL)
|
||||||
first_name,
|
)
|
||||||
last_name,
|
LIMIT 1;
|
||||||
nick_name,
|
|
||||||
email,
|
|
||||||
phone_number,
|
|
||||||
role,
|
|
||||||
age,
|
|
||||||
education_level,
|
|
||||||
country,
|
|
||||||
region,
|
|
||||||
email_verified,
|
|
||||||
phone_verified,
|
|
||||||
created_at,
|
|
||||||
updated_at,
|
|
||||||
suspended,
|
|
||||||
suspended_at,
|
|
||||||
organization_id
|
|
||||||
FROM users
|
|
||||||
WHERE phone_number = $1
|
|
||||||
AND organization_id = $2;
|
|
||||||
-- name: UpdatePassword :exec
|
-- name: UpdatePassword :exec
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET password = $1,
|
SET password = $1,
|
||||||
|
|
@ -239,4 +220,10 @@ WHERE (
|
||||||
SELECT users.*
|
SELECT users.*
|
||||||
FROM organizations
|
FROM organizations
|
||||||
JOIN users ON organizations.owner_id = users.id
|
JOIN users ON organizations.owner_id = users.id
|
||||||
WHERE organizations.id = $1;
|
WHERE organizations.id = $1;
|
||||||
|
-- name: SuspendUser :exec
|
||||||
|
UPDATE users
|
||||||
|
SET suspended = $1,
|
||||||
|
suspended_at = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = $3;
|
||||||
3248
docs/docs.go
3248
docs/docs.go
File diff suppressed because it is too large
Load Diff
3248
docs/swagger.json
3248
docs/swagger.json
File diff suppressed because it is too large
Load Diff
2174
docs/swagger.yaml
2174
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -75,52 +75,6 @@ func (q *Queries) GetRefreshTokenByUserID(ctx context.Context, userID int64) (Re
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetUserByEmailPhone = `-- name: GetUserByEmailPhone :one
|
|
||||||
SELECT id, first_name, last_name, nick_name, email, phone_number, role, password, age, education_level, country, region, email_verified, phone_verified, suspended, suspended_at, organization_id, created_at, updated_at
|
|
||||||
FROM users
|
|
||||||
WHERE (
|
|
||||||
email = $1
|
|
||||||
OR phone_number = $2
|
|
||||||
)
|
|
||||||
AND (
|
|
||||||
organization_id = $3
|
|
||||||
OR $3 IS NULL
|
|
||||||
)
|
|
||||||
`
|
|
||||||
|
|
||||||
type GetUserByEmailPhoneParams struct {
|
|
||||||
Email pgtype.Text `json:"email"`
|
|
||||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
|
||||||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (User, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetUserByEmailPhone, arg.Email, arg.PhoneNumber, arg.OrganizationID)
|
|
||||||
var i User
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.FirstName,
|
|
||||||
&i.LastName,
|
|
||||||
&i.NickName,
|
|
||||||
&i.Email,
|
|
||||||
&i.PhoneNumber,
|
|
||||||
&i.Role,
|
|
||||||
&i.Password,
|
|
||||||
&i.Age,
|
|
||||||
&i.EducationLevel,
|
|
||||||
&i.Country,
|
|
||||||
&i.Region,
|
|
||||||
&i.EmailVerified,
|
|
||||||
&i.PhoneVerified,
|
|
||||||
&i.Suspended,
|
|
||||||
&i.SuspendedAt,
|
|
||||||
&i.OrganizationID,
|
|
||||||
&i.CreatedAt,
|
|
||||||
&i.UpdatedAt,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const RevokeRefreshToken = `-- name: RevokeRefreshToken :exec
|
const RevokeRefreshToken = `-- name: RevokeRefreshToken :exec
|
||||||
UPDATE refresh_tokens
|
UPDATE refresh_tokens
|
||||||
SET revoked = TRUE
|
SET revoked = TRUE
|
||||||
|
|
|
||||||
197
gen/db/issue_reporting.sql.go
Normal file
197
gen/db/issue_reporting.sql.go
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: issue_reporting.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CountReportedIssues = `-- name: CountReportedIssues :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM reported_issues
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountReportedIssues(ctx context.Context) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountReportedIssues)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CountReportedIssuesByUser = `-- name: CountReportedIssuesByUser :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM reported_issues
|
||||||
|
WHERE user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountReportedIssuesByUser(ctx context.Context, userID int64) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountReportedIssuesByUser, userID)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateReportedIssue = `-- name: CreateReportedIssue :one
|
||||||
|
INSERT INTO reported_issues (
|
||||||
|
user_id,
|
||||||
|
user_role,
|
||||||
|
subject,
|
||||||
|
description,
|
||||||
|
issue_type,
|
||||||
|
metadata
|
||||||
|
)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
RETURNING id, user_id, user_role, subject, description, issue_type, status, metadata, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateReportedIssueParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
UserRole string `json:"user_role"`
|
||||||
|
Subject string `json:"subject"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
IssueType string `json:"issue_type"`
|
||||||
|
Metadata []byte `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateReportedIssue(ctx context.Context, arg CreateReportedIssueParams) (ReportedIssue, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateReportedIssue,
|
||||||
|
arg.UserID,
|
||||||
|
arg.UserRole,
|
||||||
|
arg.Subject,
|
||||||
|
arg.Description,
|
||||||
|
arg.IssueType,
|
||||||
|
arg.Metadata,
|
||||||
|
)
|
||||||
|
var i ReportedIssue
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.UserRole,
|
||||||
|
&i.Subject,
|
||||||
|
&i.Description,
|
||||||
|
&i.IssueType,
|
||||||
|
&i.Status,
|
||||||
|
&i.Metadata,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteReportedIssue = `-- name: DeleteReportedIssue :exec
|
||||||
|
DELETE FROM reported_issues
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteReportedIssue(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteReportedIssue, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListReportedIssues = `-- name: ListReportedIssues :many
|
||||||
|
SELECT id, user_id, user_role, subject, description, issue_type, status, metadata, created_at, updated_at
|
||||||
|
FROM reported_issues
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $1 OFFSET $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListReportedIssuesParams struct {
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListReportedIssues(ctx context.Context, arg ListReportedIssuesParams) ([]ReportedIssue, error) {
|
||||||
|
rows, err := q.db.Query(ctx, ListReportedIssues, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ReportedIssue
|
||||||
|
for rows.Next() {
|
||||||
|
var i ReportedIssue
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.UserRole,
|
||||||
|
&i.Subject,
|
||||||
|
&i.Description,
|
||||||
|
&i.IssueType,
|
||||||
|
&i.Status,
|
||||||
|
&i.Metadata,
|
||||||
|
&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 ListReportedIssuesByUser = `-- name: ListReportedIssuesByUser :many
|
||||||
|
SELECT id, user_id, user_role, subject, description, issue_type, status, metadata, created_at, updated_at
|
||||||
|
FROM reported_issues
|
||||||
|
WHERE user_id = $1
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $2 OFFSET $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListReportedIssuesByUserParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ListReportedIssuesByUser(ctx context.Context, arg ListReportedIssuesByUserParams) ([]ReportedIssue, error) {
|
||||||
|
rows, err := q.db.Query(ctx, ListReportedIssuesByUser, arg.UserID, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ReportedIssue
|
||||||
|
for rows.Next() {
|
||||||
|
var i ReportedIssue
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.UserRole,
|
||||||
|
&i.Subject,
|
||||||
|
&i.Description,
|
||||||
|
&i.IssueType,
|
||||||
|
&i.Status,
|
||||||
|
&i.Metadata,
|
||||||
|
&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 UpdateReportedIssueStatus = `-- name: UpdateReportedIssueStatus :exec
|
||||||
|
UPDATE reported_issues
|
||||||
|
SET status = $2,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateReportedIssueStatusParams struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateReportedIssueStatus(ctx context.Context, arg UpdateReportedIssueStatusParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateReportedIssueStatus, arg.ID, arg.Status)
|
||||||
|
return err
|
||||||
|
}
|
||||||
276
gen/db/notification.sql.go
Normal file
276
gen/db/notification.sql.go
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: notification.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CountUnreadNotifications = `-- name: CountUnreadNotifications :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM notifications
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND is_read = FALSE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) CountUnreadNotifications(ctx context.Context, userID int64) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CountUnreadNotifications, userID)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateNotification = `-- name: CreateNotification :one
|
||||||
|
INSERT INTO notifications (
|
||||||
|
user_id,
|
||||||
|
type,
|
||||||
|
level,
|
||||||
|
channel,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
payload
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
$6,
|
||||||
|
$7
|
||||||
|
)
|
||||||
|
RETURNING id, user_id, type, level, channel, title, message, payload, is_read, created_at, read_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateNotificationParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Level string `json:"level"`
|
||||||
|
Channel pgtype.Text `json:"channel"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Payload []byte `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateNotification(ctx context.Context, arg CreateNotificationParams) (Notification, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateNotification,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Type,
|
||||||
|
arg.Level,
|
||||||
|
arg.Channel,
|
||||||
|
arg.Title,
|
||||||
|
arg.Message,
|
||||||
|
arg.Payload,
|
||||||
|
)
|
||||||
|
var i Notification
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
|
&i.Level,
|
||||||
|
&i.Channel,
|
||||||
|
&i.Title,
|
||||||
|
&i.Message,
|
||||||
|
&i.Payload,
|
||||||
|
&i.IsRead,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.ReadAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteUserNotifications = `-- name: DeleteUserNotifications :exec
|
||||||
|
DELETE FROM notifications
|
||||||
|
WHERE user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteUserNotifications(ctx context.Context, userID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteUserNotifications, userID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetAllNotifications = `-- name: GetAllNotifications :many
|
||||||
|
SELECT id, user_id, type, level, channel, title, message, payload, is_read, created_at, read_at
|
||||||
|
FROM notifications
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $1 OFFSET $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetAllNotificationsParams struct {
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAllNotifications(ctx context.Context, arg GetAllNotificationsParams) ([]Notification, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllNotifications, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Notification
|
||||||
|
for rows.Next() {
|
||||||
|
var i Notification
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
|
&i.Level,
|
||||||
|
&i.Channel,
|
||||||
|
&i.Title,
|
||||||
|
&i.Message,
|
||||||
|
&i.Payload,
|
||||||
|
&i.IsRead,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.ReadAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetNotification = `-- name: GetNotification :one
|
||||||
|
SELECT id, user_id, type, level, channel, title, message, payload, is_read, created_at, read_at
|
||||||
|
FROM notifications
|
||||||
|
WHERE id = $1
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetNotification(ctx context.Context, id int64) (Notification, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetNotification, id)
|
||||||
|
var i Notification
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
|
&i.Level,
|
||||||
|
&i.Channel,
|
||||||
|
&i.Title,
|
||||||
|
&i.Message,
|
||||||
|
&i.Payload,
|
||||||
|
&i.IsRead,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.ReadAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetTotalNotificationCount = `-- name: GetTotalNotificationCount :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM notifications
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetTotalNotificationCount(ctx context.Context) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetTotalNotificationCount)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetUserNotificationCount = `-- name: GetUserNotificationCount :one
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM notifications
|
||||||
|
WHERE user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUserNotificationCount(ctx context.Context, userID int64) (int64, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetUserNotificationCount, userID)
|
||||||
|
var count int64
|
||||||
|
err := row.Scan(&count)
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetUserNotifications = `-- name: GetUserNotifications :many
|
||||||
|
SELECT id, user_id, type, level, channel, title, message, payload, is_read, created_at, read_at
|
||||||
|
FROM notifications
|
||||||
|
WHERE user_id = $1
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $2 OFFSET $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetUserNotificationsParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetUserNotifications(ctx context.Context, arg GetUserNotificationsParams) ([]Notification, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetUserNotifications, arg.UserID, arg.Limit, arg.Offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Notification
|
||||||
|
for rows.Next() {
|
||||||
|
var i Notification
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
|
&i.Level,
|
||||||
|
&i.Channel,
|
||||||
|
&i.Title,
|
||||||
|
&i.Message,
|
||||||
|
&i.Payload,
|
||||||
|
&i.IsRead,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.ReadAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const MarkAllUserNotificationsAsRead = `-- name: MarkAllUserNotificationsAsRead :exec
|
||||||
|
UPDATE notifications
|
||||||
|
SET is_read = TRUE,
|
||||||
|
read_at = NOW()
|
||||||
|
WHERE user_id = $1
|
||||||
|
AND is_read = FALSE
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) MarkAllUserNotificationsAsRead(ctx context.Context, userID int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, MarkAllUserNotificationsAsRead, userID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const MarkNotificationAsRead = `-- name: MarkNotificationAsRead :one
|
||||||
|
UPDATE notifications
|
||||||
|
SET is_read = TRUE,
|
||||||
|
read_at = NOW()
|
||||||
|
WHERE id = $1
|
||||||
|
RETURNING id, user_id, type, level, channel, title, message, payload, is_read, created_at, read_at
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) MarkNotificationAsRead(ctx context.Context, id int64) (Notification, error) {
|
||||||
|
row := q.db.QueryRow(ctx, MarkNotificationAsRead, id)
|
||||||
|
var i Notification
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
|
&i.Level,
|
||||||
|
&i.Channel,
|
||||||
|
&i.Title,
|
||||||
|
&i.Message,
|
||||||
|
&i.Payload,
|
||||||
|
&i.IsRead,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.ReadAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
92
gen/db/settings.sql.go
Normal file
92
gen/db/settings.sql.go
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: settings.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GetGlobalSetting = `-- name: GetGlobalSetting :one
|
||||||
|
SELECT key, value, created_at, updated_at
|
||||||
|
FROM global_settings
|
||||||
|
WHERE key = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetGlobalSetting(ctx context.Context, key string) (GlobalSetting, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetGlobalSetting, key)
|
||||||
|
var i GlobalSetting
|
||||||
|
err := row.Scan(
|
||||||
|
&i.Key,
|
||||||
|
&i.Value,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const GetGlobalSettings = `-- name: GetGlobalSettings :many
|
||||||
|
SELECT key, value, created_at, updated_at
|
||||||
|
FROM global_settings
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetGlobalSettings(ctx context.Context) ([]GlobalSetting, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetGlobalSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GlobalSetting
|
||||||
|
for rows.Next() {
|
||||||
|
var i GlobalSetting
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.Key,
|
||||||
|
&i.Value,
|
||||||
|
&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 InsertGlobalSetting = `-- name: InsertGlobalSetting :exec
|
||||||
|
INSERT INTO global_settings (key, value)
|
||||||
|
VALUES ($1, $2) ON CONFLICT (key) DO
|
||||||
|
UPDATE
|
||||||
|
SET value = EXCLUDED.value
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertGlobalSettingParams struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertGlobalSetting(ctx context.Context, arg InsertGlobalSettingParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, InsertGlobalSetting, arg.Key, arg.Value)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateGlobalSetting = `-- name: UpdateGlobalSetting :exec
|
||||||
|
UPDATE global_settings
|
||||||
|
SET value = $2,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE key = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateGlobalSettingParams struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateGlobalSetting(ctx context.Context, arg UpdateGlobalSettingParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateGlobalSetting, arg.Key, arg.Value)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -205,7 +205,9 @@ func (q *Queries) DeleteUser(ctx context.Context, id int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllUsers = `-- name: GetAllUsers :many
|
const GetAllUsers = `-- name: GetAllUsers :many
|
||||||
SELECT id,
|
SELECT
|
||||||
|
COUNT(*) OVER () AS total_count,
|
||||||
|
id,
|
||||||
first_name,
|
first_name,
|
||||||
last_name,
|
last_name,
|
||||||
nick_name,
|
nick_name,
|
||||||
|
|
@ -224,29 +226,30 @@ SELECT id,
|
||||||
suspended_at,
|
suspended_at,
|
||||||
organization_id
|
organization_id
|
||||||
FROM users
|
FROM users
|
||||||
wHERE (
|
WHERE (
|
||||||
role = $1
|
role = $1
|
||||||
OR $1 IS NULL
|
OR $1 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
organization_id = $2
|
organization_id = $2
|
||||||
OR $2 IS NULL
|
OR $2 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
first_name ILIKE '%' || $3 || '%'
|
first_name ILIKE '%' || $3 || '%'
|
||||||
OR last_name ILIKE '%' || $3 || '%'
|
OR last_name ILIKE '%' || $3 || '%'
|
||||||
OR phone_number ILIKE '%' || $3 || '%'
|
OR phone_number ILIKE '%' || $3 || '%'
|
||||||
OR $3 IS NULL
|
OR $3 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at > $4
|
created_at > $4
|
||||||
OR $4 IS NULL
|
OR $4 IS NULL
|
||||||
)
|
)
|
||||||
AND (
|
AND (
|
||||||
created_at < $5
|
created_at < $5
|
||||||
OR $5 IS NULL
|
OR $5 IS NULL
|
||||||
)
|
)
|
||||||
LIMIT $7 OFFSET $6
|
LIMIT $7
|
||||||
|
OFFSET $6
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetAllUsersParams struct {
|
type GetAllUsersParams struct {
|
||||||
|
|
@ -260,6 +263,7 @@ type GetAllUsersParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetAllUsersRow struct {
|
type GetAllUsersRow struct {
|
||||||
|
TotalCount int64 `json:"total_count"`
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
LastName string `json:"last_name"`
|
LastName string `json:"last_name"`
|
||||||
|
|
@ -298,6 +302,7 @@ func (q *Queries) GetAllUsers(ctx context.Context, arg GetAllUsersParams) ([]Get
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i GetAllUsersRow
|
var i GetAllUsersRow
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
|
&i.TotalCount,
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.FirstName,
|
&i.FirstName,
|
||||||
&i.LastName,
|
&i.LastName,
|
||||||
|
|
@ -386,14 +391,16 @@ func (q *Queries) GetTotalUsers(ctx context.Context, arg GetTotalUsersParams) (i
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetUserByEmail = `-- name: GetUserByEmail :one
|
const GetUserByEmailPhone = `-- name: GetUserByEmailPhone :one
|
||||||
SELECT id,
|
SELECT
|
||||||
|
id,
|
||||||
first_name,
|
first_name,
|
||||||
last_name,
|
last_name,
|
||||||
nick_name,
|
nick_name,
|
||||||
email,
|
email,
|
||||||
phone_number,
|
phone_number,
|
||||||
role,
|
role,
|
||||||
|
password, -- added this line
|
||||||
age,
|
age,
|
||||||
education_level,
|
education_level,
|
||||||
country,
|
country,
|
||||||
|
|
@ -406,16 +413,21 @@ SELECT id,
|
||||||
suspended_at,
|
suspended_at,
|
||||||
organization_id
|
organization_id
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1
|
WHERE organization_id = $3
|
||||||
AND organization_id = $2
|
AND (
|
||||||
|
(email = $1 AND $1 IS NOT NULL)
|
||||||
|
OR (phone_number = $2 AND $2 IS NOT NULL)
|
||||||
|
)
|
||||||
|
LIMIT 1
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetUserByEmailParams struct {
|
type GetUserByEmailPhoneParams struct {
|
||||||
Email pgtype.Text `json:"email"`
|
Email pgtype.Text `json:"email"`
|
||||||
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
OrganizationID pgtype.Int8 `json:"organization_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetUserByEmailRow struct {
|
type GetUserByEmailPhoneRow struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
LastName string `json:"last_name"`
|
LastName string `json:"last_name"`
|
||||||
|
|
@ -423,6 +435,7 @@ type GetUserByEmailRow struct {
|
||||||
Email pgtype.Text `json:"email"`
|
Email pgtype.Text `json:"email"`
|
||||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
|
Password []byte `json:"password"`
|
||||||
Age pgtype.Int4 `json:"age"`
|
Age pgtype.Int4 `json:"age"`
|
||||||
EducationLevel pgtype.Text `json:"education_level"`
|
EducationLevel pgtype.Text `json:"education_level"`
|
||||||
Country pgtype.Text `json:"country"`
|
Country pgtype.Text `json:"country"`
|
||||||
|
|
@ -436,9 +449,9 @@ type GetUserByEmailRow struct {
|
||||||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
OrganizationID pgtype.Int8 `json:"organization_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams) (GetUserByEmailRow, error) {
|
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (GetUserByEmailPhoneRow, error) {
|
||||||
row := q.db.QueryRow(ctx, GetUserByEmail, arg.Email, arg.OrganizationID)
|
row := q.db.QueryRow(ctx, GetUserByEmailPhone, arg.Email, arg.PhoneNumber, arg.OrganizationID)
|
||||||
var i GetUserByEmailRow
|
var i GetUserByEmailPhoneRow
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.FirstName,
|
&i.FirstName,
|
||||||
|
|
@ -447,6 +460,7 @@ func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams)
|
||||||
&i.Email,
|
&i.Email,
|
||||||
&i.PhoneNumber,
|
&i.PhoneNumber,
|
||||||
&i.Role,
|
&i.Role,
|
||||||
|
&i.Password,
|
||||||
&i.Age,
|
&i.Age,
|
||||||
&i.EducationLevel,
|
&i.EducationLevel,
|
||||||
&i.Country,
|
&i.Country,
|
||||||
|
|
@ -495,82 +509,6 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetUserByPhone = `-- name: GetUserByPhone :one
|
|
||||||
SELECT id,
|
|
||||||
first_name,
|
|
||||||
last_name,
|
|
||||||
nick_name,
|
|
||||||
email,
|
|
||||||
phone_number,
|
|
||||||
role,
|
|
||||||
age,
|
|
||||||
education_level,
|
|
||||||
country,
|
|
||||||
region,
|
|
||||||
email_verified,
|
|
||||||
phone_verified,
|
|
||||||
created_at,
|
|
||||||
updated_at,
|
|
||||||
suspended,
|
|
||||||
suspended_at,
|
|
||||||
organization_id
|
|
||||||
FROM users
|
|
||||||
WHERE phone_number = $1
|
|
||||||
AND organization_id = $2
|
|
||||||
`
|
|
||||||
|
|
||||||
type GetUserByPhoneParams struct {
|
|
||||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
|
||||||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetUserByPhoneRow struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
NickName pgtype.Text `json:"nick_name"`
|
|
||||||
Email pgtype.Text `json:"email"`
|
|
||||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
|
||||||
Role string `json:"role"`
|
|
||||||
Age pgtype.Int4 `json:"age"`
|
|
||||||
EducationLevel pgtype.Text `json:"education_level"`
|
|
||||||
Country pgtype.Text `json:"country"`
|
|
||||||
Region pgtype.Text `json:"region"`
|
|
||||||
EmailVerified bool `json:"email_verified"`
|
|
||||||
PhoneVerified bool `json:"phone_verified"`
|
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
|
||||||
Suspended bool `json:"suspended"`
|
|
||||||
SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
|
|
||||||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) GetUserByPhone(ctx context.Context, arg GetUserByPhoneParams) (GetUserByPhoneRow, error) {
|
|
||||||
row := q.db.QueryRow(ctx, GetUserByPhone, arg.PhoneNumber, arg.OrganizationID)
|
|
||||||
var i GetUserByPhoneRow
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.FirstName,
|
|
||||||
&i.LastName,
|
|
||||||
&i.NickName,
|
|
||||||
&i.Email,
|
|
||||||
&i.PhoneNumber,
|
|
||||||
&i.Role,
|
|
||||||
&i.Age,
|
|
||||||
&i.EducationLevel,
|
|
||||||
&i.Country,
|
|
||||||
&i.Region,
|
|
||||||
&i.EmailVerified,
|
|
||||||
&i.PhoneVerified,
|
|
||||||
&i.CreatedAt,
|
|
||||||
&i.UpdatedAt,
|
|
||||||
&i.Suspended,
|
|
||||||
&i.SuspendedAt,
|
|
||||||
&i.OrganizationID,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const SearchUserByNameOrPhone = `-- name: SearchUserByNameOrPhone :many
|
const SearchUserByNameOrPhone = `-- name: SearchUserByNameOrPhone :many
|
||||||
SELECT id,
|
SELECT id,
|
||||||
first_name,
|
first_name,
|
||||||
|
|
|
||||||
9
go.mod
9
go.mod
|
|
@ -6,7 +6,6 @@ toolchain go1.24.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/amanuelabay/afrosms-go v1.0.6
|
github.com/amanuelabay/afrosms-go v1.0.6
|
||||||
github.com/go-co-op/gocron v1.37.0
|
|
||||||
github.com/go-playground/validator/v10 v10.29.0
|
github.com/go-playground/validator/v10 v10.29.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/resend/resend-go/v2 v2.28.0
|
github.com/resend/resend-go/v2 v2.28.0
|
||||||
|
|
@ -16,6 +15,8 @@ require (
|
||||||
golang.org/x/crypto v0.45.0
|
golang.org/x/crypto v0.45.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||||
|
|
@ -31,7 +32,7 @@ require (
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/jackc/pgio v1.0.0 // indirect
|
// github.com/jackc/pgio v1.0.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
|
|
@ -40,14 +41,12 @@ require (
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
github.com/mailru/easyjson v0.7.6 // indirect
|
||||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
|
||||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
|
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||||
golang.org/x/mod v0.29.0 // indirect
|
golang.org/x/mod v0.29.0 // indirect
|
||||||
|
|
@ -66,7 +65,7 @@ require (
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/jackc/pgtype v1.14.4
|
// github.com/jackc/pgtype v1.14.4
|
||||||
github.com/jackc/pgx/v5 v5.7.6
|
github.com/jackc/pgx/v5 v5.7.6
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
|
|
||||||
152
go.sum
152
go.sum
|
|
@ -1,7 +1,6 @@
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
|
||||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
|
|
@ -21,11 +20,7 @@ github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2N
|
||||||
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
|
@ -33,10 +28,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||||
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
|
|
||||||
github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY=
|
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
|
@ -55,11 +46,9 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
|
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
|
||||||
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
|
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/gofiber/fiber/v2 v2.32.0/go.mod h1:CMy5ZLiXkn6qwthrl03YMyW1NLfj0rhxz2LKl4t7ZTY=
|
github.com/gofiber/fiber/v2 v2.32.0/go.mod h1:CMy5ZLiXkn6qwthrl03YMyW1NLfj0rhxz2LKl4t7ZTY=
|
||||||
github.com/gofiber/fiber/v2 v2.52.10 h1:jRHROi2BuNti6NYXmZ6gbNSfT3zj/8c0xy94GOU5elY=
|
github.com/gofiber/fiber/v2 v2.52.10 h1:jRHROi2BuNti6NYXmZ6gbNSfT3zj/8c0xy94GOU5elY=
|
||||||
github.com/gofiber/fiber/v2 v2.52.10/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
github.com/gofiber/fiber/v2 v2.52.10/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||||
|
|
@ -69,60 +58,17 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
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/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
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/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
|
||||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
|
||||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
|
||||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
|
||||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
|
||||||
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
|
||||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
|
||||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
|
||||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
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/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
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/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
|
||||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
|
||||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
|
||||||
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
|
||||||
github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8=
|
|
||||||
github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
|
||||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
|
||||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
|
||||||
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
|
||||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
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/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
|
@ -130,42 +76,28 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|
||||||
github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275 h1:IZycmTpoUtQK3PD60UYBwjaCUHUP7cML494ao9/O8+Q=
|
github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275 h1:IZycmTpoUtQK3PD60UYBwjaCUHUP7cML494ao9/O8+Q=
|
||||||
github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275/go.mod h1:zt6UU74K6Z6oMOYJbJzYpYucqdcQwSMPBEdSvGiaUMw=
|
github.com/localtunnel/go-localtunnel v0.0.0-20170326223115-8a804488f275/go.mod h1:zt6UU74K6Z6oMOYJbJzYpYucqdcQwSMPBEdSvGiaUMw=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
|
@ -180,7 +112,6 @@ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6
|
||||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
|
@ -189,40 +120,21 @@ github.com/resend/resend-go/v2 v2.28.0 h1:ttM1/VZR4fApBv3xI1TneSKi1pbfFsVrq7fXFl
|
||||||
github.com/resend/resend-go/v2 v2.28.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ=
|
github.com/resend/resend-go/v2 v2.28.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
|
||||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
|
||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
|
@ -257,57 +169,29 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
|
||||||
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
|
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
|
||||||
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|
||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
|
||||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
|
||||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
|
||||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
|
||||||
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
|
|
||||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||||
|
|
@ -315,27 +199,15 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
@ -348,48 +220,26 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
@ -399,7 +249,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|
@ -408,4 +257,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,7 @@ func (c *Config) loadEnv() error {
|
||||||
|
|
||||||
c.AFRO_SMS_SENDER_NAME = os.Getenv("AFRO_SMS_SENDER_NAME")
|
c.AFRO_SMS_SENDER_NAME = os.Getenv("AFRO_SMS_SENDER_NAME")
|
||||||
if c.AFRO_SMS_SENDER_NAME == "" {
|
if c.AFRO_SMS_SENDER_NAME == "" {
|
||||||
c.AFRO_SMS_SENDER_NAME = "FortuneBet"
|
c.AFRO_SMS_SENDER_NAME = "Yimaru"
|
||||||
}
|
}
|
||||||
|
|
||||||
c.AFRO_SMS_RECEIVER_PHONE_NUMBER = os.Getenv("AFRO_SMS_RECEIVER_PHONE_NUMBER")
|
c.AFRO_SMS_RECEIVER_PHONE_NUMBER = os.Getenv("AFRO_SMS_RECEIVER_PHONE_NUMBER")
|
||||||
|
|
|
||||||
|
|
@ -1,390 +0,0 @@
|
||||||
package domain
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInsufficientBalance = errors.New("insufficient balance")
|
|
||||||
ErrInvalidWithdrawalAmount = errors.New("invalid withdrawal amount")
|
|
||||||
ErrWithdrawalNotFound = errors.New("withdrawal not found")
|
|
||||||
ErrPaymentNotFound = errors.New("payment not found")
|
|
||||||
ErrPaymentAlreadyExists = errors.New("payment with this reference already exists")
|
|
||||||
ErrInvalidPaymentAmount = errors.New("invalid payment amount")
|
|
||||||
)
|
|
||||||
|
|
||||||
type PaymentStatus string
|
|
||||||
|
|
||||||
type WithdrawalStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
WithdrawalStatusSuccessful WithdrawalStatus = "success"
|
|
||||||
WithdrawalStatusPending WithdrawalStatus = "pending"
|
|
||||||
WithdrawalStatusProcessing WithdrawalStatus = "processing"
|
|
||||||
WithdrawalStatusCompleted WithdrawalStatus = "completed"
|
|
||||||
WithdrawalStatusFailed WithdrawalStatus = "failed"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PaymentStatusSuccessful PaymentStatus = "success"
|
|
||||||
PaymentStatusPending PaymentStatus = "pending"
|
|
||||||
PaymentStatusCompleted PaymentStatus = "completed"
|
|
||||||
PaymentStatusFailed PaymentStatus = "failed"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChapaInitDepositRequest struct {
|
|
||||||
Amount Currency `json:"amount"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
TxRef string `json:"tx_ref"`
|
|
||||||
CallbackURL string `json:"callback_url"`
|
|
||||||
ReturnURL string `json:"return_url"`
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
// PhoneNumber string `json:"phone_number"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaDepositRequestPayload struct {
|
|
||||||
Amount float64 `json:"amount" validate:"required,gt=0"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaWebhookPayload struct {
|
|
||||||
TxRef string `json:"trx_ref"`
|
|
||||||
Amount Currency `json:"amount"`
|
|
||||||
// Currency string `json:"currency"`
|
|
||||||
Status PaymentStatus `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaPaymentWebhookRequest struct {
|
|
||||||
TxRef string `json:"trx_ref"`
|
|
||||||
RefId string `json:"ref_id"`
|
|
||||||
Status PaymentStatus `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PaymentResponse contains the response from payment initialization
|
|
||||||
type ChapaDepositResponse struct {
|
|
||||||
CheckoutURL string
|
|
||||||
Reference string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PaymentVerification contains payment verification details
|
|
||||||
type ChapaDepositVerification struct {
|
|
||||||
Status PaymentStatus
|
|
||||||
Amount Currency
|
|
||||||
Currency string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaPaymentVerificationResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data struct {
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Charge float64 `json:"charge"`
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Reference string `json:"reference"`
|
|
||||||
TxRef string `json:"tx_ref"`
|
|
||||||
Customization struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Logo interface{} `json:"logo"`
|
|
||||||
} `json:"customization"`
|
|
||||||
Meta interface{} `json:"meta"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaTransferVerificationResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data struct {
|
|
||||||
AccountName string `json:"account_name"`
|
|
||||||
AccountNumber string `json:"account_number"`
|
|
||||||
Mobile interface{} `json:"mobile"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Charge float64 `json:"charge"`
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
TransferMethod string `json:"transfer_method"`
|
|
||||||
Narration interface{} `json:"narration"`
|
|
||||||
ChapaTransferID string `json:"chapa_transfer_id"`
|
|
||||||
BankCode int `json:"bank_code"`
|
|
||||||
BankName string `json:"bank_name"`
|
|
||||||
CrossPartyReference interface{} `json:"cross_party_reference"`
|
|
||||||
IPAddress string `json:"ip_address"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
TxRef string `json:"tx_ref"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaAllTransactionsResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data struct {
|
|
||||||
Transactions []struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
RefID string `json:"ref_id"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Amount string `json:"amount"`
|
|
||||||
Charge string `json:"charge"`
|
|
||||||
TransID *string `json:"trans_id"`
|
|
||||||
PaymentMethod string `json:"payment_method"`
|
|
||||||
Customer struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
Email *string `json:"email"`
|
|
||||||
FirstName *string `json:"first_name"`
|
|
||||||
LastName *string `json:"last_name"`
|
|
||||||
Mobile *string `json:"mobile"`
|
|
||||||
} `json:"customer"`
|
|
||||||
} `json:"transactions"`
|
|
||||||
Pagination struct {
|
|
||||||
PerPage int `json:"per_page"`
|
|
||||||
CurrentPage int `json:"current_page"`
|
|
||||||
FirstPageURL string `json:"first_page_url"`
|
|
||||||
NextPageURL *string `json:"next_page_url"`
|
|
||||||
PrevPageURL *string `json:"prev_page_url"`
|
|
||||||
} `json:"pagination"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaTransactionEvent struct {
|
|
||||||
Item int64 `json:"item"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaTransaction struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
RefID string `json:"ref_id"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Amount string `json:"amount"`
|
|
||||||
Charge string `json:"charge"`
|
|
||||||
TransID *string `json:"trans_id"`
|
|
||||||
PaymentMethod string `json:"payment_method"`
|
|
||||||
Customer ChapaCustomer `json:"customer"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaCustomer struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
Email *string `json:"email"`
|
|
||||||
FirstName *string `json:"first_name"`
|
|
||||||
LastName *string `json:"last_name"`
|
|
||||||
Mobile *string `json:"mobile"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// type Bank struct {
|
|
||||||
// ID int `json:"id"`
|
|
||||||
// Slug string `json:"slug"`
|
|
||||||
// Swift string `json:"swift"`
|
|
||||||
// Name string `json:"name"`
|
|
||||||
// AcctLength int `json:"acct_length"`
|
|
||||||
// CountryID int `json:"country_id"`
|
|
||||||
// IsMobileMoney int `json:"is_mobilemoney"` // nullable
|
|
||||||
// IsActive int `json:"is_active"`
|
|
||||||
// IsRTGS int `json:"is_rtgs"`
|
|
||||||
// Active int `json:"active"`
|
|
||||||
// Is24Hrs int `json:"is_24hrs"` // nullable
|
|
||||||
// CreatedAt time.Time `json:"created_at"`
|
|
||||||
// UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
// Currency string `json:"currency"`
|
|
||||||
// BankLogo string `json:"bank_logo"` // URL or base64
|
|
||||||
// }
|
|
||||||
|
|
||||||
type SwapResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
RefID string `json:"ref_id"`
|
|
||||||
FromCurrency string `json:"from_currency"`
|
|
||||||
ToCurrency string `json:"to_currency"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
ExchangedAmount float64 `json:"exchanged_amount"`
|
|
||||||
Charge float64 `json:"charge"`
|
|
||||||
Rate float64 `json:"rate"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaTransfersListResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Meta struct {
|
|
||||||
CurrentPage int `json:"current_page"`
|
|
||||||
FirstPageURL string `json:"first_page_url"`
|
|
||||||
LastPage int `json:"last_page"`
|
|
||||||
LastPageURL string `json:"last_page_url"`
|
|
||||||
NextPageURL string `json:"next_page_url"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
PerPage int `json:"per_page"`
|
|
||||||
PrevPageURL interface{} `json:"prev_page_url"`
|
|
||||||
To int `json:"to"`
|
|
||||||
Total int `json:"total"`
|
|
||||||
Error []interface{} `json:"error"`
|
|
||||||
} `json:"meta"`
|
|
||||||
Data []struct {
|
|
||||||
AccountName string `json:"account_name"`
|
|
||||||
AccountNumber string `json:"account_number"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Charge float64 `json:"charge"`
|
|
||||||
TransferType string `json:"transfer_type"`
|
|
||||||
ChapaReference string `json:"chapa_reference"`
|
|
||||||
BankCode int `json:"bank_code"`
|
|
||||||
BankName string `json:"bank_name"`
|
|
||||||
BankReference interface{} `json:"bank_reference"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Reference interface{} `json:"reference"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BankResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data []BankData `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BankData struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Slug string `json:"slug"`
|
|
||||||
Swift string `json:"swift"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
AcctLength int `json:"acct_length"`
|
|
||||||
CountryID int `json:"country_id"`
|
|
||||||
IsMobileMoney int `json:"is_mobilemoney"` // nullable
|
|
||||||
IsActive int `json:"is_active"`
|
|
||||||
IsRTGS int `json:"is_rtgs"`
|
|
||||||
Active int `json:"active"`
|
|
||||||
Is24Hrs int `json:"is_24hrs"` // nullable
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaWithdrawal struct {
|
|
||||||
ID string
|
|
||||||
UserID int64
|
|
||||||
Amount Currency
|
|
||||||
AccountNumber string
|
|
||||||
BankCode string
|
|
||||||
Status WithdrawalStatus
|
|
||||||
Reference string
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaWithdrawalRequest struct {
|
|
||||||
AccountName string `json:"account_name"`
|
|
||||||
AccountNumber string `json:"account_number"`
|
|
||||||
Amount string `json:"amount"` // string because Chapa API uses string for monetary values
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Reference string `json:"reference"`
|
|
||||||
BankCode int `json:"bank_code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// type ChapaWithdrawalRequest struct {
|
|
||||||
// AccountName string `json:"account_name"`
|
|
||||||
// AccountNumber string `json:"account_number"`
|
|
||||||
// Amount Currency `json:"amount"`
|
|
||||||
// Currency string `json:"currency"`
|
|
||||||
// BeneficiaryName string `json:"beneficiary_name"`
|
|
||||||
// BankCode string `json:"bank_code"`
|
|
||||||
// PhoneNumber string `json:"phone_number"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
type ChapaWithdrawalResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data string `json:"data"` // Accepts string instead of struct
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaTransactionType struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaWebhookTransfer struct {
|
|
||||||
Event string `json:"event"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
AccountName string `json:"account_name"`
|
|
||||||
AccountNumber string `json:"account_number"`
|
|
||||||
BankID int `json:"bank_id"`
|
|
||||||
BankName string `json:"bank_name"`
|
|
||||||
Amount string `json:"amount"`
|
|
||||||
Charge string `json:"charge"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Reference string `json:"reference"`
|
|
||||||
ChapaReference string `json:"chapa_reference"`
|
|
||||||
BankReference string `json:"bank_reference"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaWebhookPayment struct {
|
|
||||||
Event string `json:"event"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
Email *string `json:"email,omitempty"`
|
|
||||||
Mobile string `json:"mobile"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Amount string `json:"amount"`
|
|
||||||
Charge string `json:"charge"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
Reference string `json:"reference"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
TxRef string `json:"tx_ref"`
|
|
||||||
PaymentMethod string `json:"payment_method"`
|
|
||||||
Customization ChapaWebhookCustomization `json:"customization"`
|
|
||||||
Meta interface{} `json:"meta"` // may vary in structure, so kept flexible
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaWebhookCustomization struct {
|
|
||||||
Title *string `json:"title,omitempty"`
|
|
||||||
Description *string `json:"description,omitempty"`
|
|
||||||
Logo *string `json:"logo,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Balance struct {
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
AvailableBalance float64 `json:"available_balance"`
|
|
||||||
LedgerBalance float64 `json:"ledger_balance"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SwapRequest struct {
|
|
||||||
From string `json:"from"`
|
|
||||||
To string `json:"to"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChapaCancelResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
TxRef string `json:"tx_ref"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package domain
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type DirectDepositStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
DepositStatusPending DirectDepositStatus = "PENDING"
|
|
||||||
DepositStatusCompleted DirectDepositStatus = "COMPLETED"
|
|
||||||
DepositStatusRejected DirectDepositStatus = "REJECTED"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DirectDeposit struct {
|
|
||||||
ID int
|
|
||||||
CustomerID int
|
|
||||||
WalletID int
|
|
||||||
BankName string
|
|
||||||
AccountNumber string
|
|
||||||
AccountHolder string
|
|
||||||
Amount float64
|
|
||||||
ReferenceNumber string
|
|
||||||
TransferScreenshot string
|
|
||||||
Status string
|
|
||||||
CreatedAt time.Time
|
|
||||||
ApprovedBy *int
|
|
||||||
ApprovedAt *time.Time
|
|
||||||
RejectionReason *string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateDirectDeposit struct {
|
|
||||||
CustomerID int
|
|
||||||
WalletID int
|
|
||||||
BankName string
|
|
||||||
AccountNumber string
|
|
||||||
AccountHolder string
|
|
||||||
Amount float64
|
|
||||||
ReferenceNumber string
|
|
||||||
TransferScreenshot string
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package domain
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Bank struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Slug string `json:"slug"`
|
|
||||||
Swift string `json:"swift"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
AcctLength int `json:"acct_length"`
|
|
||||||
CountryID int `json:"country_id"`
|
|
||||||
IsMobileMoney int `json:"is_mobilemoney"` // nullable
|
|
||||||
IsActive int `json:"is_active"`
|
|
||||||
IsRTGS int `json:"is_rtgs"`
|
|
||||||
Active int `json:"active"`
|
|
||||||
Is24Hrs int `json:"is_24hrs"` // nullable
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
BankLogo string `json:"bank_logo"` // URL or base64
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Data interface{} `json:"data"` // Changed to interface{} for flexibility
|
|
||||||
Pagination *Pagination `json:"pagination,omitempty"` // Made pointer and optional
|
|
||||||
}
|
|
||||||
|
|
@ -123,11 +123,11 @@ func ReceiverFromRole(role Role) NotificationRecieverSide {
|
||||||
switch role {
|
switch role {
|
||||||
case RoleAdmin:
|
case RoleAdmin:
|
||||||
return NotificationRecieverSideAdmin
|
return NotificationRecieverSideAdmin
|
||||||
case RoleCashier:
|
case RoleSuperAdmin:
|
||||||
return NotificationRecieverSideCashier
|
return NotificationRecieverSideAdmin
|
||||||
case RoleBranchManager:
|
case RoleStudent:
|
||||||
return NotificationRecieverSideBranchManager
|
return NotificationRecieverSideCustomer
|
||||||
case RoleCustomer:
|
case RoleInstructor:
|
||||||
return NotificationRecieverSideCustomer
|
return NotificationRecieverSideCustomer
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
|
|
|
||||||
|
|
@ -1,186 +0,0 @@
|
||||||
package domain
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "time"
|
|
||||||
|
|
||||||
// dbgen "Yimaru-Backend/gen/db"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type ReferralCode struct {
|
|
||||||
// ID int64
|
|
||||||
// ReferrerID int64
|
|
||||||
// ReferralCode string
|
|
||||||
// CompanyID int64
|
|
||||||
// NumberOfReferrals int64
|
|
||||||
// RewardAmount Currency
|
|
||||||
// CreatedAt time.Time
|
|
||||||
// UpdatedAt time.Time
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ReferralCodeRes struct {
|
|
||||||
// ID int64 `json:"id"`
|
|
||||||
// ReferrerID int64 `json:"referrer_id"`
|
|
||||||
// ReferralCode string `json:"referral_code"`
|
|
||||||
// CompanyID int64 `json:"company_id"`
|
|
||||||
// NumberOfReferrals int64 `json:"number_of_referrals"`
|
|
||||||
// RewardAmount float32 `json:"reward_amount"`
|
|
||||||
// CreatedAt time.Time `json:"created_at"`
|
|
||||||
// UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type CreateReferralCode struct {
|
|
||||||
// ReferrerID int64
|
|
||||||
// ReferralCode string
|
|
||||||
// CompanyID int64
|
|
||||||
// NumberOfReferrals int64
|
|
||||||
// RewardAmount Currency
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type UserReferral struct {
|
|
||||||
// ReferredID int64
|
|
||||||
// ReferralCodeID int64
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type CreateUserReferrals struct {
|
|
||||||
// ReferredID int64
|
|
||||||
// ReferralCodeID int64
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type UpdateReferralCode struct {
|
|
||||||
// ID int64
|
|
||||||
// IsActive bool
|
|
||||||
// ReferralCode string
|
|
||||||
// RewardAmount Currency
|
|
||||||
// NumberOfReferrals int64
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ReferralStats struct {
|
|
||||||
// TotalReferrals int64
|
|
||||||
// TotalRewardEarned Currency
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type ReferralStatsRes struct {
|
|
||||||
// TotalReferrals int64 `json:"total_referrals"`
|
|
||||||
// TotalRewardEarned float32 `json:"total_reward_earned"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // type ReferralSettings struct {
|
|
||||||
// // ID int64
|
|
||||||
// // ReferralRewardAmount float64
|
|
||||||
// // CashbackPercentage float64
|
|
||||||
// // BetReferralBonusPercentage float64
|
|
||||||
// // MaxReferrals int32
|
|
||||||
// // ExpiresAfterDays int32
|
|
||||||
// // UpdatedBy string
|
|
||||||
// // CreatedAt time.Time
|
|
||||||
// // UpdatedAt time.Time
|
|
||||||
// // Version int32
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // type ReferralSettingsReq struct {
|
|
||||||
// // ReferralRewardAmount float64 `json:"referral_reward_amount" validate:"required"`
|
|
||||||
// // CashbackPercentage float64 `json:"cashback_percentage" validate:"required"`
|
|
||||||
// // MaxReferrals int32 `json:"max_referrals" validate:"required"`
|
|
||||||
// // UpdatedBy string `json:"updated_by" validate:"required"`
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// func ConvertCreateReferralCode(code CreateReferralCode) dbgen.CreateReferralCodeParams {
|
|
||||||
// return dbgen.CreateReferralCodeParams{
|
|
||||||
// ReferralCode: code.ReferralCode,
|
|
||||||
// ReferrerID: code.ReferrerID,
|
|
||||||
// CompanyID: code.CompanyID,
|
|
||||||
// NumberOfReferrals: code.NumberOfReferrals,
|
|
||||||
// RewardAmount: int64(code.RewardAmount),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertDBReferralCode(code dbgen.ReferralCode) ReferralCode {
|
|
||||||
// return ReferralCode{
|
|
||||||
// ID: code.ID,
|
|
||||||
// ReferrerID: code.ReferrerID,
|
|
||||||
// ReferralCode: code.ReferralCode,
|
|
||||||
// NumberOfReferrals: code.NumberOfReferrals,
|
|
||||||
// RewardAmount: Currency(code.RewardAmount),
|
|
||||||
// CompanyID: code.CompanyID,
|
|
||||||
// CreatedAt: code.CreatedAt.Time,
|
|
||||||
// UpdatedAt: code.UpdatedAt.Time,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertDBReferralCodes(codes []dbgen.ReferralCode) []ReferralCode {
|
|
||||||
// result := make([]ReferralCode, len(codes))
|
|
||||||
// for i, code := range codes {
|
|
||||||
// result[i] = ConvertDBReferralCode(code)
|
|
||||||
// }
|
|
||||||
// return result
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertCreateUserReferral(referral CreateUserReferrals) dbgen.CreateUserReferralParams {
|
|
||||||
// return dbgen.CreateUserReferralParams{
|
|
||||||
// ReferredID: referral.ReferredID,
|
|
||||||
// ReferralCodeID: referral.ReferralCodeID,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertDBUserReferral(referral dbgen.UserReferral) UserReferral {
|
|
||||||
// return UserReferral{
|
|
||||||
// ReferredID: referral.ReferredID,
|
|
||||||
// ReferralCodeID: referral.ReferralCodeID,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertDBUserReferrals(referrals []dbgen.UserReferral) []UserReferral {
|
|
||||||
// result := make([]UserReferral, len(referrals))
|
|
||||||
// for i, referral := range referrals {
|
|
||||||
// result[i] = ConvertDBUserReferral(referral)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return result
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertUpdateReferralCode(referralCode UpdateReferralCode) dbgen.UpdateReferralCodeParams {
|
|
||||||
// return dbgen.UpdateReferralCodeParams{
|
|
||||||
// ID: referralCode.ID,
|
|
||||||
// IsActive: referralCode.IsActive,
|
|
||||||
// ReferralCode: referralCode.ReferralCode,
|
|
||||||
// NumberOfReferrals: referralCode.NumberOfReferrals,
|
|
||||||
// RewardAmount: int64(referralCode.RewardAmount),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertDBReferralStats(stats dbgen.GetReferralStatsRow) ReferralStats {
|
|
||||||
// return ReferralStats{
|
|
||||||
// TotalReferrals: stats.TotalReferrals,
|
|
||||||
// TotalRewardEarned: Currency(stats.TotalRewardEarned),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertReferralCodeRes(referral ReferralCode) ReferralCodeRes {
|
|
||||||
// return ReferralCodeRes{
|
|
||||||
// ID: referral.ID,
|
|
||||||
// ReferrerID: referral.ReferrerID,
|
|
||||||
// ReferralCode: referral.ReferralCode,
|
|
||||||
// CompanyID: referral.CompanyID,
|
|
||||||
// NumberOfReferrals: referral.NumberOfReferrals,
|
|
||||||
// RewardAmount: referral.RewardAmount.Float32(),
|
|
||||||
// CreatedAt: referral.CreatedAt,
|
|
||||||
// UpdatedAt: referral.UpdatedAt,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertReferralCodeResList(referrals []ReferralCode) []ReferralCodeRes {
|
|
||||||
// result := make([]ReferralCodeRes, len(referrals))
|
|
||||||
|
|
||||||
// for i, referral := range referrals {
|
|
||||||
// result[i] = ConvertReferralCodeRes(referral)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return result
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertReferralStatsRes(stats ReferralStats) ReferralStatsRes {
|
|
||||||
// return ReferralStatsRes{
|
|
||||||
// TotalReferrals: stats.TotalReferrals,
|
|
||||||
// TotalRewardEarned: stats.TotalRewardEarned.Float32(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
@ -3,19 +3,22 @@ package domain
|
||||||
type Role string
|
type Role string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RoleSuperAdmin Role = "super_admin"
|
RoleSuperAdmin Role = "super_admin"
|
||||||
RoleAdmin Role = "admin"
|
RoleAdmin Role = "admin"
|
||||||
RoleBranchManager Role = "branch_manager"
|
RoleStudent Role = "student"
|
||||||
RoleCustomer Role = "customer"
|
RoleInstructor Role = "instructor"
|
||||||
RoleCashier Role = "cashier"
|
RoleSupport Role = "support"
|
||||||
RoleTransactionApprover Role = "transaction_approver"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r Role) IsValid() bool {
|
func (r Role) IsValid() bool {
|
||||||
switch r {
|
switch r {
|
||||||
case RoleSuperAdmin, RoleAdmin, RoleBranchManager, RoleCustomer, RoleCashier, RoleTransactionApprover:
|
case RoleSuperAdmin, RoleAdmin, RoleStudent, RoleInstructor, RoleSupport:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r Role) Value() string {
|
||||||
|
return string(r)
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,46 +1,44 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
// import (
|
import (
|
||||||
// "time"
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// dbgen "Yimaru-Backend/gen/db"
|
type Setting struct {
|
||||||
// )
|
Key string
|
||||||
|
Value string
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
// type Setting struct {
|
type CreateSetting struct {
|
||||||
// Key string
|
Key string
|
||||||
// Value string
|
Value string
|
||||||
// UpdatedAt time.Time
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// type CreateSetting struct {
|
type SettingRes struct {
|
||||||
// Key string
|
Key string `json:"key"`
|
||||||
// Value string
|
Value string `json:"value"`
|
||||||
// }
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
type CompanySetting struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
CompanyID int64
|
||||||
|
UpdatedAt time.Time
|
||||||
|
CreatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
// type SettingRes struct {
|
type CompanySettingRes struct {
|
||||||
// Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
// Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
// UpdatedAt time.Time `json:"updated_at"`
|
CompanyID int64 `json:"company_id"`
|
||||||
// }
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
// type CompanySetting struct {
|
CreatedAt time.Time `json:"created_at"`
|
||||||
// Key string
|
}
|
||||||
// Value string
|
|
||||||
// CompanyID int64
|
|
||||||
// UpdatedAt time.Time
|
|
||||||
// CreatedAt time.Time
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type CompanySettingRes struct {
|
func ConvertSetting(setting Setting) SettingRes {
|
||||||
// Key string `json:"key"`
|
return SettingRes(setting)
|
||||||
// Value string `json:"value"`
|
}
|
||||||
// CompanyID int64 `json:"company_id"`
|
|
||||||
// UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
// CreatedAt time.Time `json:"created_at"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertSetting(setting Setting) SettingRes {
|
|
||||||
// return SettingRes(setting)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
|
// func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
|
||||||
// return CompanySetting{
|
// return CompanySetting{
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import (
|
||||||
|
|
||||||
type NotificationStore interface {
|
type NotificationStore interface {
|
||||||
GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error)
|
GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error)
|
||||||
ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) // New method
|
// ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) // New method
|
||||||
CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error)
|
CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error)
|
||||||
GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error)
|
GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error)
|
||||||
GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error)
|
// GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error)
|
||||||
|
|
||||||
CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error)
|
CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error)
|
||||||
UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error)
|
// UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error)
|
||||||
ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error)
|
// ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error)
|
||||||
DeleteOldNotifications(ctx context.Context) error
|
// DeleteOldNotifications(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
package ports
|
package ports
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SettingStore interface {
|
type SettingStore interface {
|
||||||
// GetGlobalSettingList(ctx context.Context) (domain.SettingList, error)
|
GetGlobalSettingList(ctx context.Context) (domain.SettingList, error)
|
||||||
// GetGlobalSettings(ctx context.Context) ([]domain.Setting, error)
|
GetGlobalSettings(ctx context.Context) ([]domain.Setting, error)
|
||||||
// GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error)
|
GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error)
|
||||||
// UpdateGlobalSetting(ctx context.Context, key, value string) error
|
UpdateGlobalSetting(ctx context.Context, key, value string) error
|
||||||
// UpdateGlobalSettingList(ctx context.Context, settingList domain.ValidSettingList) error
|
UpdateGlobalSettingList(ctx context.Context, settingList domain.ValidSettingList) error
|
||||||
|
|
||||||
// InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error
|
// InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error
|
||||||
// InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error
|
// InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error
|
||||||
|
|
@ -18,6 +19,6 @@ type SettingStore interface {
|
||||||
// GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error)
|
// GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error)
|
||||||
// GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error)
|
// GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error)
|
||||||
// DeleteCompanySetting(ctx context.Context, companyID int64, key string) error
|
// DeleteCompanySetting(ctx context.Context, companyID int64, key string) error
|
||||||
DeleteAllCompanySetting(ctx context.Context, companyID int64) error
|
// DeleteAllCompanySetting(ctx context.Context, companyID int64) error
|
||||||
EnsureAllSettingsExist(ctx context.Context) error
|
EnsureAllSettingsExist(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,34 +2,53 @@ package ports
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"Yimaru-Backend/internal/domain"
|
"Yimaru-Backend/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserStore interface {
|
type UserStore interface {
|
||||||
CreateUser(ctx context.Context, user domain.User, usedOtpId int64, is_company bool) (domain.User, error)
|
CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error)
|
||||||
CreateUserWithoutOtp(ctx context.Context, user domain.User, is_company bool) (domain.User, error)
|
CreateUserWithoutOtp(ctx context.Context, user domain.User) (domain.User, error)
|
||||||
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||||
GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error)
|
GetAllUsers(
|
||||||
// GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([]domain.GetCashier, int64, error)
|
ctx context.Context,
|
||||||
// GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error)
|
role *string,
|
||||||
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
|
organizationID *int64,
|
||||||
GetAdminByCompanyID(ctx context.Context, companyID int64) (domain.User, error)
|
query *string,
|
||||||
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
createdBefore, createdAfter *time.Time,
|
||||||
UpdateUserCompany(ctx context.Context, id int64, companyID int64) error
|
limit, offset int32,
|
||||||
|
) ([]domain.User, int64, error)
|
||||||
|
GetTotalUsers(ctx context.Context, role *string, organizationID *int64) (int64, error)
|
||||||
|
SearchUserByNameOrPhone(ctx context.Context, search string, organizationID *int64, role *string) ([]domain.User, error)
|
||||||
|
UpdateUser(ctx context.Context, user domain.User) error
|
||||||
|
UpdateUserOrganization(ctx context.Context, userID, organizationID int64) error
|
||||||
|
SuspendUser(ctx context.Context, userID int64, suspended bool, suspendedAt time.Time) error
|
||||||
|
DeleteUser(ctx context.Context, userID int64) error
|
||||||
|
CheckPhoneEmailExist(ctx context.Context, phone, email string, organizationID domain.ValidInt64) (phoneExists, emailExists bool, err error)
|
||||||
|
GetUserByEmailPhone(
|
||||||
|
ctx context.Context,
|
||||||
|
email string,
|
||||||
|
phone string,
|
||||||
|
organizationID domain.ValidInt64,
|
||||||
|
) (domain.User, error)
|
||||||
|
UpdatePassword(ctx context.Context, password, email, phone string, organizationID int64, updatedAt time.Time) error
|
||||||
|
GetOwnerByOrganizationID(ctx context.Context, organizationID int64) (domain.User, error)
|
||||||
UpdateUserSuspend(ctx context.Context, id int64, status bool) error
|
UpdateUserSuspend(ctx context.Context, id int64, status bool) error
|
||||||
DeleteUser(ctx context.Context, id int64) error
|
|
||||||
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string, companyID domain.ValidInt64) (bool, bool, error)
|
// UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
||||||
GetUserByEmail(ctx context.Context, email string, companyID domain.ValidInt64) (domain.User, error)
|
// UpdateUserSuspend(ctx context.Context, id int64, status bool) error
|
||||||
GetUserByPhone(ctx context.Context, phoneNum string, companyID domain.ValidInt64) (domain.User, error)
|
// DeleteUser(ctx context.Context, id int64) error
|
||||||
SearchUserByNameOrPhone(ctx context.Context, searchString string, role *domain.Role, companyID domain.ValidInt64) ([]domain.User, error)
|
// CheckPhoneEmailExist(ctx context.Context, phoneNum, email string, companyID domain.ValidInt64) (bool, bool, error)
|
||||||
UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64, companyId int64) error
|
// GetUserByEmail(ctx context.Context, email string, companyID domain.ValidInt64) (domain.User, error)
|
||||||
GetUserByEmailPhone(ctx context.Context, email, phone string, companyID domain.ValidInt64) (domain.User, error)
|
// GetUserByPhone(ctx context.Context, phoneNum string, companyID domain.ValidInt64) (domain.User, error)
|
||||||
|
// SearchUserByNameOrPhone(ctx context.Context, searchString string, role *domain.Role, companyID domain.ValidInt64) ([]domain.User, error)
|
||||||
GetCustomerCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
// UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64, companyId int64) error
|
||||||
GetCustomerDetails(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.CustomerDetail, error)
|
// GetUserByEmailPhone(ctx context.Context, email, phone string, companyID domain.ValidInt64) (domain.User, error)
|
||||||
GetBranchCustomerCounts(ctx context.Context, filter domain.ReportFilter) (map[int64]int64, error)
|
|
||||||
GetRoleCounts(ctx context.Context, role string, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
// GetCustomerCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
||||||
|
// GetCustomerDetails(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.CustomerDetail, error)
|
||||||
|
// GetRoleCounts(ctx context.Context, role string, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
||||||
}
|
}
|
||||||
type SmsGateway interface {
|
type SmsGateway interface {
|
||||||
SendSMSOTP(ctx context.Context, phoneNumber, otp string) error
|
SendSMSOTP(ctx context.Context, phoneNumber, otp string) error
|
||||||
|
|
|
||||||
64
internal/repository/issue_reporting.go
Normal file
64
internal/repository/issue_reporting.go
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReportedIssueRepository interface {
|
||||||
|
CreateReportedIssue(ctx context.Context, arg dbgen.CreateReportedIssueParams) (dbgen.ReportedIssue, error)
|
||||||
|
ListReportedIssues(ctx context.Context, limit, offset int32) ([]dbgen.ReportedIssue, error)
|
||||||
|
ListReportedIssuesByUser(ctx context.Context, userID int64, limit, offset int32) ([]dbgen.ReportedIssue, error)
|
||||||
|
CountReportedIssues(ctx context.Context) (int64, error)
|
||||||
|
CountReportedIssuesByUser(ctx context.Context, userID int64) (int64, error)
|
||||||
|
UpdateReportedIssueStatus(ctx context.Context, id int64, status string) error
|
||||||
|
DeleteReportedIssue(ctx context.Context, id int64) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportedIssueRepo struct {
|
||||||
|
store *Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReportedIssueRepository(store *Store) ReportedIssueRepository {
|
||||||
|
return &ReportedIssueRepo{store: store}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) CreateReportedIssue(ctx context.Context, arg dbgen.CreateReportedIssueParams) (dbgen.ReportedIssue, error) {
|
||||||
|
return s.store.queries.CreateReportedIssue(ctx, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) ListReportedIssues(ctx context.Context, limit, offset int32) ([]dbgen.ReportedIssue, error) {
|
||||||
|
params := dbgen.ListReportedIssuesParams{
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
return s.store.queries.ListReportedIssues(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) ListReportedIssuesByUser(ctx context.Context, userID int64, limit, offset int32) ([]dbgen.ReportedIssue, error) {
|
||||||
|
params := dbgen.ListReportedIssuesByUserParams{
|
||||||
|
UserID: userID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
return s.store.queries.ListReportedIssuesByUser(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) CountReportedIssues(ctx context.Context) (int64, error) {
|
||||||
|
return s.store.queries.CountReportedIssues(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) CountReportedIssuesByUser(ctx context.Context, userID int64) (int64, error) {
|
||||||
|
return s.store.queries.CountReportedIssuesByUser(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) UpdateReportedIssueStatus(ctx context.Context, id int64, status string) error {
|
||||||
|
return s.store.queries.UpdateReportedIssueStatus(ctx, dbgen.UpdateReportedIssueStatusParams{
|
||||||
|
ID: id,
|
||||||
|
Status: status,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ReportedIssueRepo) DeleteReportedIssue(ctx context.Context, id int64) error {
|
||||||
|
return s.store.queries.DeleteReportedIssue(ctx, id)
|
||||||
|
}
|
||||||
|
|
@ -1,356 +1,192 @@
|
||||||
package repository
|
package repository
|
||||||
|
|
||||||
// import (
|
import (
|
||||||
// "context"
|
"context"
|
||||||
// "encoding/json"
|
"encoding/json"
|
||||||
// "fmt"
|
|
||||||
|
|
||||||
// dbgen "Yimaru-Backend/gen/db"
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
// "Yimaru-Backend/internal/domain"
|
"Yimaru-Backend/internal/domain"
|
||||||
// "Yimaru-Backend/internal/ports"
|
"Yimaru-Backend/internal/ports"
|
||||||
// "github.com/jackc/pgx/v5/pgtype"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func NewNotificationStore(s *Store) ports.NotificationStore { return s }
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
// func (r *Store) CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error) {
|
func NewNotificationStore(s *Store) ports.NotificationStore {
|
||||||
// var errorSeverity pgtype.Text
|
return s
|
||||||
// if notification.ErrorSeverity != "" {
|
}
|
||||||
// errorSeverity.String = string(notification.ErrorSeverity)
|
|
||||||
// errorSeverity.Valid = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var deliveryChannel pgtype.Text
|
/* =========================
|
||||||
// if notification.DeliveryChannel != "" {
|
Create
|
||||||
// deliveryChannel.String = string(notification.DeliveryChannel)
|
========================= */
|
||||||
// deliveryChannel.Valid = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var priority pgtype.Int4
|
func (r *Store) CreateNotification(
|
||||||
// if notification.Priority != 0 {
|
ctx context.Context,
|
||||||
// priority.Int32 = int32(notification.Priority)
|
n *domain.Notification,
|
||||||
// priority.Valid = true
|
) (*domain.Notification, error) {
|
||||||
// }
|
|
||||||
|
|
||||||
// params := dbgen.CreateNotificationParams{
|
params := dbgen.CreateNotificationParams{
|
||||||
// ID: notification.ID,
|
UserID: n.RecipientID,
|
||||||
// RecipientID: notification.RecipientID,
|
Type: string(n.Type),
|
||||||
// Type: string(notification.Type),
|
Level: string(n.Level),
|
||||||
// Level: string(notification.Level),
|
Channel: pgtype.Text{String: string(n.DeliveryChannel)},
|
||||||
// ErrorSeverity: errorSeverity,
|
Title: n.Payload.Headline,
|
||||||
// Reciever: string(notification.Reciever),
|
Message: n.Payload.Message,
|
||||||
// IsRead: notification.IsRead,
|
Payload: marshalPayload(n.Payload),
|
||||||
// DeliveryStatus: string(notification.DeliveryStatus),
|
}
|
||||||
// DeliveryChannel: deliveryChannel,
|
|
||||||
// Payload: marshalPayload(notification.Payload),
|
|
||||||
// Priority: priority,
|
|
||||||
// Timestamp: pgtype.Timestamptz{Time: notification.Timestamp, Valid: true},
|
|
||||||
// Expires: pgtype.Timestamptz{Time: notification.Expires, Valid: true},
|
|
||||||
// Img: pgtype.Text{String: notification.Image, Valid: notification.Image != ""},
|
|
||||||
// Metadata: notification.Metadata,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// dbNotification, err := r.queries.CreateNotification(ctx, params)
|
dbNotif, err := r.queries.CreateNotification(ctx, params)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return nil, err
|
return nil, err
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return r.mapDBToDomain(&dbNotification), nil
|
return mapDBToDomain(&dbNotif), nil
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func (r *Store) UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error) {
|
/* =========================
|
||||||
// params := dbgen.UpdateNotificationStatusParams{
|
Read
|
||||||
// ID: id,
|
========================= */
|
||||||
// DeliveryStatus: status,
|
|
||||||
// IsRead: isRead,
|
|
||||||
// Metadata: metadata,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// dbNotification, err := r.queries.UpdateNotificationStatus(ctx, params)
|
func (r *Store) GetUserNotifications(
|
||||||
// if err != nil {
|
ctx context.Context,
|
||||||
// return nil, err
|
userID int64,
|
||||||
// }
|
limit, offset int,
|
||||||
|
) ([]domain.Notification, int64, error) {
|
||||||
|
|
||||||
// return r.mapDBToDomain(&dbNotification), nil
|
params := dbgen.GetUserNotificationsParams{
|
||||||
// }
|
UserID: userID,
|
||||||
|
Limit: int32(limit),
|
||||||
|
Offset: int32(offset),
|
||||||
|
}
|
||||||
|
|
||||||
// func (r *Store) GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error) {
|
rows, err := r.queries.GetUserNotifications(ctx, params)
|
||||||
// params := dbgen.GetUserNotificationsParams{
|
if err != nil {
|
||||||
// RecipientID: recipientID,
|
return nil, 0, err
|
||||||
// Limit: int32(limit),
|
}
|
||||||
// Offset: int32(offset),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// dbNotifications, err := r.queries.GetUserNotifications(ctx, params)
|
total, err := r.queries.GetUserNotificationCount(ctx, userID)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return nil, 0, err
|
return nil, 0, err
|
||||||
// }
|
}
|
||||||
|
|
||||||
// total, err := r.queries.GetUserNotificationCount(ctx, recipientID)
|
result := make([]domain.Notification, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
result = append(result, *mapDBToDomain(&row))
|
||||||
|
}
|
||||||
|
|
||||||
// if err != nil {
|
return result, total, nil
|
||||||
// return nil, 0, err
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
func (r *Store) GetAllNotifications(
|
||||||
// for _, dbNotif := range dbNotifications {
|
ctx context.Context,
|
||||||
// domainNotif := r.mapDBToDomain(&dbNotif)
|
limit, offset int,
|
||||||
// result = append(result, *domainNotif)
|
) ([]domain.Notification, error) {
|
||||||
// }
|
|
||||||
|
|
||||||
// return result, total, nil
|
rows, err := r.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
|
||||||
// }
|
Limit: int32(limit),
|
||||||
|
Offset: int32(offset),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// func (r *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
|
result := make([]domain.Notification, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
result = append(result, *mapDBToDomain(&row))
|
||||||
|
}
|
||||||
|
|
||||||
// dbNotifications, err := r.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
|
return result, nil
|
||||||
// Limit: int32(limit),
|
}
|
||||||
// Offset: int32(offset),
|
|
||||||
// })
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
func (r *Store) CountUnreadNotifications(
|
||||||
// for _, dbNotif := range dbNotifications {
|
ctx context.Context,
|
||||||
// domainNotif := r.mapDBToDomain(&dbNotif)
|
userID int64,
|
||||||
// result = append(result, *domainNotif)
|
) (int64, error) {
|
||||||
// }
|
return r.queries.CountUnreadNotifications(ctx, userID)
|
||||||
// return result, nil
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// func (r *Store) ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error) {
|
/* =========================
|
||||||
// dbNotifications, err := r.queries.ListFailedNotifications(ctx, int32(limit))
|
Update
|
||||||
// if err != nil {
|
========================= */
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var result []domain.Notification
|
func (r *Store) MarkNotificationAsRead(
|
||||||
// for _, dbNotif := range dbNotifications {
|
ctx context.Context,
|
||||||
// domainNotif := r.mapDBToDomain(&dbNotif)
|
id int64,
|
||||||
// result = append(result, *domainNotif)
|
) (*domain.Notification, error) {
|
||||||
// }
|
|
||||||
|
|
||||||
// return result, nil
|
dbNotif, err := r.queries.MarkNotificationAsRead(ctx, id)
|
||||||
// }
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// func (r *Store) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
return mapDBToDomain(&dbNotif), nil
|
||||||
// return r.queries.ListRecipientIDsByReceiver(ctx, string(receiver))
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// func (s *Store) DeleteOldNotifications(ctx context.Context) error {
|
func (r *Store) MarkAllUserNotificationsAsRead(
|
||||||
// return s.queries.DeleteOldNotifications(ctx)
|
ctx context.Context,
|
||||||
// }
|
userID int64,
|
||||||
|
) error {
|
||||||
|
return r.queries.MarkAllUserNotificationsAsRead(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
// func (r *Store) mapDBToDomain(dbNotif *dbgen.Notification) *domain.Notification {
|
/* =========================
|
||||||
// var errorSeverity domain.NotificationErrorSeverity
|
Delete
|
||||||
// if dbNotif.ErrorSeverity.Valid {
|
========================= */
|
||||||
// errorSeverity = domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String)
|
|
||||||
|
|
||||||
// } else {
|
func (r *Store) DeleteUserNotifications(
|
||||||
// errorSeverity = ""
|
ctx context.Context,
|
||||||
// }
|
userID int64,
|
||||||
|
) error {
|
||||||
|
return r.queries.DeleteUserNotifications(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
// var deliveryChannel domain.DeliveryChannel
|
/* =========================
|
||||||
// if dbNotif.DeliveryChannel.Valid {
|
Mapping
|
||||||
// deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String)
|
========================= */
|
||||||
// } else {
|
|
||||||
// deliveryChannel = ""
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var priority int
|
func mapDBToDomain(db *dbgen.Notification) *domain.Notification {
|
||||||
// if dbNotif.Priority.Valid {
|
payload, err := unmarshalPayload(db.Payload)
|
||||||
// priority = int(dbNotif.Priority.Int32)
|
if err != nil {
|
||||||
// }
|
payload = domain.NotificationPayload{}
|
||||||
|
}
|
||||||
|
|
||||||
// payload, err := unmarshalPayload(dbNotif.Payload)
|
var channel domain.DeliveryChannel
|
||||||
// if err != nil {
|
if db.Channel.Valid {
|
||||||
// payload = domain.NotificationPayload{}
|
channel = domain.DeliveryChannel(db.Channel.String)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return &domain.Notification{
|
return &domain.Notification{
|
||||||
// ID: dbNotif.ID,
|
ID: string(db.ID),
|
||||||
// RecipientID: dbNotif.RecipientID,
|
RecipientID: db.UserID,
|
||||||
// Type: domain.NotificationType(dbNotif.Type),
|
Type: domain.NotificationType(db.Type),
|
||||||
// Level: domain.NotificationLevel(dbNotif.Level),
|
Level: domain.NotificationLevel(db.Level),
|
||||||
// ErrorSeverity: errorSeverity,
|
DeliveryChannel: channel,
|
||||||
// Reciever: domain.NotificationRecieverSide(dbNotif.Reciever),
|
DeliveryStatus: "PENDING",
|
||||||
// IsRead: dbNotif.IsRead,
|
Payload: domain.NotificationPayload{
|
||||||
// DeliveryStatus: domain.NotificationDeliveryStatus(dbNotif.DeliveryStatus),
|
Headline: payload.Headline,
|
||||||
// DeliveryChannel: deliveryChannel,
|
Message: payload.Message,
|
||||||
// Payload: payload,
|
},
|
||||||
// Priority: priority,
|
IsRead: db.IsRead,
|
||||||
// Timestamp: dbNotif.Timestamp.Time,
|
Timestamp: db.CreatedAt.Time,
|
||||||
// Expires: dbNotif.Expires.Time,
|
// ReadAt: db.ReadAt.Time,
|
||||||
// Image: dbNotif.Img.String,
|
}
|
||||||
// Metadata: dbNotif.Metadata,
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func marshalPayload(payload domain.NotificationPayload) []byte {
|
/* =========================
|
||||||
// data, _ := json.Marshal(payload)
|
JSON Helpers
|
||||||
// return data
|
========================= */
|
||||||
// }
|
|
||||||
|
|
||||||
// func unmarshalPayload(data []byte) (domain.NotificationPayload, error) {
|
func marshalPayload(p domain.NotificationPayload) []byte {
|
||||||
// var payload domain.NotificationPayload
|
b, _ := json.Marshal(p)
|
||||||
// if err := json.Unmarshal(data, &payload); err != nil {
|
return b
|
||||||
// return domain.NotificationPayload{}, err
|
}
|
||||||
// }
|
|
||||||
// return payload, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (r *Store) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
func unmarshalPayload(b []byte) (domain.NotificationPayload, error) {
|
||||||
// return r.queries.CountUnreadNotifications(ctx, recipient_id)
|
var p domain.NotificationPayload
|
||||||
// }
|
if len(b) == 0 {
|
||||||
|
return p, nil
|
||||||
// func (r *Store) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error) {
|
}
|
||||||
// rows, err := r.queries.GetNotificationCounts(ctx)
|
if err := json.Unmarshal(b, &p); err != nil {
|
||||||
// if err != nil {
|
return p, err
|
||||||
// return 0, 0, 0, fmt.Errorf("failed to get notification counts: %w", err)
|
}
|
||||||
// }
|
return p, nil
|
||||||
|
}
|
||||||
// // var total, read, unread int64
|
|
||||||
// for _, row := range rows {
|
|
||||||
// total += row.Total
|
|
||||||
// read += row.Read
|
|
||||||
// unread += row.Unread
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return total, read, unread, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (s *Store) GetMostActiveNotificationRecipients(ctx context.Context, filter domain.ReportFilter, limit int) ([]domain.ActiveNotificationRecipient, error) {
|
|
||||||
// query := `SELECT
|
|
||||||
// n.recipient_id,
|
|
||||||
// u.first_name || ' ' || u.last_name as recipient_name,
|
|
||||||
// COUNT(*) as notification_count,
|
|
||||||
// MAX(n.timestamp) as last_notification_time
|
|
||||||
// FROM notifications n
|
|
||||||
// JOIN users u ON n.recipient_id = u.id
|
|
||||||
// WHERE n.timestamp BETWEEN $1 AND $2
|
|
||||||
// GROUP BY n.recipient_id, u.first_name, u.last_name
|
|
||||||
// ORDER BY notification_count DESC
|
|
||||||
// LIMIT $3`
|
|
||||||
|
|
||||||
// var recipients []domain.ActiveNotificationRecipient
|
|
||||||
// rows, err := s.conn.Query(ctx, query, filter.StartTime.Value, filter.EndTime.Value, limit)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, fmt.Errorf("failed to get active notification recipients: %w", err)
|
|
||||||
// }
|
|
||||||
// defer rows.Close()
|
|
||||||
|
|
||||||
// for rows.Next() {
|
|
||||||
// var r domain.ActiveNotificationRecipient
|
|
||||||
// if err := rows.Scan(&r.RecipientID, &r.RecipientName, &r.NotificationCount, &r.LastNotificationTime); err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// recipients = append(recipients, r)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return recipients, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // GetNotificationDeliveryStats
|
|
||||||
// func (s *Store) GetNotificationDeliveryStats(ctx context.Context, filter domain.ReportFilter) (domain.NotificationDeliveryStats, error) {
|
|
||||||
// query := `SELECT
|
|
||||||
// COUNT(*) as total_sent,
|
|
||||||
// COUNT(CASE WHEN delivery_status = 'failed' THEN 1 END) as failed_deliveries,
|
|
||||||
// (COUNT(CASE WHEN delivery_status = 'sent' THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0)) as success_rate,
|
|
||||||
// MODE() WITHIN GROUP (ORDER BY delivery_channel) as most_used_channel
|
|
||||||
// FROM notifications
|
|
||||||
// WHERE timestamp BETWEEN $1 AND $2`
|
|
||||||
|
|
||||||
// var stats domain.NotificationDeliveryStats
|
|
||||||
// row := s.conn.QueryRow(ctx, query, filter.StartTime.Value, filter.EndTime.Value)
|
|
||||||
// err := row.Scan(&stats.TotalSent, &stats.FailedDeliveries, &stats.SuccessRate, &stats.MostUsedChannel)
|
|
||||||
// if err != nil {
|
|
||||||
// return domain.NotificationDeliveryStats{}, fmt.Errorf("failed to get notification delivery stats: %w", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return stats, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // GetNotificationCountsByType
|
|
||||||
// func (s *Store) GetNotificationCountsByType(ctx context.Context, filter domain.ReportFilter) (map[string]domain.NotificationTypeCount, error) {
|
|
||||||
// query := `SELECT
|
|
||||||
// type,
|
|
||||||
// COUNT(*) as total,
|
|
||||||
// COUNT(CASE WHEN is_read = true THEN 1 END) as read,
|
|
||||||
// COUNT(CASE WHEN is_read = false THEN 1 END) as unread
|
|
||||||
// FROM notifications
|
|
||||||
// WHERE timestamp BETWEEN $1 AND $2
|
|
||||||
// GROUP BY type`
|
|
||||||
|
|
||||||
// counts := make(map[string]domain.NotificationTypeCount)
|
|
||||||
// rows, err := s.conn.Query(ctx, query, filter.StartTime.Value, filter.EndTime.Value)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, fmt.Errorf("failed to get notification counts by type: %w", err)
|
|
||||||
// }
|
|
||||||
// defer rows.Close()
|
|
||||||
|
|
||||||
// for rows.Next() {
|
|
||||||
// var nt domain.NotificationTypeCount
|
|
||||||
// var typ string
|
|
||||||
// if err := rows.Scan(&typ, &nt.Total, &nt.Read, &nt.Unread); err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// counts[typ] = nt
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return counts, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // func (s *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
|
|
||||||
// // dbNotifications, err := s.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
|
|
||||||
// // Limit: int32(limit),
|
|
||||||
// // Offset: int32(offset),
|
|
||||||
// // })
|
|
||||||
// // if err != nil {
|
|
||||||
// // return nil, err
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // result := make([]domain.Notification, 0, len(dbNotifications))
|
|
||||||
// // for _, dbNotif := range dbNotifications {
|
|
||||||
// // // You may want to move this mapping logic to a shared function if not already present
|
|
||||||
// // var errorSeverity *domain.NotificationErrorSeverity
|
|
||||||
// // if dbNotif.ErrorSeverity.Valid {
|
|
||||||
// // s := domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String)
|
|
||||||
// // errorSeverity = &s
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // var deliveryChannel domain.DeliveryChannel
|
|
||||||
// // if dbNotif.DeliveryChannel.Valid {
|
|
||||||
// // deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String)
|
|
||||||
// // } else {
|
|
||||||
// // deliveryChannel = ""
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // var priority int
|
|
||||||
// // if dbNotif.Priority.Valid {
|
|
||||||
// // priority = int(dbNotif.Priority.Int32)
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // payload, err := unmarshalPayload(dbNotif.Payload)
|
|
||||||
// // if err != nil {
|
|
||||||
// // payload = domain.NotificationPayload{}
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // result = append(result, domain.Notification{
|
|
||||||
// // ID: dbNotif.ID,
|
|
||||||
// // RecipientID: dbNotif.RecipientID,
|
|
||||||
// // Type: domain.NotificationType(dbNotif.Type),
|
|
||||||
// // Level: domain.NotificationLevel(dbNotif.Level),
|
|
||||||
// // ErrorSeverity: errorSeverity,
|
|
||||||
// // Reciever: domain.NotificationRecieverSide(dbNotif.Reciever),
|
|
||||||
// // IsRead: dbNotif.IsRead,
|
|
||||||
// // DeliveryStatus: domain.NotificationDeliveryStatus(dbNotif.DeliveryStatus),
|
|
||||||
// // DeliveryChannel: deliveryChannel,
|
|
||||||
// // Payload: payload,
|
|
||||||
// // Priority: priority,
|
|
||||||
// // Timestamp: dbNotif.Timestamp.Time,
|
|
||||||
// // Metadata: dbNotif.Metadata,
|
|
||||||
// // })
|
|
||||||
// // }
|
|
||||||
// // return result, nil
|
|
||||||
// // }
|
|
||||||
|
|
|
||||||
168
internal/repository/settings.go
Normal file
168
internal/repository/settings.go
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"Yimaru-Backend/internal/ports"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface for creating new setting store
|
||||||
|
func NewSettingStore(s *Store) ports.SettingStore { return s }
|
||||||
|
|
||||||
|
func (s *Store) InsertGlobalSetting(ctx context.Context, setting domain.CreateSetting) error {
|
||||||
|
err := s.queries.InsertGlobalSetting(ctx, dbgen.InsertGlobalSettingParams{
|
||||||
|
Key: setting.Key,
|
||||||
|
Value: setting.Value,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetGlobalSettingList(ctx context.Context) (domain.SettingList, error) {
|
||||||
|
settings, err := s.queries.GetGlobalSettings(ctx)
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
|
||||||
|
return domain.SettingList{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.ConvertDBGlobalSettingList(settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetGlobalSettings(ctx context.Context) ([]domain.Setting, error) {
|
||||||
|
settings, err := s.queries.GetGlobalSettings(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []domain.Setting = make([]domain.Setting, 0, len(settings))
|
||||||
|
for _, setting := range settings {
|
||||||
|
result = append(result, domain.Setting{
|
||||||
|
Key: setting.Key,
|
||||||
|
Value: setting.Value,
|
||||||
|
UpdatedAt: setting.UpdatedAt.Time,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error) {
|
||||||
|
dbSetting, err := s.queries.GetGlobalSetting(ctx, key)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := domain.Setting{
|
||||||
|
Key: dbSetting.Key,
|
||||||
|
Value: dbSetting.Value,
|
||||||
|
UpdatedAt: dbSetting.UpdatedAt.Time,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateGlobalSetting(ctx context.Context, key, value string) error {
|
||||||
|
err := s.queries.UpdateGlobalSetting(ctx, dbgen.UpdateGlobalSettingParams{
|
||||||
|
Key: key,
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Error("failed to update setting",
|
||||||
|
zap.String("key", key),
|
||||||
|
zap.String("value", value),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateGlobalSettingList(ctx context.Context, settingList domain.ValidSettingList) error {
|
||||||
|
convertedSettings := settingList.ConvertAllSettings()
|
||||||
|
|
||||||
|
for _, setting := range convertedSettings {
|
||||||
|
err := s.UpdateGlobalSetting(ctx, setting.Key, setting.Value)
|
||||||
|
if err != nil {
|
||||||
|
domain.MongoDBLogger.Warn("failed to update setting list", zap.String("key", setting.Key), zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// func (s *Store) GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error) {
|
||||||
|
// settings, err := s.queries.GetOverrideSettings(ctx, companyID)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// result := make([]domain.Setting, 0, len(settings))
|
||||||
|
// for _, setting := range settings {
|
||||||
|
// result = append(result, domain.Setting{
|
||||||
|
// Key: setting.Key,
|
||||||
|
// Value: setting.Value,
|
||||||
|
// UpdatedAt: setting.UpdatedAt.Time,
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return result, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (s *Store) GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) {
|
||||||
|
// settings, err := s.queries.GetOverrideSettings(ctx, companyID)
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// return domain.SettingList{}, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return domain.ConvertDBOverrideSettingList(settings)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
|
||||||
|
// return s.queries.DeleteCompanySetting(ctx, dbgen.DeleteCompanySettingParams{
|
||||||
|
// CompanyID: companyID,
|
||||||
|
// Key: key,
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
|
||||||
|
// return s.queries.DeleteAllCompanySetting(ctx, companyID)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (s *Store) EnsureAllSettingsExist(ctx context.Context) error {
|
||||||
|
defaultSettings := domain.NewDefaultSettingList().ToSettingArray() // returns []domain.Setting from your typed struct
|
||||||
|
|
||||||
|
dbSettings, err := s.GetGlobalSettings(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to fetch settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
existing := map[string]struct{}{}
|
||||||
|
for _, s := range dbSettings {
|
||||||
|
existing[s.Key] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, setting := range defaultSettings {
|
||||||
|
if _, found := existing[setting.Key]; !found {
|
||||||
|
if err := s.InsertGlobalSetting(ctx, domain.CreateSetting{
|
||||||
|
Key: setting.Key,
|
||||||
|
Value: setting.Value,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("failed to create missing setting %q: %w", setting.Key, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,10 @@ package repository
|
||||||
import (
|
import (
|
||||||
dbgen "Yimaru-Backend/gen/db"
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
"Yimaru-Backend/internal/domain"
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"Yimaru-Backend/internal/ports"
|
||||||
|
"Yimaru-Backend/internal/services/authentication"
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -23,6 +26,54 @@ import (
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
func NewUserStore(s *Store) ports.UserStore { return s }
|
||||||
|
|
||||||
|
func (s *Store) CreateUserWithoutOtp(ctx context.Context, user domain.User) (domain.User, error) {
|
||||||
|
userRes, err := s.queries.CreateUser(ctx, dbgen.CreateUserParams{
|
||||||
|
FirstName: user.FirstName,
|
||||||
|
LastName: user.LastName,
|
||||||
|
NickName: pgtype.Text{String: user.NickName},
|
||||||
|
Email: pgtype.Text{String: user.Email, Valid: user.Email != ""},
|
||||||
|
PhoneNumber: pgtype.Text{String: user.PhoneNumber, Valid: user.PhoneNumber != ""},
|
||||||
|
Role: string(user.Role),
|
||||||
|
Password: user.Password,
|
||||||
|
Age: pgtype.Int4{Int32: int32(user.Age), Valid: user.Age > 0},
|
||||||
|
EducationLevel: pgtype.Text{String: user.EducationLevel, Valid: user.EducationLevel != ""},
|
||||||
|
Country: pgtype.Text{String: user.Country, Valid: user.Country != ""},
|
||||||
|
Region: pgtype.Text{String: user.Region, Valid: user.Region != ""},
|
||||||
|
EmailVerified: user.EmailVerified,
|
||||||
|
PhoneVerified: user.PhoneVerified,
|
||||||
|
Suspended: user.Suspended,
|
||||||
|
SuspendedAt: pgtype.Timestamptz{Time: user.SuspendedAt, Valid: !user.SuspendedAt.IsZero()},
|
||||||
|
OrganizationID: pgtype.Int8{Int64: user.OrganizationID.Value, Valid: user.OrganizationID.Valid},
|
||||||
|
CreatedAt: pgtype.Timestamptz{Time: time.Now(), Valid: true},
|
||||||
|
UpdatedAt: pgtype.Timestamptz{Time: time.Now(), Valid: true},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return domain.User{}, err
|
||||||
|
}
|
||||||
|
return domain.User{
|
||||||
|
ID: userRes.ID,
|
||||||
|
FirstName: userRes.FirstName,
|
||||||
|
LastName: userRes.LastName,
|
||||||
|
NickName: userRes.NickName.String,
|
||||||
|
Email: userRes.Email.String,
|
||||||
|
PhoneNumber: userRes.PhoneNumber.String,
|
||||||
|
Role: domain.Role(userRes.Role),
|
||||||
|
Age: int(userRes.Age.Int32),
|
||||||
|
EducationLevel: userRes.EducationLevel.String,
|
||||||
|
Country: userRes.Country.String,
|
||||||
|
Region: userRes.Region.String,
|
||||||
|
EmailVerified: userRes.EmailVerified,
|
||||||
|
PhoneVerified: userRes.PhoneVerified,
|
||||||
|
Suspended: userRes.Suspended,
|
||||||
|
SuspendedAt: userRes.SuspendedAt.Time,
|
||||||
|
OrganizationID: domain.ValidInt64{Value: userRes.OrganizationID.Int64, Valid: userRes.OrganizationID.Valid},
|
||||||
|
CreatedAt: userRes.CreatedAt.Time,
|
||||||
|
UpdatedAt: userRes.UpdatedAt.Time,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateUser inserts a new user into the database
|
// CreateUser inserts a new user into the database
|
||||||
func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error) {
|
func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error) {
|
||||||
// Optional: mark OTP as used
|
// Optional: mark OTP as used
|
||||||
|
|
@ -117,23 +168,54 @@ func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllUsers retrieves users with optional filters
|
// GetAllUsers retrieves users with optional filters
|
||||||
func (s *Store) GetAllUsers(ctx context.Context, role *string, organizationID *int64, query *string, createdBefore, createdAfter *time.Time, limit, offset int32) ([]domain.User, error) {
|
func (s *Store) GetAllUsers(
|
||||||
rows, err := s.queries.GetAllUsers(ctx, dbgen.GetAllUsersParams{
|
ctx context.Context,
|
||||||
Role: *role,
|
role *string,
|
||||||
OrganizationID: pgtype.Int8{Int64: *organizationID},
|
organizationID *int64,
|
||||||
Query: pgtype.Text{String: *query},
|
query *string,
|
||||||
CreatedBefore: pgtype.Timestamptz{Time: *createdBefore},
|
createdBefore, createdAfter *time.Time,
|
||||||
CreatedAfter: pgtype.Timestamptz{Time: *createdAfter},
|
limit, offset int32,
|
||||||
Limit: pgtype.Int4{Int32: limit},
|
) ([]domain.User, int64, error) {
|
||||||
Offset: pgtype.Int4{Int32: offset},
|
|
||||||
})
|
params := dbgen.GetAllUsersParams{
|
||||||
if err != nil {
|
Limit: pgtype.Int4{Int32: limit, Valid: true},
|
||||||
return nil, err
|
Offset: pgtype.Int4{Int32: offset, Valid: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
users := make([]domain.User, len(rows))
|
if role != nil {
|
||||||
for i, u := range rows {
|
params.Role = *role
|
||||||
users[i] = domain.User{
|
}
|
||||||
|
|
||||||
|
if organizationID != nil {
|
||||||
|
params.OrganizationID = pgtype.Int8{Int64: *organizationID, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
if query != nil {
|
||||||
|
params.Query = pgtype.Text{String: *query, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
if createdBefore != nil {
|
||||||
|
params.CreatedBefore = pgtype.Timestamptz{Time: *createdBefore, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
if createdAfter != nil {
|
||||||
|
params.CreatedAfter = pgtype.Timestamptz{Time: *createdAfter, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := s.queries.GetAllUsers(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rows) == 0 {
|
||||||
|
return []domain.User{}, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCount := rows[0].TotalCount
|
||||||
|
|
||||||
|
users := make([]domain.User, 0, len(rows))
|
||||||
|
for _, u := range rows {
|
||||||
|
users = append(users, domain.User{
|
||||||
ID: u.ID,
|
ID: u.ID,
|
||||||
FirstName: u.FirstName,
|
FirstName: u.FirstName,
|
||||||
LastName: u.LastName,
|
LastName: u.LastName,
|
||||||
|
|
@ -149,13 +231,16 @@ func (s *Store) GetAllUsers(ctx context.Context, role *string, organizationID *i
|
||||||
PhoneVerified: u.PhoneVerified,
|
PhoneVerified: u.PhoneVerified,
|
||||||
Suspended: u.Suspended,
|
Suspended: u.Suspended,
|
||||||
SuspendedAt: u.SuspendedAt.Time,
|
SuspendedAt: u.SuspendedAt.Time,
|
||||||
OrganizationID: domain.ValidInt64{Value: u.OrganizationID.Int64, Valid: u.OrganizationID.Valid},
|
OrganizationID: domain.ValidInt64{
|
||||||
CreatedAt: u.CreatedAt.Time,
|
Value: u.OrganizationID.Int64,
|
||||||
UpdatedAt: u.UpdatedAt.Time,
|
Valid: u.OrganizationID.Valid,
|
||||||
}
|
},
|
||||||
|
CreatedAt: u.CreatedAt.Time,
|
||||||
|
UpdatedAt: u.UpdatedAt.Time,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return users, nil
|
return users, totalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTotalUsers counts users with optional filters
|
// GetTotalUsers counts users with optional filters
|
||||||
|
|
@ -241,11 +326,11 @@ func (s *Store) DeleteUser(ctx context.Context, userID int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckPhoneEmailExist checks if phone or email exists in an organization
|
// CheckPhoneEmailExist checks if phone or email exists in an organization
|
||||||
func (s *Store) CheckPhoneEmailExist(ctx context.Context, phone, email string, organizationID int64) (phoneExists, emailExists bool, err error) {
|
func (s *Store) CheckPhoneEmailExist(ctx context.Context, phone, email string, organizationID domain.ValidInt64) (phoneExists, emailExists bool, err error) {
|
||||||
res, err := s.queries.CheckPhoneEmailExist(ctx, dbgen.CheckPhoneEmailExistParams{
|
res, err := s.queries.CheckPhoneEmailExist(ctx, dbgen.CheckPhoneEmailExistParams{
|
||||||
PhoneNumber: pgtype.Text{String: phone},
|
PhoneNumber: pgtype.Text{String: phone},
|
||||||
Email: pgtype.Text{String: email},
|
Email: pgtype.Text{String: email},
|
||||||
OrganizationID: pgtype.Int8{Int64: organizationID},
|
OrganizationID: pgtype.Int8{Int64: organizationID.Value},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
|
|
@ -255,64 +340,54 @@ func (s *Store) CheckPhoneEmailExist(ctx context.Context, phone, email string, o
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByEmail retrieves a user by email and organization
|
// GetUserByEmail retrieves a user by email and organization
|
||||||
func (s *Store) GetUserByEmail(ctx context.Context, email string, organizationID int64) (domain.User, error) {
|
func (s *Store) GetUserByEmailPhone(
|
||||||
userRes, err := s.queries.GetUserByEmail(ctx, dbgen.GetUserByEmailParams{
|
ctx context.Context,
|
||||||
Email: pgtype.Text{String: email},
|
email string,
|
||||||
OrganizationID: pgtype.Int8{Int64: organizationID},
|
phone string,
|
||||||
})
|
organizationID domain.ValidInt64,
|
||||||
if err != nil {
|
) (domain.User, error) {
|
||||||
return domain.User{}, err
|
|
||||||
}
|
|
||||||
return domain.User{
|
|
||||||
ID: userRes.ID,
|
|
||||||
FirstName: userRes.FirstName,
|
|
||||||
LastName: userRes.LastName,
|
|
||||||
NickName: userRes.NickName.String,
|
|
||||||
Email: userRes.Email.String,
|
|
||||||
PhoneNumber: userRes.PhoneNumber.String,
|
|
||||||
Role: domain.Role(userRes.Role),
|
|
||||||
Age: int(userRes.Age.Int32),
|
|
||||||
EducationLevel: userRes.EducationLevel.String,
|
|
||||||
Country: userRes.Country.String,
|
|
||||||
Region: userRes.Region.String,
|
|
||||||
EmailVerified: userRes.EmailVerified,
|
|
||||||
PhoneVerified: userRes.PhoneVerified,
|
|
||||||
Suspended: userRes.Suspended,
|
|
||||||
SuspendedAt: userRes.SuspendedAt.Time,
|
|
||||||
OrganizationID: domain.ValidInt64{Value: userRes.OrganizationID.Int64, Valid: userRes.OrganizationID.Valid},
|
|
||||||
CreatedAt: userRes.CreatedAt.Time,
|
|
||||||
UpdatedAt: userRes.UpdatedAt.Time,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByPhone retrieves a user by phone and organization
|
user, err := s.queries.GetUserByEmailPhone(ctx, dbgen.GetUserByEmailPhoneParams{
|
||||||
func (s *Store) GetUserByPhone(ctx context.Context, phone string, organizationID int64) (domain.User, error) {
|
Email: pgtype.Text{
|
||||||
userRes, err := s.queries.GetUserByPhone(ctx, dbgen.GetUserByPhoneParams{
|
String: email,
|
||||||
PhoneNumber: pgtype.Text{String: phone},
|
Valid: email != "",
|
||||||
OrganizationID: pgtype.Int8{Int64: organizationID},
|
},
|
||||||
|
PhoneNumber: pgtype.Text{
|
||||||
|
String: phone,
|
||||||
|
Valid: phone != "",
|
||||||
|
},
|
||||||
|
OrganizationID: organizationID.ToPG(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return domain.User{}, authentication.ErrUserNotFound
|
||||||
|
}
|
||||||
return domain.User{}, err
|
return domain.User{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain.User{
|
return domain.User{
|
||||||
ID: userRes.ID,
|
ID: user.ID,
|
||||||
FirstName: userRes.FirstName,
|
FirstName: user.FirstName,
|
||||||
LastName: userRes.LastName,
|
LastName: user.LastName,
|
||||||
NickName: userRes.NickName.String,
|
NickName: user.NickName.String,
|
||||||
Email: userRes.Email.String,
|
Email: user.Email.String,
|
||||||
PhoneNumber: userRes.PhoneNumber.String,
|
PhoneNumber: user.PhoneNumber.String,
|
||||||
Role: domain.Role(userRes.Role),
|
Password: user.Password,
|
||||||
Age: int(userRes.Age.Int32),
|
Role: domain.Role(user.Role),
|
||||||
EducationLevel: userRes.EducationLevel.String,
|
Age: int(user.Age.Int32),
|
||||||
Country: userRes.Country.String,
|
EducationLevel: user.EducationLevel.String,
|
||||||
Region: userRes.Region.String,
|
Country: user.Country.String,
|
||||||
EmailVerified: userRes.EmailVerified,
|
Region: user.Region.String,
|
||||||
PhoneVerified: userRes.PhoneVerified,
|
EmailVerified: user.EmailVerified,
|
||||||
Suspended: userRes.Suspended,
|
PhoneVerified: user.PhoneVerified,
|
||||||
SuspendedAt: userRes.SuspendedAt.Time,
|
Suspended: user.Suspended,
|
||||||
OrganizationID: domain.ValidInt64{Value: userRes.OrganizationID.Int64, Valid: userRes.OrganizationID.Valid},
|
SuspendedAt: user.SuspendedAt.Time,
|
||||||
CreatedAt: userRes.CreatedAt.Time,
|
OrganizationID: domain.ValidInt64{
|
||||||
UpdatedAt: userRes.UpdatedAt.Time,
|
Value: user.OrganizationID.Int64,
|
||||||
|
Valid: user.OrganizationID.Valid,
|
||||||
|
},
|
||||||
|
CreatedAt: user.CreatedAt.Time,
|
||||||
|
UpdatedAt: user.UpdatedAt.Time,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,6 +411,21 @@ func (s *Store) GetOwnerByOrganizationID(ctx context.Context, organizationID int
|
||||||
return mapUser(userRes), nil
|
return mapUser(userRes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdateUserSuspend(ctx context.Context, id int64, status bool) error {
|
||||||
|
err := s.queries.SuspendUser(ctx, dbgen.SuspendUserParams{
|
||||||
|
ID: id,
|
||||||
|
Suspended: status,
|
||||||
|
SuspendedAt: pgtype.Timestamptz{
|
||||||
|
Time: time.Now(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// mapUser converts dbgen.User to domain.User
|
// mapUser converts dbgen.User to domain.User
|
||||||
func mapUser(u dbgen.User) domain.User {
|
func mapUser(u dbgen.User) domain.User {
|
||||||
return domain.User{
|
return domain.User{
|
||||||
|
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
package currency
|
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FixerFetcher struct {
|
|
||||||
apiKey string
|
|
||||||
baseURL string
|
|
||||||
httpClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFixerFetcher(apiKey string, baseURL string) *FixerFetcher {
|
|
||||||
|
|
||||||
return &FixerFetcher{
|
|
||||||
apiKey: apiKey,
|
|
||||||
baseURL: baseURL,
|
|
||||||
httpClient: &http.Client{Timeout: 10 * time.Second},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fixerResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Base string `json:"base"`
|
|
||||||
Date string `json:"date"`
|
|
||||||
Rates map[string]float64 `json:"rates"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FixerFetcher) FetchLatestRates(ctx context.Context, baseCurrency domain.IntCurrency) (map[domain.IntCurrency]float64, error) {
|
|
||||||
url := fmt.Sprintf("%s/latest?base=%s", f.baseURL, baseCurrency)
|
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("apikey", f.apiKey)
|
|
||||||
|
|
||||||
resp, err := f.httpClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to fetch rates: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
var result fixerResponse
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !result.Success {
|
|
||||||
return nil, fmt.Errorf("api returned unsuccessful response")
|
|
||||||
}
|
|
||||||
|
|
||||||
rates := make(map[domain.IntCurrency]float64)
|
|
||||||
for currency, rate := range result.Rates {
|
|
||||||
rates[domain.IntCurrency(currency)] = rate
|
|
||||||
}
|
|
||||||
|
|
||||||
return rates, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
package currency
|
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
"Yimaru-Backend/internal/repository"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
repo repository.CurrencyRepository
|
|
||||||
baseCurrency domain.IntCurrency
|
|
||||||
fixerFetcher *FixerFetcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(repo repository.CurrencyRepository, baseCurrency domain.IntCurrency, fixerFetcher *FixerFetcher) *Service {
|
|
||||||
return &Service{repo: repo}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Convert(ctx context.Context, amount float64, from, to domain.IntCurrency) (float64, error) {
|
|
||||||
if from == to {
|
|
||||||
return amount, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rate, err := s.repo.GetExchangeRate(ctx, from, to)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return rate.Convert(amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetSupportedCurrencies(ctx context.Context) ([]domain.IntCurrency, error) {
|
|
||||||
return s.repo.GetSupportedCurrencies(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateRates(ctx context.Context) error {
|
|
||||||
// Implement fetching from external API (e.g., Fixer, Open Exchange Rates)
|
|
||||||
rates := map[domain.IntCurrency]map[domain.IntCurrency]float64{
|
|
||||||
domain.ETB: {
|
|
||||||
domain.USD: 0.018,
|
|
||||||
domain.EUR: 0.016,
|
|
||||||
domain.GBP: 0.014,
|
|
||||||
},
|
|
||||||
// Add other currencies...
|
|
||||||
}
|
|
||||||
|
|
||||||
for from, toRates := range rates {
|
|
||||||
for to, rate := range toRates {
|
|
||||||
err := s.repo.StoreExchangeRate(ctx, domain.IntCurrencyRate{
|
|
||||||
From: from,
|
|
||||||
To: to,
|
|
||||||
Rate: rate,
|
|
||||||
ValidUntil: time.Now().Add(24 * time.Hour), // Refresh daily
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) FetchAndStoreRates(ctx context.Context) error {
|
|
||||||
// s.logger.Info("Starting exchange rate update")
|
|
||||||
|
|
||||||
rates, err := s.fixerFetcher.FetchLatestRates(ctx, s.baseCurrency)
|
|
||||||
if err != nil {
|
|
||||||
// s.logger.Error("Failed to fetch rates", "error", err)
|
|
||||||
return fmt.Errorf("failed to fetch rates: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to integer rates with precision
|
|
||||||
const precision = 6 // 1.000000
|
|
||||||
for currency, rate := range rates {
|
|
||||||
if currency == s.baseCurrency {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
intRate := domain.IntCurrencyRate{
|
|
||||||
From: s.baseCurrency,
|
|
||||||
To: currency,
|
|
||||||
Rate: rate * float64(pow10(precision)),
|
|
||||||
ValidUntil: time.Now().Add(24 * time.Hour), // Rates valid for 24 hours
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.repo.StoreExchangeRate(ctx, intRate); err != nil {
|
|
||||||
// s.logger.Error("Failed to store rate",
|
|
||||||
// "from", s.baseCurrency,
|
|
||||||
// "to", currency,
|
|
||||||
// "error", err)
|
|
||||||
continue // Try to store other rates even if one fails
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also store the inverse rate
|
|
||||||
inverseRate := domain.IntCurrencyRate{
|
|
||||||
From: currency,
|
|
||||||
To: s.baseCurrency,
|
|
||||||
Rate: (1 / rate) * float64(pow10(precision)),
|
|
||||||
ValidUntil: time.Now().Add(24 * time.Hour),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.repo.StoreExchangeRate(ctx, inverseRate); err != nil {
|
|
||||||
// s.logger.Error("Failed to store inverse rate",
|
|
||||||
// "from", currency,
|
|
||||||
// "to", s.baseCurrency,
|
|
||||||
// "error", err)
|
|
||||||
return fmt.Errorf("Error storing exchange rates")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// s.logger.Info("Exchange rates updated successfully")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func pow10(n int) int64 {
|
|
||||||
result := int64(1)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
result *= 10
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
package currency
|
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/config"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-co-op/gocron"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ExchangeRateWorker struct {
|
|
||||||
fetcherService *FixerFetcher
|
|
||||||
scheduler *gocron.Scheduler
|
|
||||||
logger *slog.Logger
|
|
||||||
cfg *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewExchangeRateWorker(
|
|
||||||
fetcherService *FixerFetcher, logger *slog.Logger, cfg *config.Config,
|
|
||||||
) *ExchangeRateWorker {
|
|
||||||
return &ExchangeRateWorker{
|
|
||||||
fetcherService: fetcherService,
|
|
||||||
scheduler: gocron.NewScheduler(time.UTC),
|
|
||||||
logger: logger,
|
|
||||||
cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ExchangeRateWorker) Start(ctx context.Context) {
|
|
||||||
_, err := w.scheduler.Every(6).Hours().Do(w.RunUpdate)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run immediately on startup
|
|
||||||
go w.RunUpdate()
|
|
||||||
|
|
||||||
w.scheduler.StartAsync()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ExchangeRateWorker) RunUpdate() {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if _, err := w.fetcherService.FetchLatestRates(ctx, w.cfg.BASE_CURRENCY); err != nil {
|
|
||||||
fmt.Println("Exchange rate update failed", "error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ExchangeRateWorker) Stop() {
|
|
||||||
w.scheduler.Stop()
|
|
||||||
w.logger.Info("Exchange rate worker stopped")
|
|
||||||
}
|
|
||||||
92
internal/services/issue_reporting/service.go
Normal file
92
internal/services/issue_reporting/service.go
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
package issuereporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
dbgen "Yimaru-Backend/gen/db"
|
||||||
|
"Yimaru-Backend/internal/domain"
|
||||||
|
"Yimaru-Backend/internal/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
repo repository.ReportedIssueRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo repository.ReportedIssueRepository) *Service {
|
||||||
|
return &Service{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateReportedIssue(ctx context.Context, issue domain.ReportedIssueReq, userID int64, role domain.Role) (domain.ReportedIssue, error) {
|
||||||
|
|
||||||
|
// metadata, err := json.Marshal(issue.Metadata)
|
||||||
|
// if err != nil {
|
||||||
|
// return domain.ReportedIssue{}, err
|
||||||
|
// }
|
||||||
|
params := dbgen.CreateReportedIssueParams{
|
||||||
|
UserID: userID,
|
||||||
|
UserRole: string(role),
|
||||||
|
Subject: issue.Subject,
|
||||||
|
Description: issue.Description,
|
||||||
|
IssueType: string(issue.IssueType),
|
||||||
|
// Metadata: metadata,
|
||||||
|
}
|
||||||
|
dbIssue, err := s.repo.CreateReportedIssue(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return domain.ReportedIssue{}, err
|
||||||
|
}
|
||||||
|
// Map dbgen.ReportedIssue to domain.ReportedIssue
|
||||||
|
reportedIssue := domain.ReportedIssue{
|
||||||
|
ID: dbIssue.ID,
|
||||||
|
Subject: dbIssue.Subject,
|
||||||
|
Description: dbIssue.Description,
|
||||||
|
UserID: dbIssue.UserID,
|
||||||
|
UserRole: domain.Role(dbIssue.UserRole),
|
||||||
|
Status: domain.ReportedIssueStatus(dbIssue.Status),
|
||||||
|
IssueType: domain.ReportedIssueType(dbIssue.IssueType),
|
||||||
|
CreatedAt: dbIssue.CreatedAt.Time,
|
||||||
|
UpdatedAt: dbIssue.UpdatedAt.Time,
|
||||||
|
|
||||||
|
// Add other fields as necessary
|
||||||
|
}
|
||||||
|
return reportedIssue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetIssuesForUser(ctx context.Context, userID int64, limit, offset int) ([]domain.ReportedIssue, error) {
|
||||||
|
dbIssues, err := s.repo.ListReportedIssuesByUser(ctx, userID, int32(limit), int32(offset))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reportedIssues := make([]domain.ReportedIssue, len(dbIssues))
|
||||||
|
for i, dbIssue := range dbIssues {
|
||||||
|
reportedIssues[i] = domain.ReportedIssue{
|
||||||
|
ID: dbIssue.ID,
|
||||||
|
Subject: dbIssue.Subject,
|
||||||
|
Description: dbIssue.Description,
|
||||||
|
UserID: dbIssue.UserID,
|
||||||
|
UserRole: domain.Role(dbIssue.UserRole),
|
||||||
|
Status: domain.ReportedIssueStatus(dbIssue.Status),
|
||||||
|
IssueType: domain.ReportedIssueType(dbIssue.IssueType),
|
||||||
|
CreatedAt: dbIssue.CreatedAt.Time,
|
||||||
|
UpdatedAt: dbIssue.UpdatedAt.Time,
|
||||||
|
// Add other fields as necessary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reportedIssues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllIssues(ctx context.Context, limit, offset int) ([]dbgen.ReportedIssue, error) {
|
||||||
|
return s.repo.ListReportedIssues(ctx, int32(limit), int32(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) UpdateIssueStatus(ctx context.Context, issueID int64, status string) error {
|
||||||
|
validStatuses := map[string]bool{"pending": true, "in_progress": true, "resolved": true, "rejected": true}
|
||||||
|
if !validStatuses[status] {
|
||||||
|
return errors.New("invalid status")
|
||||||
|
}
|
||||||
|
return s.repo.UpdateReportedIssueStatus(ctx, issueID, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) DeleteIssue(ctx context.Context, issueID int64) error {
|
||||||
|
return s.repo.DeleteReportedIssue(ctx, issueID)
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
func (s *Service) SendEmail(ctx context.Context, receiverEmail, message string, messageHTML string, subject string) error {
|
func (s *Service) SendEmail(ctx context.Context, receiverEmail, message string, messageHTML string, subject string) error {
|
||||||
apiKey := s.config.ResendApiKey
|
apiKey := s.config.ResendApiKey
|
||||||
client := resend.NewClient(apiKey)
|
client := resend.NewClient(apiKey)
|
||||||
formattedSenderEmail := "FortuneBets <" + s.config.ResendSenderEmail + ">"
|
formattedSenderEmail := "Y <" + s.config.ResendSenderEmail + ">"
|
||||||
params := &resend.SendEmailRequest{
|
params := &resend.SendEmailRequest{
|
||||||
From: formattedSenderEmail,
|
From: formattedSenderEmail,
|
||||||
To: []string{receiverEmail},
|
To: []string{receiverEmail},
|
||||||
|
|
|
||||||
|
|
@ -19,21 +19,21 @@ var (
|
||||||
func (s *Service) SendSMS(ctx context.Context, receiverPhone, message string, companyID domain.ValidInt64) error {
|
func (s *Service) SendSMS(ctx context.Context, receiverPhone, message string, companyID domain.ValidInt64) error {
|
||||||
|
|
||||||
var settingsList domain.SettingList
|
var settingsList domain.SettingList
|
||||||
var err error
|
// var err error
|
||||||
|
|
||||||
if companyID.Valid {
|
// if companyID.Valid {
|
||||||
settingsList, err = s.settingSvc.GetOverrideSettingsList(ctx, companyID.Value)
|
// settingsList, err = s.settingSvc.GetOverrideSettingsList(ctx, companyID.Value)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
// TODO: Send a log about the error
|
// // TODO: Send a log about the error
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
settingsList, err = s.settingSvc.GetGlobalSettingList(ctx)
|
// settingsList, err = s.settingSvc.GetGlobalSettingList(ctx)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
// TODO: Send a log about the error
|
// // TODO: Send a log about the error
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
switch settingsList.SMSProvider {
|
switch settingsList.SMSProvider {
|
||||||
case domain.AfroMessage:
|
case domain.AfroMessage:
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func New(
|
||||||
|
|
||||||
go hub.Run()
|
go hub.Run()
|
||||||
go svc.startWorker()
|
go svc.startWorker()
|
||||||
go svc.startRetryWorker()
|
// go svc.startRetryWorker()
|
||||||
// go svc.RunRedisSubscriber(context.Background())
|
// go svc.RunRedisSubscriber(context.Background())
|
||||||
// go svc.StartKafkaConsumer(context.Background())
|
// go svc.StartKafkaConsumer(context.Background())
|
||||||
|
|
||||||
|
|
@ -123,42 +123,42 @@ func (s *Service) SendNotification(ctx context.Context, notification *domain.Not
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) MarkAsRead(ctx context.Context, notificationIDs []string, recipientID int64) error {
|
// func (s *Service) MarkAsRead(ctx context.Context, notificationIDs []string, recipientID int64) error {
|
||||||
for _, notificationID := range notificationIDs {
|
// for _, notificationID := range notificationIDs {
|
||||||
_, err := s.store.UpdateNotificationStatus(ctx, notificationID, string(domain.DeliveryStatusSent), true, nil)
|
// _, err := s.store.UpdateNotificationStatus(ctx, notificationID, string(domain.DeliveryStatusSent), true, nil)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
s.mongoLogger.Error("[NotificationSvc.MarkAsRead] Failed to mark notification as read",
|
// s.mongoLogger.Error("[NotificationSvc.MarkAsRead] Failed to mark notification as read",
|
||||||
zap.String("notificationID", notificationID),
|
// zap.String("notificationID", notificationID),
|
||||||
zap.Int64("recipientID", recipientID),
|
// zap.Int64("recipientID", recipientID),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
|
||||||
// count, err := s.store.CountUnreadNotifications(ctx, recipientID)
|
// // count, err := s.store.CountUnreadNotifications(ctx, recipientID)
|
||||||
// if err != nil {
|
// // if err != nil {
|
||||||
// s.logger.Error("[NotificationSvc.MarkAsRead] Failed to count unread notifications", "recipientID", recipientID, "error", err)
|
// // s.logger.Error("[NotificationSvc.MarkAsRead] Failed to count unread notifications", "recipientID", recipientID, "error", err)
|
||||||
// return err
|
// // return err
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
// s.Hub.Broadcast <- map[string]interface{}{
|
// // s.Hub.Broadcast <- map[string]interface{}{
|
||||||
// "type": "COUNT_NOT_OPENED_NOTIFICATION",
|
// // "type": "COUNT_NOT_OPENED_NOTIFICATION",
|
||||||
// "recipient_id": recipientID,
|
// // "recipient_id": recipientID,
|
||||||
// "payload": map[string]int{
|
// // "payload": map[string]int{
|
||||||
// "not_opened_notifications_count": int(count),
|
// // "not_opened_notifications_count": int(count),
|
||||||
// },
|
// // },
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
s.mongoLogger.Info("[NotificationSvc.MarkAsRead] Notification marked as read",
|
// s.mongoLogger.Info("[NotificationSvc.MarkAsRead] Notification marked as read",
|
||||||
zap.String("notificationID", notificationID),
|
// zap.String("notificationID", notificationID),
|
||||||
zap.Int64("recipientID", recipientID),
|
// zap.Int64("recipientID", recipientID),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error) {
|
func (s *Service) GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error) {
|
||||||
notifications, total, err := s.store.GetUserNotifications(ctx, recipientID, limit, offset)
|
notifications, total, err := s.store.GetUserNotifications(ctx, recipientID, limit, offset)
|
||||||
|
|
@ -277,9 +277,9 @@ func (s *Service) startWorker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
// func (s *Service) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||||
return s.store.ListRecipientIDs(ctx, receiver)
|
// return s.store.ListRecipientIDs(ctx, receiver)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) handleNotification(notification *domain.Notification) {
|
func (s *Service) handleNotification(notification *domain.Notification) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
@ -310,13 +310,13 @@ func (s *Service) handleNotification(notification *domain.Notification) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.store.UpdateNotificationStatus(ctx, notification.ID, string(notification.DeliveryStatus), notification.IsRead, notification.Metadata); err != nil {
|
// if _, err := s.store.UpdateNotificationStatus(ctx, notification.ID, string(notification.DeliveryStatus), notification.IsRead, notification.Metadata); err != nil {
|
||||||
s.mongoLogger.Error("[NotificationSvc.HandleNotification] Failed to update notification status",
|
// s.mongoLogger.Error("[NotificationSvc.HandleNotification] Failed to update notification status",
|
||||||
zap.String("id", notification.ID),
|
// zap.String("id", notification.ID),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SendNotificationSMS(ctx context.Context, recipientID int64, message string) error {
|
func (s *Service) SendNotificationSMS(ctx context.Context, recipientID int64, message string) error {
|
||||||
|
|
@ -381,94 +381,94 @@ func (s *Service) SendNotificationEmail(ctx context.Context, recipientID int64,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) startRetryWorker() {
|
// func (s *Service) startRetryWorker() {
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
// ticker := time.NewTicker(1 * time.Minute)
|
||||||
defer ticker.Stop()
|
// defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
// for {
|
||||||
select {
|
// select {
|
||||||
case <-ticker.C:
|
// case <-ticker.C:
|
||||||
s.retryFailedNotifications()
|
// s.retryFailedNotifications()
|
||||||
case <-s.stopCh:
|
// case <-s.stopCh:
|
||||||
s.mongoLogger.Info("[NotificationSvc.StartRetryWorker] Retry worker stopped",
|
// s.mongoLogger.Info("[NotificationSvc.StartRetryWorker] Retry worker stopped",
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) retryFailedNotifications() {
|
// func (s *Service) retryFailedNotifications() {
|
||||||
ctx := context.Background()
|
// ctx := context.Background()
|
||||||
failedNotifications, err := s.store.ListFailedNotifications(ctx, 100)
|
// failedNotifications, err := s.store.ListFailedNotifications(ctx, 100)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to list failed notifications",
|
// s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to list failed notifications",
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
for _, n := range failedNotifications {
|
// for _, n := range failedNotifications {
|
||||||
notification := &n
|
// notification := &n
|
||||||
go func(notification *domain.Notification) {
|
// go func(notification *domain.Notification) {
|
||||||
for attempt := 0; attempt < 3; attempt++ {
|
// for attempt := 0; attempt < 3; attempt++ {
|
||||||
time.Sleep(time.Duration(attempt) * time.Second)
|
// time.Sleep(time.Duration(attempt) * time.Second)
|
||||||
switch notification.DeliveryChannel {
|
// switch notification.DeliveryChannel {
|
||||||
case domain.DeliveryChannelSMS:
|
// case domain.DeliveryChannelSMS:
|
||||||
if err := s.SendNotificationSMS(ctx, notification.RecipientID, notification.Payload.Message); err == nil {
|
// if err := s.SendNotificationSMS(ctx, notification.RecipientID, notification.Payload.Message); err == nil {
|
||||||
notification.DeliveryStatus = domain.DeliveryStatusSent
|
// notification.DeliveryStatus = domain.DeliveryStatusSent
|
||||||
if _, err := s.store.UpdateNotificationStatus(ctx, notification.ID, string(notification.DeliveryStatus), notification.IsRead, notification.Metadata); err != nil {
|
// if _, err := s.store.UpdateNotificationStatus(ctx, notification.ID, string(notification.DeliveryStatus), notification.IsRead, notification.Metadata); err != nil {
|
||||||
s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to update after retry",
|
// s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to update after retry",
|
||||||
zap.String("id", notification.ID),
|
// zap.String("id", notification.ID),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
} else {
|
// } else {
|
||||||
s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
// s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
||||||
zap.String("id", notification.ID),
|
// zap.String("id", notification.ID),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
case domain.DeliveryChannelEmail:
|
// case domain.DeliveryChannelEmail:
|
||||||
if err := s.SendNotificationEmail(ctx, notification.RecipientID, notification.Payload.Message, notification.Payload.Headline); err == nil {
|
// if err := s.SendNotificationEmail(ctx, notification.RecipientID, notification.Payload.Message, notification.Payload.Headline); err == nil {
|
||||||
notification.DeliveryStatus = domain.DeliveryStatusSent
|
// notification.DeliveryStatus = domain.DeliveryStatusSent
|
||||||
if _, err := s.store.UpdateNotificationStatus(ctx, notification.ID, string(notification.DeliveryStatus), notification.IsRead, notification.Metadata); err != nil {
|
// if _, err := s.store.UpdateNotificationStatus(ctx, notification.ID, string(notification.DeliveryStatus), notification.IsRead, notification.Metadata); err != nil {
|
||||||
s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to update after retry",
|
// s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to update after retry",
|
||||||
zap.String("id", notification.ID),
|
// zap.String("id", notification.ID),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
} else {
|
// } else {
|
||||||
s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
// s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
||||||
zap.String("id", notification.ID),
|
// zap.String("id", notification.ID),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Max retries reached for notification",
|
// s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Max retries reached for notification",
|
||||||
zap.String("id", notification.ID),
|
// zap.String("id", notification.ID),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
}(notification)
|
// }(notification)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
func (s *Service) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
||||||
return s.store.CountUnreadNotifications(ctx, recipient_id)
|
return s.store.CountUnreadNotifications(ctx, recipient_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) DeleteOldNotifications(ctx context.Context) error {
|
// func (s *Service) DeleteOldNotifications(ctx context.Context) error {
|
||||||
return s.store.DeleteOldNotifications(ctx)
|
// return s.store.DeleteOldNotifications(ctx)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// func (s *Service) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error){
|
// func (s *Service) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error){
|
||||||
// return s.store.Get(ctx, filter)
|
// return s.store.Get(ctx, filter)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package referralservice
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "context"
|
|
||||||
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type ReferralStore interface {
|
|
||||||
// GenerateReferralCode() (string, error)
|
|
||||||
// CreateReferral(ctx context.Context, userID int64, companyID int64) error
|
|
||||||
// ProcessReferral(ctx context.Context, referredPhone, referralCode string, companyID int64) error
|
|
||||||
// ProcessDepositBonus(ctx context.Context, userPhone string, amount float64) error
|
|
||||||
// ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error
|
|
||||||
// GetReferralStats(ctx context.Context, userID int64, companyID int64) (*domain.ReferralStats, error)
|
|
||||||
// GetReferralCountByID(ctx context.Context, referrerID int64) (int64, error)
|
|
||||||
// }
|
|
||||||
|
|
@ -1,260 +0,0 @@
|
||||||
package referralservice
|
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/config"
|
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
"Yimaru-Backend/internal/ports"
|
|
||||||
"Yimaru-Backend/internal/services/settings"
|
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base32"
|
|
||||||
"errors"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
repo ports.ReferralStore
|
|
||||||
settingSvc settings.Service
|
|
||||||
config *config.Config
|
|
||||||
logger *slog.Logger
|
|
||||||
mongoLogger *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(
|
|
||||||
repo ports.ReferralStore,
|
|
||||||
settingSvc settings.Service,
|
|
||||||
cfg *config.Config,
|
|
||||||
logger *slog.Logger,
|
|
||||||
mongoLogger *zap.Logger,
|
|
||||||
) *Service {
|
|
||||||
return &Service{
|
|
||||||
repo: repo,
|
|
||||||
settingSvc: settingSvc,
|
|
||||||
config: cfg,
|
|
||||||
logger: logger,
|
|
||||||
mongoLogger: mongoLogger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInvalidReferral = errors.New("invalid or expired referral")
|
|
||||||
ErrUserNotFound = errors.New("user not found")
|
|
||||||
ErrNoReferralFound = errors.New("no referral found for this user")
|
|
||||||
ErrUserAlreadyHasReferralCode = errors.New("user already has an active referral code")
|
|
||||||
ErrMaxReferralCountLimitReached = errors.New("referral count limit has been reached")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Service) GenerateReferralCode() (string, error) {
|
|
||||||
b := make([]byte, 8)
|
|
||||||
if _, err := rand.Read(b); err != nil {
|
|
||||||
s.mongoLogger.Error("Failed to generate random bytes for referral code", zap.Error(err))
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
code := base32.StdEncoding.EncodeToString(b)[:10]
|
|
||||||
s.mongoLogger.Debug("Generated referral code", zap.String("code", code))
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) CreateReferralCode(ctx context.Context, userID int64, companyID int64) (domain.ReferralCode, error) {
|
|
||||||
|
|
||||||
settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, companyID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error("Failed to fetch settings", zap.Error(err))
|
|
||||||
return domain.ReferralCode{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if user already has an active referral code
|
|
||||||
referralCodes, err := s.repo.GetReferralCodesByUser(ctx, userID)
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error("Failed to check if user already has active referral code", zap.Int64("userID", userID), zap.Error(err))
|
|
||||||
return domain.ReferralCode{}, err
|
|
||||||
}
|
|
||||||
if len(referralCodes) != 0 {
|
|
||||||
s.mongoLogger.Error("user already has an active referral code", zap.Int64("userID", userID), zap.Any("codes", referralCodes), zap.Error(err))
|
|
||||||
return domain.ReferralCode{}, ErrUserAlreadyHasReferralCode
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err := s.GenerateReferralCode()
|
|
||||||
if err != nil {
|
|
||||||
return domain.ReferralCode{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newReferralCode, err := s.repo.CreateReferralCode(ctx, domain.CreateReferralCode{
|
|
||||||
ReferrerID: userID,
|
|
||||||
ReferralCode: code,
|
|
||||||
CompanyID: companyID,
|
|
||||||
NumberOfReferrals: settingsList.DefaultMaxReferrals,
|
|
||||||
RewardAmount: settingsList.ReferralRewardAmount,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return domain.ReferralCode{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newReferralCode, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) ProcessReferral(ctx context.Context, referredID int64, referralCode string, companyID int64) error {
|
|
||||||
paramLogger := s.mongoLogger.With(
|
|
||||||
zap.Int64("referredID", referredID),
|
|
||||||
zap.String("referralCode", referralCode),
|
|
||||||
zap.Int64("companyID", companyID),
|
|
||||||
)
|
|
||||||
referral, err := s.repo.GetReferralCode(ctx, referralCode)
|
|
||||||
if err != nil {
|
|
||||||
paramLogger.Error("Failed to get referral by code", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// wallets, err := s.walletSvc.GetCustomerWallet(ctx, referral.ReferrerID)
|
|
||||||
// if err != nil {
|
|
||||||
// paramLogger.Error("Failed to get referrer wallets", zap.Error(err))
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID,
|
|
||||||
// referral.RewardAmount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
|
||||||
// fmt.Sprintf("Added %v to static wallet due to %v referral code being used", referral.RewardAmount, referral.ReferralCode),
|
|
||||||
// )
|
|
||||||
// if err != nil {
|
|
||||||
// paramLogger.Error("Failed to add referral reward to static wallet", zap.Int64("static_wallet_id", wallets.StaticID), zap.Error(err))
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
_, err = s.repo.CreateUserReferral(ctx, domain.CreateUserReferrals{
|
|
||||||
ReferredID: referredID,
|
|
||||||
ReferralCodeID: referral.ID,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
paramLogger.Error("Failed to create user referral", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
paramLogger.Info("Referral processed successfully", zap.String("rewardAmount", referral.ReferralCode))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetReferralStats(ctx context.Context, userID int64, companyID int64) (domain.ReferralStats, error) {
|
|
||||||
paramLogger := s.mongoLogger.With(zap.Int64("userID", userID), zap.Int64("companyID", companyID))
|
|
||||||
|
|
||||||
stats, err := s.repo.GetReferralStats(ctx, userID, companyID)
|
|
||||||
if err != nil {
|
|
||||||
paramLogger.Error("Failed to get referral stats", zap.Error(err))
|
|
||||||
return domain.ReferralStats{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return stats, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetUserReferralCount(ctx context.Context, referrerID int64) (int64, error) {
|
|
||||||
count, err := s.repo.GetUserReferralCount(ctx, referrerID)
|
|
||||||
if err != nil {
|
|
||||||
s.mongoLogger.Error("Failed to get referral count", zap.Int64("referrerID", referrerID), zap.Error(err))
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetReferralCodesByUser(ctx context.Context, userID int64) ([]domain.ReferralCode, error) {
|
|
||||||
return s.repo.GetReferralCodesByUser(ctx, userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetReferralCode(ctx context.Context, code string) (domain.ReferralCode, error) {
|
|
||||||
return s.repo.GetReferralCode(ctx, code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) UpdateReferralCode(ctx context.Context, referral domain.UpdateReferralCode) error {
|
|
||||||
return s.repo.UpdateReferralCode(ctx, referral)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetUserReferral(ctx context.Context, referrerID int64) (domain.UserReferral, error) {
|
|
||||||
return s.repo.GetUserReferral(ctx, referrerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetUserReferralsByCode(ctx context.Context, code string) ([]domain.UserReferral, error) {
|
|
||||||
return s.repo.GetUserReferralsByCode(ctx, code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (s *Service) ProcessDepositBonus(ctx context.Context, userID int64, amount float32, companyID int64) error {
|
|
||||||
// settingsList, err := s.settingSvc.GetOverrideSettingsList(ctx, companyID)
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to fetch settings", "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// s.logger.Info("Processing deposit bonus", "amount", amount)
|
|
||||||
|
|
||||||
// customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, userID)
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to get wallets for user", "userID", userID, "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bonus := amount * settingsList.CashbackPercentage
|
|
||||||
|
|
||||||
// _, err = s.walletSvc.AddToWallet(ctx, customerWallet.StaticID, domain.ToCurrency(bonus), domain.ValidInt64{},
|
|
||||||
// domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
|
||||||
// fmt.Sprintf("Added to bonus wallet because of Deposit Cashback Bonus %d", bonus))
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to add deposit bonus to wallet", "staticWalletID", customerWallet.StaticID, "userID", userID, "bonus", bonus, "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// s.logger.Info("Deposit bonus processed successfully", "bonus", bonus)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (s *Service) ProcessBetReferral(ctx context.Context, userId int64, betAmount float64) error {
|
|
||||||
// s.logger.Info("Processing bet referral", "userID", userId, "betAmount", betAmount)
|
|
||||||
|
|
||||||
// settings, err := s.repo.GetSettings(ctx)
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to get referral settings", "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// referral, err := s.repo.GetReferralByReferredID(ctx, userId)
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to get referral by referred ID", "userId", userId, "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if referral == nil || referral.Status != domain.ReferralCompleted {
|
|
||||||
// s.logger.Warn("No valid referral found", "userId", userId, "status", referral.Status)
|
|
||||||
// return ErrNoReferralFound
|
|
||||||
// }
|
|
||||||
|
|
||||||
// wallets, err := s.walletSvc.GetWalletsByUser(ctx, referral.ReferrerID)
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to get wallets for referrer", "referrerID", referral.ReferrerID, "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if len(wallets) == 0 {
|
|
||||||
// s.logger.Error("Referrer has no wallet", "referrerID", referral.ReferrerID)
|
|
||||||
// return errors.New("referrer has no wallet")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bonusPercentage := settings.BetReferralBonusPercentage
|
|
||||||
// if bonusPercentage == 0 {
|
|
||||||
// bonusPercentage = 5.0
|
|
||||||
// s.logger.Debug("Using default bet referral bonus percentage", "percentage", bonusPercentage)
|
|
||||||
// }
|
|
||||||
// bonus := betAmount * (bonusPercentage / 100)
|
|
||||||
|
|
||||||
// walletID := wallets[0].ID
|
|
||||||
// currentBalance := float64(wallets[0].Balance)
|
|
||||||
// _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBalance+bonus)), domain.ValidInt64{},
|
|
||||||
// domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
|
||||||
// fmt.Sprintf("Added %v to static wallet because of bet referral", referral.RewardAmount))
|
|
||||||
// if err != nil {
|
|
||||||
// s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referral.ReferrerID, "bonus", bonus, "error", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// s.logger.Info("Bet referral processed successfully", "referrer ID", referral.ReferrerID, "referrerID", referral.ReferrerID, "bonus", bonus)
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
@ -35,29 +35,29 @@ func (s *Service) UpdateGlobalSettingList(ctx context.Context, settingList domai
|
||||||
return s.settingStore.UpdateGlobalSettingList(ctx, settingList)
|
return s.settingStore.UpdateGlobalSettingList(ctx, settingList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error {
|
// func (s *Service) InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error {
|
||||||
return s.settingStore.InsertCompanySetting(ctx, key, value, companyID)
|
// return s.settingStore.InsertCompanySetting(ctx, key, value, companyID)
|
||||||
}
|
// }
|
||||||
func (s *Service) InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error {
|
// func (s *Service) InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error {
|
||||||
return s.settingStore.InsertCompanySettingList(ctx, settingList, companyID)
|
// return s.settingStore.InsertCompanySettingList(ctx, settingList, companyID)
|
||||||
}
|
// }
|
||||||
func (s *Service) GetAllCompanySettings(ctx context.Context) ([]domain.CompanySetting, error) {
|
// func (s *Service) GetAllCompanySettings(ctx context.Context) ([]domain.CompanySetting, error) {
|
||||||
return s.settingStore.GetAllCompanySettings(ctx)
|
// return s.settingStore.GetAllCompanySettings(ctx)
|
||||||
}
|
// }
|
||||||
func (s *Service) GetCompanySettingsByKey(ctx context.Context, key string) ([]domain.CompanySetting, error) {
|
// func (s *Service) GetCompanySettingsByKey(ctx context.Context, key string) ([]domain.CompanySetting, error) {
|
||||||
return s.settingStore.GetCompanySettingsByKey(ctx, key)
|
// return s.settingStore.GetCompanySettingsByKey(ctx, key)
|
||||||
}
|
// }
|
||||||
func (s *Service) GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error) {
|
// func (s *Service) GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error) {
|
||||||
return s.settingStore.GetOverrideSettings(ctx, companyID)
|
// return s.settingStore.GetOverrideSettings(ctx, companyID)
|
||||||
}
|
// }
|
||||||
func (s *Service) GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) {
|
// func (s *Service) GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) {
|
||||||
return s.settingStore.GetOverrideSettingsList(ctx, companyID)
|
// return s.settingStore.GetOverrideSettingsList(ctx, companyID)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
|
// func (s *Service) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
|
||||||
return s.settingStore.DeleteCompanySetting(ctx, companyID, key)
|
// return s.settingStore.DeleteCompanySetting(ctx, companyID, key)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
|
// func (s *Service) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
|
||||||
return s.settingStore.DeleteAllCompanySetting(ctx, companyID)
|
// return s.settingStore.DeleteAllCompanySetting(ctx, companyID)
|
||||||
}
|
// }
|
||||||
|
|
|
||||||
|
|
@ -134,39 +134,41 @@ func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role dom
|
||||||
// var companyID int64
|
// var companyID int64
|
||||||
|
|
||||||
switch role {
|
switch role {
|
||||||
case domain.RoleAdmin, domain.RoleBranchManager, domain.RoleSuperAdmin:
|
case domain.RoleAdmin, domain.RoleSuperAdmin:
|
||||||
if branchID == nil {
|
if branchID == nil {
|
||||||
// h.logger.Error("CashoutReq Branch ID is required for this user role")
|
// h.logger.Error("CashoutReq Branch ID is required for this user role")
|
||||||
return nil, nil, ErrBranchRequiredForRole
|
return nil, nil, ErrBranchRequiredForRole
|
||||||
}
|
}
|
||||||
branch, err := s.branchSvc.GetBranchByID(ctx, *branchID)
|
// branch, err := s.branchSvc.GetBranchByID(ctx, *branchID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
// h.logger.Error("CashoutReq no branches")
|
// // h.logger.Error("CashoutReq no branches")
|
||||||
return nil, nil, err
|
// return nil, nil, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Check if the user has access to the company
|
// Check if the user has access to the company
|
||||||
if role != domain.RoleSuperAdmin {
|
if role != domain.RoleSuperAdmin {
|
||||||
if userCompanyID.Valid && userCompanyID.Value != branch.CompanyID {
|
// if userCompanyID.Valid && userCompanyID.Value != branch.CompanyID {
|
||||||
return nil, nil, ErrUnauthorizedCompanyID
|
// return nil, nil, ErrUnauthorizedCompanyID
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
if role == domain.RoleBranchManager {
|
// if role == domain.RoleBranchManager {
|
||||||
if branch.BranchManagerID != userID {
|
// // if branch.BranchManagerID != userID {
|
||||||
return nil, nil, ErrUnauthorizedBranchManager
|
// // return nil, nil, ErrUnauthorizedBranchManager
|
||||||
}
|
// // }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return &branch.ID, &branch.CompanyID, nil
|
// return &branch.ID, &branch.CompanyID, nil
|
||||||
case domain.RoleCashier:
|
case domain.RoleInstructor:
|
||||||
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
// branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
// h.logger.Error("CashoutReq failed, branch id invalid")
|
// // h.logger.Error("CashoutReq failed, branch id invalid")
|
||||||
return nil, nil, ErrInvalidBranchID
|
// return nil, nil, ErrInvalidBranchID
|
||||||
}
|
// }
|
||||||
return &branch.ID, &branch.CompanyID, nil
|
// return &branch.ID, &branch.CompanyID, nil
|
||||||
default:
|
default:
|
||||||
return nil, nil, ErrCustomerRoleNotAuthorized
|
return nil, nil, ErrCustomerRoleNotAuthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil, nil, ErrCustomerRoleNotAuthorized
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
func (s *Service) SendOtp(ctx context.Context, sentTo string, otpFor domain.OtpFor, medium domain.OtpMedium, provider domain.SMSProvider) error {
|
func (s *Service) SendOtp(ctx context.Context, sentTo string, otpFor domain.OtpFor, medium domain.OtpMedium, provider domain.SMSProvider) error {
|
||||||
otpCode := helpers.GenerateOTP()
|
otpCode := helpers.GenerateOTP()
|
||||||
|
|
||||||
message := fmt.Sprintf("Welcome to Fortune bets, your OTP is %s please don't share with anyone.", otpCode)
|
message := fmt.Sprintf("Welcome to Yimaru Online Learning Platform, your OTP is %s please don't share with anyone.", otpCode)
|
||||||
|
|
||||||
switch medium {
|
switch medium {
|
||||||
case domain.OtpMediumSms:
|
case domain.OtpMediumSms:
|
||||||
|
|
@ -31,7 +31,7 @@ func (s *Service) SendOtp(ctx context.Context, sentTo string, otpFor domain.OtpF
|
||||||
return fmt.Errorf("invalid sms provider: %s", provider)
|
return fmt.Errorf("invalid sms provider: %s", provider)
|
||||||
}
|
}
|
||||||
case domain.OtpMediumEmail:
|
case domain.OtpMediumEmail:
|
||||||
if err := s.messengerSvc.SendEmail(ctx, sentTo, message, message, "FortuneBets - One Time Password"); err != nil {
|
if err := s.messengerSvc.SendEmail(ctx, sentTo, message, message, "Yimaru - One Time Password"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,17 +25,17 @@ func (s *Service) CreateUser(ctx context.Context, User domain.CreateUserReq, is_
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.userStore.CreateUserWithoutOtp(ctx, domain.User{
|
return s.userStore.CreateUserWithoutOtp(ctx, domain.User{
|
||||||
FirstName: User.FirstName,
|
FirstName: User.FirstName,
|
||||||
LastName: User.LastName,
|
LastName: User.LastName,
|
||||||
Email: User.Email,
|
Email: User.Email,
|
||||||
PhoneNumber: User.PhoneNumber,
|
PhoneNumber: User.PhoneNumber,
|
||||||
Password: hashedPassword,
|
Password: hashedPassword,
|
||||||
Role: domain.Role(User.Role),
|
Role: domain.Role(User.Role),
|
||||||
EmailVerified: true,
|
EmailVerified: true,
|
||||||
PhoneVerified: true,
|
PhoneVerified: true,
|
||||||
Suspended: User.Suspended,
|
Suspended: User.Suspended,
|
||||||
CompanyID: User.CompanyID,
|
OrganizationID: User.OrganizationID,
|
||||||
}, is_company)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) DeleteUser(ctx context.Context, id int64) error {
|
func (s *Service) DeleteUser(ctx context.Context, id int64) error {
|
||||||
|
|
@ -45,24 +45,9 @@ func (s *Service) DeleteUser(ctx context.Context, id int64) error {
|
||||||
|
|
||||||
func (s *Service) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
|
func (s *Service) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
|
||||||
// Get all Users
|
// Get all Users
|
||||||
return s.userStore.GetAllUsers(ctx, filter)
|
return s.userStore.GetAllUsers(ctx, &filter.Role, &filter.OrganizationID.Value, &filter.Query.Value, &filter.CreatedBefore.Value, &filter.CreatedAfter.Value, int32(filter.PageSize.Value), int32(filter.Page.Value))
|
||||||
}
|
}
|
||||||
func (s *Service) GetUserById(ctx context.Context, id int64) (domain.User, error) {
|
func (s *Service) GetUserById(ctx context.Context, id int64) (domain.User, error) {
|
||||||
|
|
||||||
return s.userStore.GetUserByID(ctx, id)
|
return s.userStore.GetUserByID(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) {
|
|
||||||
return s.userStore.GetCashiersByBranch(ctx, branchID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetAdminByCompanyID(ctx context.Context, companyID int64) (domain.User, error) {
|
|
||||||
return s.userStore.GetAdminByCompanyID(ctx, companyID)
|
|
||||||
}
|
|
||||||
func (s *Service) GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([]domain.GetCashier, int64, error) {
|
|
||||||
return s.userStore.GetAllCashiers(ctx, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) {
|
|
||||||
return s.userStore.GetCashierByID(ctx, cashierID)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,15 @@ import (
|
||||||
func (s *Service) CheckPhoneEmailExist(ctx context.Context, phoneNum, email string, companyID domain.ValidInt64) (bool, bool, error) { // email,phone,error
|
func (s *Service) CheckPhoneEmailExist(ctx context.Context, phoneNum, email string, companyID domain.ValidInt64) (bool, bool, error) { // email,phone,error
|
||||||
return s.userStore.CheckPhoneEmailExist(ctx, phoneNum, email, companyID)
|
return s.userStore.CheckPhoneEmailExist(ctx, phoneNum, email, companyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SendRegisterCode(ctx context.Context, medium domain.OtpMedium, sentTo string, provider domain.SMSProvider, companyID domain.ValidInt64) error {
|
func (s *Service) SendRegisterCode(ctx context.Context, medium domain.OtpMedium, sentTo string, provider domain.SMSProvider, companyID domain.ValidInt64) error {
|
||||||
var err error
|
var err error
|
||||||
// check if user exists
|
// check if user exists
|
||||||
switch medium {
|
switch medium {
|
||||||
case domain.OtpMediumEmail:
|
case domain.OtpMediumEmail:
|
||||||
_, err = s.userStore.GetUserByEmail(ctx, sentTo, companyID)
|
_, err = s.userStore.GetUserByEmailPhone(ctx, sentTo, "", companyID)
|
||||||
case domain.OtpMediumSms:
|
case domain.OtpMediumSms:
|
||||||
_, err = s.userStore.GetUserByPhone(ctx, sentTo, companyID)
|
_, err = s.userStore.GetUserByEmailPhone(ctx, "", sentTo, companyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && err != domain.ErrUserNotFound {
|
if err != nil && err != domain.ErrUserNotFound {
|
||||||
|
|
@ -27,6 +28,7 @@ func (s *Service) SendRegisterCode(ctx context.Context, medium domain.OtpMedium,
|
||||||
// send otp based on the medium
|
// send otp based on the medium
|
||||||
return s.SendOtp(ctx, sentTo, domain.OtpRegister, medium, provider)
|
return s.SendOtp(ctx, sentTo, domain.OtpRegister, medium, provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterUserReq) (domain.User, error) { // normal
|
func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterUserReq) (domain.User, error) { // normal
|
||||||
// get otp
|
// get otp
|
||||||
|
|
||||||
|
|
@ -59,18 +61,18 @@ func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterU
|
||||||
return domain.User{}, err
|
return domain.User{}, err
|
||||||
}
|
}
|
||||||
userR := domain.User{
|
userR := domain.User{
|
||||||
FirstName: registerReq.FirstName,
|
FirstName: registerReq.FirstName,
|
||||||
LastName: registerReq.LastName,
|
LastName: registerReq.LastName,
|
||||||
Email: registerReq.Email,
|
Email: registerReq.Email,
|
||||||
PhoneNumber: registerReq.PhoneNumber,
|
PhoneNumber: registerReq.PhoneNumber,
|
||||||
Password: hashedPassword,
|
Password: hashedPassword,
|
||||||
Role: domain.RoleCustomer,
|
Role: domain.RoleStudent,
|
||||||
EmailVerified: registerReq.OtpMedium == domain.OtpMediumEmail,
|
EmailVerified: registerReq.OtpMedium == domain.OtpMediumEmail,
|
||||||
PhoneVerified: registerReq.OtpMedium == domain.OtpMediumSms,
|
PhoneVerified: registerReq.OtpMedium == domain.OtpMediumSms,
|
||||||
CompanyID: registerReq.CompanyID,
|
OrganizationID: registerReq.OrganizationID,
|
||||||
}
|
}
|
||||||
// create the user and mark otp as used
|
// create the user and mark otp as used
|
||||||
user, err := s.userStore.CreateUser(ctx, userR, otp.ID, false)
|
user, err := s.userStore.CreateUser(ctx, userR, otp.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.User{}, err
|
return domain.User{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ func (s *Service) SendResetCode(ctx context.Context, medium domain.OtpMedium, se
|
||||||
// check if user exists
|
// check if user exists
|
||||||
switch medium {
|
switch medium {
|
||||||
case domain.OtpMediumEmail:
|
case domain.OtpMediumEmail:
|
||||||
_, err = s.userStore.GetUserByEmail(ctx, sentTo, companyID)
|
_, err = s.userStore.GetUserByEmailPhone(ctx, sentTo, "", companyID)
|
||||||
case domain.OtpMediumSms:
|
case domain.OtpMediumSms:
|
||||||
_, err = s.userStore.GetUserByPhone(ctx, sentTo, companyID)
|
_, err = s.userStore.GetUserByEmailPhone(ctx, "", sentTo, companyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -51,13 +51,13 @@ func (s *Service) ResetPassword(ctx context.Context, resetReq domain.ResetPasswo
|
||||||
return domain.ErrInvalidOtp
|
return domain.ErrInvalidOtp
|
||||||
}
|
}
|
||||||
// hash password
|
// hash password
|
||||||
hashedPassword, err := hashPassword(resetReq.Password)
|
// hashedPassword, err := hashPassword(resetReq.Password)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
// reset pass and mark otp as used
|
// reset pass and mark otp as used
|
||||||
|
|
||||||
err = s.userStore.UpdatePassword(ctx, sentTo, hashedPassword, otp.ID, resetReq.CompanyID)
|
err = s.userStore.UpdatePassword(ctx, resetReq.Password, resetReq.Email, resetReq.PhoneNumber, resetReq.OrganizationID, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,34 @@ import (
|
||||||
"context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) SearchUserByNameOrPhone(ctx context.Context, searchString string, role *domain.Role, companyID domain.ValidInt64) ([]domain.User, error) {
|
func (s *Service) SearchUserByNameOrPhone(ctx context.Context, searchString string, role *int64, companyID *string) ([]domain.User, error) {
|
||||||
// Search user
|
// Search user
|
||||||
return s.userStore.SearchUserByNameOrPhone(ctx, searchString, role, companyID)
|
return s.userStore.SearchUserByNameOrPhone(ctx, searchString, role, companyID)
|
||||||
|
|
||||||
}
|
}
|
||||||
func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
||||||
// update user
|
// update user
|
||||||
return s.userStore.UpdateUser(ctx, user)
|
|
||||||
|
newUser := domain.User{
|
||||||
|
ID: user.UserID,
|
||||||
|
FirstName: user.FirstName.Value,
|
||||||
|
LastName: user.LastName.Value,
|
||||||
|
NickName: user.NickName.Value,
|
||||||
|
Age: user.Age.Value,
|
||||||
|
EducationLevel: user.EducationLevel.Value,
|
||||||
|
Country: user.Country.Value,
|
||||||
|
Region: user.Region.Value,
|
||||||
|
Suspended: user.Suspended.Value,
|
||||||
|
OrganizationID: user.OrganizationID,
|
||||||
|
}
|
||||||
|
return s.userStore.UpdateUser(ctx, newUser)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error {
|
// func (s *Service) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error {
|
||||||
// update user
|
// // update user
|
||||||
return s.userStore.UpdateUserCompany(ctx, id, companyID)
|
// return s.userStore.UpdateUserCompany(ctx, id, companyID)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (s *Service) UpdateUserSuspend(ctx context.Context, id int64, status bool) error {
|
func (s *Service) UpdateUserSuspend(ctx context.Context, id int64, status bool) error {
|
||||||
// update user
|
// update user
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ import (
|
||||||
"Yimaru-Backend/internal/config"
|
"Yimaru-Backend/internal/config"
|
||||||
"Yimaru-Backend/internal/services/arifpay"
|
"Yimaru-Backend/internal/services/arifpay"
|
||||||
"Yimaru-Backend/internal/services/authentication"
|
"Yimaru-Backend/internal/services/authentication"
|
||||||
|
issuereporting "Yimaru-Backend/internal/services/issue_reporting"
|
||||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||||
"Yimaru-Backend/internal/services/recommendation"
|
"Yimaru-Backend/internal/services/recommendation"
|
||||||
referralservice "Yimaru-Backend/internal/services/referal"
|
|
||||||
"Yimaru-Backend/internal/services/settings"
|
"Yimaru-Backend/internal/services/settings"
|
||||||
"Yimaru-Backend/internal/services/transaction"
|
"Yimaru-Backend/internal/services/transaction"
|
||||||
"Yimaru-Backend/internal/services/user"
|
"Yimaru-Backend/internal/services/user"
|
||||||
|
|
@ -23,60 +24,36 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
// directDepositSvc *directdeposit.Service
|
arifpaySvc *arifpay.ArifpayService
|
||||||
// telebirrSvc *telebirr.TelebirrService
|
issueReportingSvc *issuereporting.Service
|
||||||
arifpaySvc *arifpay.ArifpayService
|
|
||||||
// santimpaySvc *santimpay.SantimPayService
|
|
||||||
// issueReportingSvc *issuereporting.Service
|
|
||||||
// instSvc *institutions.Service
|
|
||||||
// currSvc *currency.Service
|
|
||||||
fiber *fiber.App
|
fiber *fiber.App
|
||||||
recommendationSvc recommendation.RecommendationService
|
recommendationSvc recommendation.RecommendationService
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
NotidicationStore *notificationservice.Service
|
NotidicationStore *notificationservice.Service
|
||||||
referralSvc *referralservice.Service
|
port int
|
||||||
// raffleSvc *raffle.Service
|
settingSvc *settings.Service
|
||||||
// bonusSvc *bonus.Service
|
authSvc *authentication.Service
|
||||||
port int
|
userSvc *user.Service
|
||||||
settingSvc *settings.Service
|
transactionSvc *transaction.Service
|
||||||
authSvc *authentication.Service
|
validator *customvalidator.CustomValidator
|
||||||
userSvc *user.Service
|
JwtConfig jwtutil.JwtConfig
|
||||||
// chapaSvc *chapa.Service
|
Logger *slog.Logger
|
||||||
transactionSvc *transaction.Service
|
mongoLoggerSvc *zap.Logger
|
||||||
// branchSvc *branch.Service
|
|
||||||
// companySvc *company.Service
|
|
||||||
validator *customvalidator.CustomValidator
|
|
||||||
JwtConfig jwtutil.JwtConfig
|
|
||||||
Logger *slog.Logger
|
|
||||||
// statSvc *stats.Service
|
|
||||||
mongoLoggerSvc *zap.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApp(
|
func NewApp(
|
||||||
// directDepositSvc *directdeposit.Service,
|
|
||||||
// telebirrSvc *telebirr.TelebirrService,
|
|
||||||
arifpaySvc *arifpay.ArifpayService,
|
arifpaySvc *arifpay.ArifpayService,
|
||||||
// santimpaySvc *santimpay.SantimPayService,
|
issueReportingSvc *issuereporting.Service,
|
||||||
// issueReportingSvc *issuereporting.Service,
|
|
||||||
// instSvc *institutions.Service,
|
|
||||||
// currSvc *currency.Service,
|
|
||||||
port int, validator *customvalidator.CustomValidator,
|
port int, validator *customvalidator.CustomValidator,
|
||||||
settingSvc *settings.Service,
|
settingSvc *settings.Service,
|
||||||
authSvc *authentication.Service,
|
authSvc *authentication.Service,
|
||||||
logger *slog.Logger,
|
logger *slog.Logger,
|
||||||
JwtConfig jwtutil.JwtConfig,
|
JwtConfig jwtutil.JwtConfig,
|
||||||
userSvc *user.Service,
|
userSvc *user.Service,
|
||||||
// chapaSvc *chapa.Service,
|
|
||||||
transactionSvc *transaction.Service,
|
transactionSvc *transaction.Service,
|
||||||
// branchSvc *branch.Service,
|
|
||||||
// companySvc *company.Service,
|
|
||||||
notidicationStore *notificationservice.Service,
|
notidicationStore *notificationservice.Service,
|
||||||
referralSvc *referralservice.Service,
|
|
||||||
// raffleSvc *raffle.Service,
|
|
||||||
// bonusSvc *bonus.Service,
|
|
||||||
recommendationSvc recommendation.RecommendationService,
|
recommendationSvc recommendation.RecommendationService,
|
||||||
// statSvc *stats.Service,
|
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
mongoLoggerSvc *zap.Logger,
|
mongoLoggerSvc *zap.Logger,
|
||||||
) *App {
|
) *App {
|
||||||
|
|
@ -97,35 +74,22 @@ func NewApp(
|
||||||
app.Static("/static", "./static")
|
app.Static("/static", "./static")
|
||||||
|
|
||||||
s := &App{
|
s := &App{
|
||||||
// directDepositSvc: directDepositSvc,
|
arifpaySvc: arifpaySvc,
|
||||||
// telebirrSvc: telebirrSvc,
|
|
||||||
arifpaySvc: arifpaySvc,
|
|
||||||
// santimpaySvc: santimpaySvc,
|
|
||||||
// issueReportingSvc: issueReportingSvc,
|
// issueReportingSvc: issueReportingSvc,
|
||||||
// instSvc: instSvc,
|
fiber: app,
|
||||||
// currSvc: currSvc,
|
port: port,
|
||||||
fiber: app,
|
settingSvc: settingSvc,
|
||||||
port: port,
|
authSvc: authSvc,
|
||||||
settingSvc: settingSvc,
|
validator: validator,
|
||||||
authSvc: authSvc,
|
logger: logger,
|
||||||
validator: validator,
|
JwtConfig: JwtConfig,
|
||||||
logger: logger,
|
userSvc: userSvc,
|
||||||
JwtConfig: JwtConfig,
|
transactionSvc: transactionSvc,
|
||||||
userSvc: userSvc,
|
|
||||||
// ticketSvc: ticketSvc,
|
|
||||||
// chapaSvc: chapaSvc,
|
|
||||||
transactionSvc: transactionSvc,
|
|
||||||
// branchSvc: branchSvc,
|
|
||||||
// companySvc: companySvc,
|
|
||||||
NotidicationStore: notidicationStore,
|
NotidicationStore: notidicationStore,
|
||||||
referralSvc: referralSvc,
|
|
||||||
// raffleSvc: raffleSvc,
|
|
||||||
// bonusSvc: bonusSvc,
|
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
recommendationSvc: recommendationSvc,
|
recommendationSvc: recommendationSvc,
|
||||||
// statSvc: statSvc,
|
cfg: cfg,
|
||||||
cfg: cfg,
|
mongoLoggerSvc: mongoLoggerSvc,
|
||||||
mongoLoggerSvc: mongoLoggerSvc,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.initAppRoutes()
|
s.initAppRoutes()
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateAdminReq struct {
|
type CreateAdminReq struct {
|
||||||
FirstName string `json:"first_name" example:"John"`
|
FirstName string `json:"first_name" example:"John"`
|
||||||
LastName string `json:"last_name" example:"Doe"`
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
Email string `json:"email" example:"john.doe@example.com"`
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
Password string `json:"password" example:"password123"`
|
Password string `json:"password" example:"password123"`
|
||||||
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
|
OrganizationID *int64 `json:"company_id,omitempty" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAdmin godoc
|
// CreateAdmin godoc
|
||||||
|
|
@ -34,7 +34,7 @@ type CreateAdminReq struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/admin [post]
|
// @Router /api/v1/admin [post]
|
||||||
func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
||||||
var companyID domain.ValidInt64
|
var OrganizationID domain.ValidInt64
|
||||||
var req CreateAdminReq
|
var req CreateAdminReq
|
||||||
|
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
@ -60,36 +60,36 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.CompanyID == nil {
|
if req.OrganizationID == nil {
|
||||||
companyID = domain.ValidInt64{
|
OrganizationID = domain.ValidInt64{
|
||||||
Value: 0,
|
Value: 0,
|
||||||
Valid: false,
|
Valid: false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// _, err := h.companySvc.GetCompanyByID(c.Context(), *req.CompanyID)
|
// _, err := h.companySvc.GetCompanyByID(c.Context(), *req.OrganizationID)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
// h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
||||||
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||||
// zap.Int64("company_id", *req.CompanyID),
|
// zap.Int64("company_id", *req.OrganizationID),
|
||||||
// zap.Error(err),
|
// zap.Error(err),
|
||||||
// zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
// )
|
// )
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
||||||
// }
|
// }
|
||||||
companyID = domain.ValidInt64{
|
OrganizationID = domain.ValidInt64{
|
||||||
Value: *req.CompanyID,
|
Value: *req.OrganizationID,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user := domain.CreateUserReq{
|
user := domain.CreateUserReq{
|
||||||
FirstName: req.FirstName,
|
FirstName: req.FirstName,
|
||||||
LastName: req.LastName,
|
LastName: req.LastName,
|
||||||
Email: req.Email,
|
Email: req.Email,
|
||||||
PhoneNumber: req.PhoneNumber,
|
PhoneNumber: req.PhoneNumber,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Role: string(domain.RoleAdmin),
|
Role: string(domain.RoleAdmin),
|
||||||
CompanyID: companyID,
|
OrganizationID: OrganizationID,
|
||||||
}
|
}
|
||||||
|
|
||||||
newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||||
|
|
@ -103,9 +103,9 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// if req.CompanyID != nil {
|
// if req.OrganizationID != nil {
|
||||||
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
|
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
|
||||||
// ID: *req.CompanyID,
|
// ID: *req.OrganizationID,
|
||||||
// AdminID: domain.ValidInt64{
|
// AdminID: domain.ValidInt64{
|
||||||
// Value: newUser.ID,
|
// Value: newUser.ID,
|
||||||
// Valid: true,
|
// Valid: true,
|
||||||
|
|
@ -114,7 +114,7 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// h.mongoLoggerSvc.Error("failed to update company with new admin",
|
// h.mongoLoggerSvc.Error("failed to update company with new admin",
|
||||||
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||||
// zap.Int64("company_id", *req.CompanyID),
|
// zap.Int64("company_id", *req.OrganizationID),
|
||||||
// zap.Int64("admin_id", newUser.ID),
|
// zap.Int64("admin_id", newUser.ID),
|
||||||
// zap.Error(err),
|
// zap.Error(err),
|
||||||
// zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
|
|
@ -200,7 +200,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
|
||||||
companyFilter := int64(c.QueryInt("company_id"))
|
companyFilter := int64(c.QueryInt("company_id"))
|
||||||
filter := domain.UserFilter{
|
filter := domain.UserFilter{
|
||||||
Role: string(domain.RoleAdmin),
|
Role: string(domain.RoleAdmin),
|
||||||
CompanyID: domain.ValidInt64{
|
OrganizationID: domain.ValidInt64{
|
||||||
Value: companyFilter,
|
Value: companyFilter,
|
||||||
Valid: companyFilter != 0,
|
Valid: companyFilter != 0,
|
||||||
},
|
},
|
||||||
|
|
@ -362,10 +362,10 @@ func (h *Handler) GetAdminByID(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateAdminReq struct {
|
type updateAdminReq struct {
|
||||||
FirstName string `json:"first_name" example:"John"`
|
FirstName string `json:"first_name" example:"John"`
|
||||||
LastName string `json:"last_name" example:"Doe"`
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
Suspended bool `json:"suspended" example:"false"`
|
Suspended bool `json:"suspended" example:"false"`
|
||||||
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
|
OrganizationID *int64 `json:"company_id,omitempty" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAdmin godoc
|
// UpdateAdmin godoc
|
||||||
|
|
@ -417,16 +417,16 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Admin ID")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid Admin ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
var companyID domain.ValidInt64
|
var OrganizationID domain.ValidInt64
|
||||||
if req.CompanyID != nil {
|
if req.OrganizationID != nil {
|
||||||
companyID = domain.ValidInt64{
|
OrganizationID = domain.ValidInt64{
|
||||||
Value: *req.CompanyID,
|
Value: *req.OrganizationID,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
UserId: AdminID,
|
UserID: AdminID,
|
||||||
FirstName: domain.ValidString{
|
FirstName: domain.ValidString{
|
||||||
Value: req.FirstName,
|
Value: req.FirstName,
|
||||||
Valid: req.FirstName != "",
|
Valid: req.FirstName != "",
|
||||||
|
|
@ -439,7 +439,7 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
|
||||||
Value: req.Suspended,
|
Value: req.Suspended,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
},
|
},
|
||||||
CompanyID: companyID,
|
OrganizationID: OrganizationID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("UpdateAdmin failed - user service error",
|
h.mongoLoggerSvc.Error("UpdateAdmin failed - user service error",
|
||||||
|
|
@ -451,9 +451,9 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// if req.CompanyID != nil {
|
// if req.OrganizationID != nil {
|
||||||
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
|
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
|
||||||
// ID: *req.CompanyID,
|
// ID: *req.OrganizationID,
|
||||||
// AdminID: domain.ValidInt64{
|
// AdminID: domain.ValidInt64{
|
||||||
// Value: AdminID,
|
// Value: AdminID,
|
||||||
// Valid: true,
|
// Valid: true,
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ type loginCustomerRes struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/customer-login [post]
|
// @Router /api/v1/{tenant_slug}/customer-login [post]
|
||||||
func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
OrganizationID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
if !OrganizationID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password, companyID)
|
successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password, OrganizationID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -95,7 +95,7 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if successRes.Role != domain.RoleCustomer {
|
if successRes.Role != domain.RoleStudent {
|
||||||
h.mongoLoggerSvc.Info("Login attempt: customer login of other role",
|
h.mongoLoggerSvc.Info("Login attempt: customer login of other role",
|
||||||
zap.Int("status_code", fiber.StatusForbidden),
|
zap.Int("status_code", fiber.StatusForbidden),
|
||||||
zap.String("role", string(successRes.Role)),
|
zap.String("role", string(successRes.Role)),
|
||||||
|
|
@ -167,8 +167,8 @@ type LoginAdminRes struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/admin-login [post]
|
// @Router /api/v1/{tenant_slug}/admin-login [post]
|
||||||
func (h *Handler) LoginAdmin(c *fiber.Ctx) error {
|
func (h *Handler) LoginAdmin(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
OrganizationID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
if !OrganizationID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +190,7 @@ func (h *Handler) LoginAdmin(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password, companyID)
|
successRes, err := h.authSvc.Login(c.Context(), req.Email, req.PhoneNumber, req.Password, OrganizationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, authentication.ErrInvalidPassword), errors.Is(err, authentication.ErrUserNotFound):
|
case errors.Is(err, authentication.ErrInvalidPassword), errors.Is(err, authentication.ErrUserNotFound):
|
||||||
|
|
@ -221,7 +221,7 @@ func (h *Handler) LoginAdmin(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if successRes.Role == domain.RoleCustomer {
|
if successRes.Role == domain.RoleStudent || successRes.Role == domain.RoleInstructor {
|
||||||
h.mongoLoggerSvc.Warn("Login attempt: admin login of customer",
|
h.mongoLoggerSvc.Warn("Login attempt: admin login of customer",
|
||||||
zap.Int("status_code", fiber.StatusForbidden),
|
zap.Int("status_code", fiber.StatusForbidden),
|
||||||
zap.String("role", string(successRes.Role)),
|
zap.String("role", string(successRes.Role)),
|
||||||
|
|
@ -451,7 +451,7 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user information:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user information:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken, err := jwtutil.CreateJwt(user.ID, user.Role, user.CompanyID, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
accessToken, err := jwtutil.CreateJwt(user.ID, user.Role, user.OrganizationID, h.jwtConfig.JwtAccessKey, h.jwtConfig.JwtAccessExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to create new access token",
|
h.mongoLoggerSvc.Error("Failed to create new access token",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
|
|
||||||
|
|
@ -1,456 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
"Yimaru-Backend/internal/services/authentication"
|
|
||||||
"Yimaru-Backend/internal/web_server/response"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CreateCashierReq struct {
|
|
||||||
FirstName string `json:"first_name" example:"John"`
|
|
||||||
LastName string `json:"last_name" example:"Doe"`
|
|
||||||
Email string `json:"email" example:"john.doe@example.com"`
|
|
||||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
|
||||||
Password string `json:"password" example:"password123"`
|
|
||||||
BranchID int64 `json:"branch_id" example:"1"`
|
|
||||||
Suspended bool `json:"suspended" example:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateCashier godoc
|
|
||||||
// @Summary Create cashier
|
|
||||||
// @Description Create cashier
|
|
||||||
// @Tags cashier
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param cashier body CreateCashierReq true "Create cashier"
|
|
||||||
// @Success 200 {object} response.APIResponse
|
|
||||||
// @Failure 400 {object} response.APIResponse
|
|
||||||
// @Failure 401 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Router /api/v1/cashiers [post]
|
|
||||||
func (h *Handler) CreateCashier(c *fiber.Ctx) error {
|
|
||||||
|
|
||||||
// Get user_id from middleware
|
|
||||||
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
|
||||||
|
|
||||||
var req CreateCashierReq
|
|
||||||
if err := c.BodyParser(&req); err != nil {
|
|
||||||
h.mongoLoggerSvc.Info("failed to parse CreateCashier request body",
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
|
||||||
}
|
|
||||||
valErrs, ok := h.validator.Validate(c, req)
|
|
||||||
if !ok {
|
|
||||||
var errMsg string
|
|
||||||
for field, msg := range valErrs {
|
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
|
||||||
}
|
|
||||||
h.mongoLoggerSvc.Info("Failed to validate CreateCashier",
|
|
||||||
zap.Any("request", req),
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cashiers inherit the company id from the branch id
|
|
||||||
// TODO add a check here to make sure that the admin/manager if from same company
|
|
||||||
// branch, err := h.branchSvc.GetBranchByID(c.Context(), req.BranchID)
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// return fiber.NewError(fiber.StatusBadRequest, "Branch ID is invalid")
|
|
||||||
// }
|
|
||||||
// userRequest := domain.CreateUserReq{
|
|
||||||
// FirstName: req.FirstName,
|
|
||||||
// LastName: req.LastName,
|
|
||||||
// Email: req.Email,
|
|
||||||
// PhoneNumber: req.PhoneNumber,
|
|
||||||
// Password: req.Password,
|
|
||||||
// Role: string(domain.RoleCashier),
|
|
||||||
// Suspended: req.Suspended,
|
|
||||||
// CompanyID: domain.ValidInt64{
|
|
||||||
// Value: 0,
|
|
||||||
// Valid: true,
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// fmt.Print(req.Suspended)
|
|
||||||
// newUser, err := h.userSvc.CreateUser(c.Context(), userRequest, true)
|
|
||||||
// if err != nil {
|
|
||||||
// h.mongoLoggerSvc.Error("Failed to create cashier user",
|
|
||||||
// zap.Any("userRequest", userRequest),
|
|
||||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
// zap.Error(err),
|
|
||||||
// zap.Time("timestamp", time.Now()),
|
|
||||||
// )
|
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create cashier user:"+err.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = h.branchSvc.CreateBranchCashier(c.Context(), req.BranchID, newUser.ID)
|
|
||||||
// if err != nil {
|
|
||||||
// h.mongoLoggerSvc.Error("failed to create branch cashier",
|
|
||||||
// zap.Int64("branchID", req.BranchID),
|
|
||||||
// zap.Int64("userID", newUser.ID),
|
|
||||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
// zap.Error(err),
|
|
||||||
// zap.Time("timestamp", time.Now()),
|
|
||||||
// )
|
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create branch cashier:"+err.Error())
|
|
||||||
// }
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Cashier created successfully", nil, nil)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetCashierRes struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
Role domain.Role `json:"role"`
|
|
||||||
EmailVerified bool `json:"email_verified"`
|
|
||||||
PhoneVerified bool `json:"phone_verified"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
SuspendedAt time.Time `json:"suspended_at"`
|
|
||||||
Suspended bool `json:"suspended"`
|
|
||||||
LastLogin time.Time `json:"last_login"`
|
|
||||||
BranchID int64 `json:"branch_id"`
|
|
||||||
BranchName string `json:"branch_name"`
|
|
||||||
BranchWallet int64 `json:"branch_wallet"`
|
|
||||||
BranchLocation string `json:"branch_location"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllCashiers godoc
|
|
||||||
// @Summary Get all cashiers
|
|
||||||
// @Description Get all cashiers
|
|
||||||
// @Tags cashier
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param page query int false "Page number"
|
|
||||||
// @Param page_size query int false "Page size"
|
|
||||||
// @Success 200 {array} GetCashierRes
|
|
||||||
// @Failure 400 {object} response.APIResponse
|
|
||||||
// @Failure 401 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Router /api/v1/cashiers [get]
|
|
||||||
func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
|
|
||||||
role := c.Locals("role").(domain.Role)
|
|
||||||
companyId := c.Locals("company_id").(domain.ValidInt64)
|
|
||||||
|
|
||||||
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
|
||||||
h.mongoLoggerSvc.Error("Cannot get company ID in context",
|
|
||||||
zap.String("role", string(role)),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID in context")
|
|
||||||
}
|
|
||||||
searchQuery := c.Query("query")
|
|
||||||
searchString := domain.ValidString{
|
|
||||||
Value: searchQuery,
|
|
||||||
Valid: searchQuery != "",
|
|
||||||
}
|
|
||||||
|
|
||||||
createdBeforeQuery := c.Query("created_before")
|
|
||||||
var createdBefore domain.ValidTime
|
|
||||||
if createdBeforeQuery != "" {
|
|
||||||
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Info("invalid created_before format",
|
|
||||||
zap.String("createdBefore", createdBeforeQuery),
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format")
|
|
||||||
}
|
|
||||||
createdBefore = domain.ValidTime{
|
|
||||||
Value: createdBeforeParsed,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createdAfterQuery := c.Query("created_after")
|
|
||||||
var createdAfter domain.ValidTime
|
|
||||||
if createdAfterQuery != "" {
|
|
||||||
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Info("invalid created_after format",
|
|
||||||
zap.String("created_after", createdAfterQuery),
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format")
|
|
||||||
}
|
|
||||||
createdAfter = domain.ValidTime{
|
|
||||||
Value: createdAfterParsed,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter := domain.UserFilter{
|
|
||||||
Role: string(domain.RoleCashier),
|
|
||||||
CompanyID: companyId,
|
|
||||||
Page: domain.ValidInt{
|
|
||||||
Value: c.QueryInt("page", 1) - 1,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
PageSize: domain.ValidInt{
|
|
||||||
Value: c.QueryInt("page_size", 10),
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
Query: searchString,
|
|
||||||
CreatedBefore: createdBefore,
|
|
||||||
CreatedAfter: createdAfter,
|
|
||||||
}
|
|
||||||
|
|
||||||
valErrs, ok := h.validator.Validate(c, filter)
|
|
||||||
if !ok {
|
|
||||||
var errMsg string
|
|
||||||
for field, msg := range valErrs {
|
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
|
||||||
}
|
|
||||||
h.mongoLoggerSvc.Info("Failed to validate filters for GetAllCashier",
|
|
||||||
zap.Any("filter", filter),
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
cashiers, total, err := h.userSvc.GetAllCashiers(c.Context(), filter)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("failed to get all cashiers",
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get cashiers:"+err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []GetCashierRes = make([]GetCashierRes, 0, len(cashiers))
|
|
||||||
|
|
||||||
for _, cashier := range cashiers {
|
|
||||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), cashier.ID)
|
|
||||||
if err != nil {
|
|
||||||
if err == authentication.ErrRefreshTokenNotFound {
|
|
||||||
lastLogin = &cashier.CreatedAt
|
|
||||||
} else {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to get user last login",
|
|
||||||
zap.Int64("userID", cashier.ID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, GetCashierRes{
|
|
||||||
ID: cashier.ID,
|
|
||||||
FirstName: cashier.FirstName,
|
|
||||||
LastName: cashier.LastName,
|
|
||||||
Email: cashier.Email,
|
|
||||||
PhoneNumber: cashier.PhoneNumber,
|
|
||||||
Role: cashier.Role,
|
|
||||||
EmailVerified: cashier.EmailVerified,
|
|
||||||
PhoneVerified: cashier.PhoneVerified,
|
|
||||||
CreatedAt: cashier.CreatedAt,
|
|
||||||
UpdatedAt: cashier.UpdatedAt,
|
|
||||||
SuspendedAt: cashier.SuspendedAt,
|
|
||||||
Suspended: cashier.Suspended,
|
|
||||||
LastLogin: *lastLogin,
|
|
||||||
BranchID: cashier.BranchID,
|
|
||||||
BranchName: cashier.BranchName,
|
|
||||||
BranchWallet: cashier.BranchWallet,
|
|
||||||
BranchLocation: cashier.BranchLocation,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", result, nil, filter.Page.Value, int(total))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCashierByID godoc
|
|
||||||
// @Summary Get cashier by id
|
|
||||||
// @Description Get a single cashier by id
|
|
||||||
// @Tags cashier
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param id path int true "User ID"
|
|
||||||
// @Success 200 {object} UserProfileRes
|
|
||||||
// @Failure 400 {object} response.APIResponse
|
|
||||||
// @Failure 401 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Router /api/v1/cashier/{id} [get]
|
|
||||||
func (h *Handler) GetCashierByID(c *fiber.Ctx) error {
|
|
||||||
// branchId := int64(12) //c.Locals("branch_id").(int64)
|
|
||||||
// filter := user.Filter{
|
|
||||||
// Role: string(domain.RoleUser),
|
|
||||||
// BranchId: user.ValidBranchId{
|
|
||||||
// Value: branchId,
|
|
||||||
// Valid: true,
|
|
||||||
// },
|
|
||||||
// Page: c.QueryInt("page", 1),
|
|
||||||
// PageSize: c.QueryInt("page_size", 10),
|
|
||||||
// }
|
|
||||||
// valErrs, ok := validator.Validate(c, filter)
|
|
||||||
// if !ok {
|
|
||||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
|
||||||
// }
|
|
||||||
|
|
||||||
stringID := c.Params("id")
|
|
||||||
cashierID, err := strconv.ParseInt(stringID, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Info("failed to parse user_id",
|
|
||||||
zap.String("stringID", stringID),
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid cashier ID")
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := h.userSvc.GetCashierByID(c.Context(), cashierID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("Get User By ID failed",
|
|
||||||
zap.Int64("cashierID", cashierID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get cashiers:"+err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
|
||||||
if err != nil {
|
|
||||||
if err != authentication.ErrRefreshTokenNotFound {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to get user last login",
|
|
||||||
zap.Int64("userID", user.ID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
|
||||||
}
|
|
||||||
lastLogin = &user.CreatedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
res := GetCashierRes{
|
|
||||||
ID: user.ID,
|
|
||||||
FirstName: user.FirstName,
|
|
||||||
LastName: user.LastName,
|
|
||||||
Email: user.Email,
|
|
||||||
PhoneNumber: user.PhoneNumber,
|
|
||||||
Role: user.Role,
|
|
||||||
EmailVerified: user.EmailVerified,
|
|
||||||
PhoneVerified: user.PhoneVerified,
|
|
||||||
CreatedAt: user.CreatedAt,
|
|
||||||
UpdatedAt: user.UpdatedAt,
|
|
||||||
SuspendedAt: user.SuspendedAt,
|
|
||||||
Suspended: user.Suspended,
|
|
||||||
LastLogin: *lastLogin,
|
|
||||||
BranchID: user.BranchID,
|
|
||||||
BranchName: user.BranchName,
|
|
||||||
BranchWallet: user.BranchWallet,
|
|
||||||
BranchLocation: user.BranchLocation,
|
|
||||||
}
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
type updateCashierReq struct {
|
|
||||||
FirstName string `json:"first_name" example:"John"`
|
|
||||||
LastName string `json:"last_name" example:"Doe"`
|
|
||||||
Suspended bool `json:"suspended" example:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCashier godoc
|
|
||||||
// @Summary Update cashier
|
|
||||||
// @Description Update cashier
|
|
||||||
// @Tags cashier
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param id path int true "Cashier ID"
|
|
||||||
// @Param cashier body updateCashierReq true "Update cashier"
|
|
||||||
// @Success 200 {object} response.APIResponse
|
|
||||||
// @Failure 400 {object} response.APIResponse
|
|
||||||
// @Failure 401 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Router /api/v1/cashiers/{id} [put]
|
|
||||||
func (h *Handler) UpdateCashier(c *fiber.Ctx) error {
|
|
||||||
cashierIdStr := c.Params("id")
|
|
||||||
cashierId, err := strconv.ParseInt(cashierIdStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Info("UpdateCashier invalid cashier ID",
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid cashier ID")
|
|
||||||
}
|
|
||||||
var req updateCashierReq
|
|
||||||
if err := c.BodyParser(&req); err != nil {
|
|
||||||
h.mongoLoggerSvc.Info("UpdateCashier failed to parse request body",
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
valErrs, ok := h.validator.Validate(c, req)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
var errMsg string
|
|
||||||
for field, msg := range valErrs {
|
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
|
||||||
}
|
|
||||||
h.mongoLoggerSvc.Info("Failed to validate update cashier request",
|
|
||||||
zap.Any("request", req),
|
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
|
||||||
UserId: cashierId,
|
|
||||||
FirstName: domain.ValidString{
|
|
||||||
Value: req.FirstName,
|
|
||||||
Valid: req.FirstName != "",
|
|
||||||
},
|
|
||||||
LastName: domain.ValidString{
|
|
||||||
Value: req.LastName,
|
|
||||||
Valid: req.LastName != "",
|
|
||||||
},
|
|
||||||
Suspended: domain.ValidBool{
|
|
||||||
Value: req.Suspended,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("failed to update cashier",
|
|
||||||
zap.Int64("userID", cashierId),
|
|
||||||
zap.Any("request", req),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update cashier"+err.Error())
|
|
||||||
}
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Cashier updated successfully", nil, nil)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +1,24 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// @Summary Get supported currencies
|
// @Summary Get supported currencies
|
||||||
// @Description Returns list of supported currencies
|
// @Description Returns list of supported currencies
|
||||||
// @Tags Multi-Currency
|
// @Tags Multi-Currency
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} domain.Response{data=[]domain.Currency}
|
// @Success 200 {object} domain.Response{data=[]domain.Currency}
|
||||||
// @Router /api/v1/currencies [get]
|
// @Router /api/v1/currencies [get]
|
||||||
func (h *Handler) GetSupportedCurrencies(c *fiber.Ctx) error {
|
// func (h *Handler) GetSupportedCurrencies(c *fiber.Ctx) error {
|
||||||
currencies, err := h.currSvc.GetSupportedCurrencies(c.Context())
|
// currencies, err := h.currSvc.GetSupportedCurrencies(c.Context())
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return domain.UnExpectedErrorResponse(c)
|
// return domain.UnExpectedErrorResponse(c)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
// return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
Success: true,
|
// Success: true,
|
||||||
Message: "Supported currencies retrieved successfully",
|
// Message: "Supported currencies retrieved successfully",
|
||||||
Data: currencies,
|
// Data: currencies,
|
||||||
StatusCode: fiber.StatusOK,
|
// StatusCode: fiber.StatusOK,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Summary Convert currency
|
// @Summary Convert currency
|
||||||
// @Description Converts amount from one currency to another
|
// @Description Converts amount from one currency to another
|
||||||
|
|
@ -36,23 +30,23 @@ func (h *Handler) GetSupportedCurrencies(c *fiber.Ctx) error {
|
||||||
// @Success 200 {object} domain.Response{data=float64}
|
// @Success 200 {object} domain.Response{data=float64}
|
||||||
// @Failure 400 {object} domain.ErrorResponse
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/currencies/convert [get]
|
// @Router /api/v1/currencies/convert [get]
|
||||||
func (h *Handler) ConvertCurrency(c *fiber.Ctx) error {
|
// func (h *Handler) ConvertCurrency(c *fiber.Ctx) error {
|
||||||
from := domain.IntCurrency(c.Query("from"))
|
// from := domain.IntCurrency(c.Query("from"))
|
||||||
to := domain.IntCurrency(c.Query("to"))
|
// to := domain.IntCurrency(c.Query("to"))
|
||||||
amount := c.QueryFloat("amount", 0)
|
// amount := c.QueryFloat("amount", 0)
|
||||||
// if err != nil {
|
// // if err != nil {
|
||||||
// return domain.BadRequestResponse(c)
|
// // return domain.BadRequestResponse(c)
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
converted, err := h.currSvc.Convert(c.Context(), amount, from, to)
|
// converted, err := h.currSvc.Convert(c.Context(), amount, from, to)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return domain.UnExpectedErrorResponse(c)
|
// return domain.UnExpectedErrorResponse(c)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
// return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
Success: true,
|
// Success: true,
|
||||||
Message: "Currency converted successfully",
|
// Message: "Currency converted successfully",
|
||||||
Data: converted,
|
// Data: converted,
|
||||||
StatusCode: fiber.StatusOK,
|
// StatusCode: fiber.StatusOK,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@ import (
|
||||||
"Yimaru-Backend/internal/config"
|
"Yimaru-Backend/internal/config"
|
||||||
"Yimaru-Backend/internal/services/arifpay"
|
"Yimaru-Backend/internal/services/arifpay"
|
||||||
"Yimaru-Backend/internal/services/authentication"
|
"Yimaru-Backend/internal/services/authentication"
|
||||||
"Yimaru-Backend/internal/services/currency"
|
|
||||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||||
"Yimaru-Backend/internal/services/recommendation"
|
"Yimaru-Backend/internal/services/recommendation"
|
||||||
referralservice "Yimaru-Backend/internal/services/referal"
|
// referralservice "Yimaru-Backend/internal/services/referal"
|
||||||
|
|
||||||
"Yimaru-Backend/internal/services/settings"
|
"Yimaru-Backend/internal/services/settings"
|
||||||
|
|
||||||
|
|
@ -22,13 +21,10 @@ import (
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
arifpaySvc *arifpay.ArifpayService
|
arifpaySvc *arifpay.ArifpayService
|
||||||
// instSvc *institutions.Service
|
|
||||||
currSvc *currency.Service
|
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
settingSvc *settings.Service
|
settingSvc *settings.Service
|
||||||
notificationSvc *notificationservice.Service
|
notificationSvc *notificationservice.Service
|
||||||
userSvc *user.Service
|
userSvc *user.Service
|
||||||
referralSvc *referralservice.Service
|
|
||||||
transactionSvc *transaction.Service
|
transactionSvc *transaction.Service
|
||||||
recommendationSvc recommendation.RecommendationService
|
recommendationSvc recommendation.RecommendationService
|
||||||
authSvc *authentication.Service
|
authSvc *authentication.Service
|
||||||
|
|
@ -39,23 +35,14 @@ type Handler struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
// directDepositSvc *directdeposit.Service,
|
|
||||||
// telebirrSvc *telebirr.TelebirrService,
|
|
||||||
arifpaySvc *arifpay.ArifpayService,
|
arifpaySvc *arifpay.ArifpayService,
|
||||||
// santimpaySvc *santimpay.SantimPayService,
|
|
||||||
// instSvc *institutions.Service,
|
|
||||||
currSvc *currency.Service,
|
|
||||||
logger *slog.Logger,
|
logger *slog.Logger,
|
||||||
settingSvc *settings.Service,
|
settingSvc *settings.Service,
|
||||||
notificationSvc *notificationservice.Service,
|
notificationSvc *notificationservice.Service,
|
||||||
validator *customvalidator.CustomValidator,
|
validator *customvalidator.CustomValidator,
|
||||||
// reportSvc report.ReportService,
|
|
||||||
// chapaSvc *chapa.Service,
|
|
||||||
referralSvc *referralservice.Service,
|
|
||||||
recommendationSvc recommendation.RecommendationService,
|
recommendationSvc recommendation.RecommendationService,
|
||||||
userSvc *user.Service,
|
userSvc *user.Service,
|
||||||
transactionSvc *transaction.Service,
|
transactionSvc *transaction.Service,
|
||||||
// ticketSvc *ticket.Service,
|
|
||||||
authSvc *authentication.Service,
|
authSvc *authentication.Service,
|
||||||
jwtConfig jwtutil.JwtConfig,
|
jwtConfig jwtutil.JwtConfig,
|
||||||
cfg *config.Config,
|
cfg *config.Config,
|
||||||
|
|
@ -63,12 +50,9 @@ func New(
|
||||||
) *Handler {
|
) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
arifpaySvc: arifpaySvc,
|
arifpaySvc: arifpaySvc,
|
||||||
instSvc: instSvc,
|
|
||||||
currSvc: currSvc,
|
|
||||||
logger: logger,
|
logger: logger,
|
||||||
settingSvc: settingSvc,
|
settingSvc: settingSvc,
|
||||||
notificationSvc: notificationSvc,
|
notificationSvc: notificationSvc,
|
||||||
referralSvc: referralSvc,
|
|
||||||
validator: validator,
|
validator: validator,
|
||||||
userSvc: userSvc,
|
userSvc: userSvc,
|
||||||
transactionSvc: transactionSvc,
|
transactionSvc: transactionSvc,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,5 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
|
||||||
"Yimaru-Backend/internal/domain"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// @Summary Create a new bank
|
// @Summary Create a new bank
|
||||||
// @Tags Institutions - Banks
|
// @Tags Institutions - Banks
|
||||||
// @Accept json
|
// @Accept json
|
||||||
|
|
@ -16,18 +8,18 @@ import (
|
||||||
// @Success 201 {object} domain.Bank
|
// @Success 201 {object} domain.Bank
|
||||||
// @Failure 400 {object} domain.ErrorResponse
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/banks [post]
|
// @Router /api/v1/banks [post]
|
||||||
func (h *Handler) CreateBank(c *fiber.Ctx) error {
|
// func (h *Handler) CreateBank(c *fiber.Ctx) error {
|
||||||
var bank domain.Bank
|
// var bank domain.Bank
|
||||||
if err := c.BodyParser(&bank); err != nil {
|
// if err := c.BodyParser(&bank); err != nil {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||||
}
|
// }
|
||||||
|
|
||||||
err := h.instSvc.Create(c.Context(), &bank)
|
// // err := h.instSvc.Create(c.Context(), &bank)
|
||||||
if err != nil {
|
// // if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
// // return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||||
}
|
// // }
|
||||||
return c.Status(fiber.StatusCreated).JSON(bank)
|
// return c.Status(fiber.StatusCreated).JSON(bank)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Summary Get a bank by ID
|
// @Summary Get a bank by ID
|
||||||
// @Tags Institutions - Banks
|
// @Tags Institutions - Banks
|
||||||
|
|
@ -38,19 +30,19 @@ func (h *Handler) CreateBank(c *fiber.Ctx) error {
|
||||||
// @Failure 404 {object} domain.ErrorResponse
|
// @Failure 404 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/banks/{id} [get]
|
// @Router /api/v1/banks/{id} [get]
|
||||||
func (h *Handler) GetBankByID(c *fiber.Ctx) error {
|
// func (h *Handler) GetBankByID(c *fiber.Ctx) error {
|
||||||
id, err := c.ParamsInt("id")
|
// id, err := c.ParamsInt("id")
|
||||||
if err != nil || id <= 0 {
|
// if err != nil || id <= 0 {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||||
}
|
// }
|
||||||
|
|
||||||
bank, err := h.instSvc.GetByID(c.Context(), int64(id))
|
// // bank, err := h.instSvc.GetByID(c.Context(), int64(id))
|
||||||
if err != nil {
|
// // if err != nil {
|
||||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "bank not found"})
|
// // return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "bank not found"})
|
||||||
}
|
// // }
|
||||||
|
|
||||||
return c.JSON(bank)
|
// return c.JSON(bank)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Summary Update a bank
|
// @Summary Update a bank
|
||||||
// @Tags Institutions - Banks
|
// @Tags Institutions - Banks
|
||||||
|
|
@ -63,42 +55,42 @@ func (h *Handler) GetBankByID(c *fiber.Ctx) error {
|
||||||
// @Failure 404 {object} domain.ErrorResponse
|
// @Failure 404 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/banks/{id} [put]
|
// @Router /api/v1/banks/{id} [put]
|
||||||
func (h *Handler) UpdateBank(c *fiber.Ctx) error {
|
// func (h *Handler) UpdateBank(c *fiber.Ctx) error {
|
||||||
id, err := c.ParamsInt("id")
|
// id, err := c.ParamsInt("id")
|
||||||
if err != nil || id <= 0 {
|
// if err != nil || id <= 0 {
|
||||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
// // return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
// return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to update bank",
|
// Message: "Failed to update bank",
|
||||||
Error: err.Error(),
|
// Error: err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
var bank domain.Bank
|
// var bank domain.Bank
|
||||||
if err := c.BodyParser(&bank); err != nil {
|
// if err := c.BodyParser(&bank); err != nil {
|
||||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
// // return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
// return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to update bank",
|
// Message: "Failed to update bank",
|
||||||
Error: err.Error(),
|
// Error: err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
bank.ID = id
|
// bank.ID = id
|
||||||
|
|
||||||
err = h.instSvc.Update(c.Context(), &bank)
|
// err = h.instSvc.Update(c.Context(), &bank)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
// return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to update bank",
|
// Message: "Failed to update bank",
|
||||||
Error: err.Error(),
|
// Error: err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
// return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
Message: "Bank updated successfully",
|
// Message: "Bank updated successfully",
|
||||||
StatusCode: fiber.StatusOK,
|
// StatusCode: fiber.StatusOK,
|
||||||
Success: true,
|
// Success: true,
|
||||||
Data: bank,
|
// Data: bank,
|
||||||
})
|
// })
|
||||||
// return c.JSON(bank)
|
// // return c.JSON(bank)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Summary Delete a bank
|
// @Summary Delete a bank
|
||||||
// @Tags Institutions - Banks
|
// @Tags Institutions - Banks
|
||||||
|
|
@ -109,19 +101,19 @@ func (h *Handler) UpdateBank(c *fiber.Ctx) error {
|
||||||
// @Failure 404 {object} domain.ErrorResponse
|
// @Failure 404 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/banks/{id} [delete]
|
// @Router /api/v1/banks/{id} [delete]
|
||||||
func (h *Handler) DeleteBank(c *fiber.Ctx) error {
|
// func (h *Handler) DeleteBank(c *fiber.Ctx) error {
|
||||||
id, err := c.ParamsInt("id")
|
// id, err := c.ParamsInt("id")
|
||||||
if err != nil || id <= 0 {
|
// if err != nil || id <= 0 {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||||
}
|
// }
|
||||||
|
|
||||||
err = h.instSvc.Delete(c.Context(), int64(id))
|
// err = h.instSvc.Delete(c.Context(), int64(id))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.SendStatus(fiber.StatusNoContent)
|
// return c.SendStatus(fiber.StatusNoContent)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// @Summary List all banks with pagination and filtering
|
// @Summary List all banks with pagination and filtering
|
||||||
// @Tags Institutions - Banks
|
// @Tags Institutions - Banks
|
||||||
|
|
@ -135,51 +127,51 @@ func (h *Handler) DeleteBank(c *fiber.Ctx) error {
|
||||||
// @Failure 400 {object} domain.ErrorResponse
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/banks [get]
|
// @Router /api/v1/banks [get]
|
||||||
func (h *Handler) ListBanks(c *fiber.Ctx) error {
|
// func (h *Handler) ListBanks(c *fiber.Ctx) error {
|
||||||
// Parse query parameters
|
// // Parse query parameters
|
||||||
countryID, _ := strconv.Atoi(c.Query("country_id"))
|
// countryID, _ := strconv.Atoi(c.Query("country_id"))
|
||||||
var countryIDPtr *int
|
// var countryIDPtr *int
|
||||||
if c.Query("country_id") != "" {
|
// if c.Query("country_id") != "" {
|
||||||
countryIDPtr = &countryID
|
// countryIDPtr = &countryID
|
||||||
}
|
// }
|
||||||
|
|
||||||
isActive, _ := strconv.ParseBool(c.Query("is_active"))
|
// isActive, _ := strconv.ParseBool(c.Query("is_active"))
|
||||||
var isActivePtr *bool
|
// var isActivePtr *bool
|
||||||
if c.Query("is_active") != "" {
|
// if c.Query("is_active") != "" {
|
||||||
isActivePtr = &isActive
|
// isActivePtr = &isActive
|
||||||
}
|
// }
|
||||||
|
|
||||||
var searchTermPtr *string
|
// var searchTermPtr *string
|
||||||
if searchTerm := c.Query("search"); searchTerm != "" {
|
// if searchTerm := c.Query("search"); searchTerm != "" {
|
||||||
searchTermPtr = &searchTerm
|
// searchTermPtr = &searchTerm
|
||||||
}
|
// }
|
||||||
|
|
||||||
page, _ := strconv.Atoi(c.Query("page", "1"))
|
// page, _ := strconv.Atoi(c.Query("page", "1"))
|
||||||
pageSize, _ := strconv.Atoi(c.Query("page_size", "50"))
|
// pageSize, _ := strconv.Atoi(c.Query("page_size", "50"))
|
||||||
|
|
||||||
banks, pagination, err := h.instSvc.List(
|
// banks, pagination, err := h.instSvc.List(
|
||||||
c.Context(),
|
// c.Context(),
|
||||||
countryIDPtr,
|
// countryIDPtr,
|
||||||
isActivePtr,
|
// isActivePtr,
|
||||||
searchTermPtr,
|
// searchTermPtr,
|
||||||
page,
|
// page,
|
||||||
pageSize,
|
// pageSize,
|
||||||
)
|
// )
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("failed to list banks",
|
// h.mongoLoggerSvc.Error("failed to list banks",
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Any("query_params", c.Queries()),
|
// zap.Any("query_params", c.Queries()),
|
||||||
)
|
// )
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
// return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to retrieve banks",
|
// Message: "Failed to retrieve banks",
|
||||||
Error: err.Error(),
|
// Error: err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).JSON(domain.InstResponse{
|
// return c.Status(fiber.StatusOK).JSON(domain.InstResponse{
|
||||||
Message: "Banks retrieved successfully",
|
// Message: "Banks retrieved successfully",
|
||||||
Status: "success",
|
// Status: "success",
|
||||||
Data: banks,
|
// Data: banks,
|
||||||
Pagination: pagination,
|
// Pagination: pagination,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,12 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"Yimaru-Backend/internal/domain"
|
"Yimaru-Backend/internal/domain"
|
||||||
"Yimaru-Backend/internal/services/authentication"
|
|
||||||
"Yimaru-Backend/internal/web_server/response"
|
"Yimaru-Backend/internal/web_server/response"
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateManagerReq struct {
|
type CreateManagerReq struct {
|
||||||
|
|
@ -34,75 +31,75 @@ type CreateManagerReq struct {
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/managers [post]
|
// @Router /api/v1/managers [post]
|
||||||
func (h *Handler) CreateManager(c *fiber.Ctx) error {
|
// func (h *Handler) CreateManager(c *fiber.Ctx) error {
|
||||||
|
|
||||||
// Get user_id from middleware
|
// // Get user_id from middleware
|
||||||
|
|
||||||
var req CreateManagerReq
|
// var req CreateManagerReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
// if err := c.BodyParser(&req); err != nil {
|
||||||
h.logger.Error("RegisterUser failed", "error", err)
|
// h.logger.Error("RegisterUser failed", "error", err)
|
||||||
h.mongoLoggerSvc.Info("CreateManager failed to create manager",
|
// h.mongoLoggerSvc.Info("CreateManager failed to create manager",
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error())
|
||||||
}
|
// }
|
||||||
valErrs, ok := h.validator.Validate(c, req)
|
// valErrs, ok := h.validator.Validate(c, req)
|
||||||
if !ok {
|
// if !ok {
|
||||||
var errMsg string
|
// var errMsg string
|
||||||
for field, msg := range valErrs {
|
// for field, msg := range valErrs {
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
// errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
}
|
// }
|
||||||
h.mongoLoggerSvc.Info("Failed to validate CreateManager",
|
// h.mongoLoggerSvc.Info("Failed to validate CreateManager",
|
||||||
zap.Any("request", req),
|
// zap.Any("request", req),
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.String("errMsg", errMsg),
|
// zap.String("errMsg", errMsg),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
var companyID domain.ValidInt64
|
// var companyID domain.ValidInt64
|
||||||
role := c.Locals("role").(domain.Role)
|
// role := c.Locals("role").(domain.Role)
|
||||||
if role == domain.RoleSuperAdmin {
|
// if role == domain.RoleSuperAdmin {
|
||||||
if req.CompanyID == nil {
|
// if req.CompanyID == nil {
|
||||||
h.logger.Error("RegisterUser failed error: company id is required")
|
// h.logger.Error("RegisterUser failed error: company id is required")
|
||||||
h.mongoLoggerSvc.Info("RegisterUser failed error: company id is required",
|
// h.mongoLoggerSvc.Info("RegisterUser failed error: company id is required",
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Company ID is required for super-admin")
|
// return fiber.NewError(fiber.StatusBadRequest, "Company ID is required for super-admin")
|
||||||
}
|
// }
|
||||||
companyID = domain.ValidInt64{
|
// companyID = domain.ValidInt64{
|
||||||
Value: *req.CompanyID,
|
// Value: *req.CompanyID,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
companyID = c.Locals("company_id").(domain.ValidInt64)
|
// companyID = c.Locals("company_id").(domain.ValidInt64)
|
||||||
}
|
// }
|
||||||
|
|
||||||
user := domain.CreateUserReq{
|
// user := domain.CreateUserReq{
|
||||||
FirstName: req.FirstName,
|
// FirstName: req.FirstName,
|
||||||
LastName: req.LastName,
|
// LastName: req.LastName,
|
||||||
Email: req.Email,
|
// Email: req.Email,
|
||||||
PhoneNumber: req.PhoneNumber,
|
// PhoneNumber: req.PhoneNumber,
|
||||||
Password: req.Password,
|
// Password: req.Password,
|
||||||
Role: string(domain.RoleBranchManager),
|
// Role: string(domain.RoleBranchManager),
|
||||||
CompanyID: companyID,
|
// OrganizationID: companyID,
|
||||||
}
|
// }
|
||||||
_, err := h.userSvc.CreateUser(c.Context(), user, true)
|
// _, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("CreateManager failed to create manager",
|
// h.mongoLoggerSvc.Error("CreateManager failed to create manager",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create manager:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create manager:"+err.Error())
|
||||||
}
|
// }
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Manager created successfully", nil, nil)
|
// return response.WriteJSON(c, fiber.StatusOK, "Manager created successfully", nil, nil)
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
type ManagersRes struct {
|
type ManagersRes struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
|
|
@ -133,141 +130,141 @@ type ManagersRes struct {
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/managers [get]
|
// @Router /api/v1/managers [get]
|
||||||
func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
// func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
||||||
role := c.Locals("role").(domain.Role)
|
// role := c.Locals("role").(domain.Role)
|
||||||
companyId := c.Locals("company_id").(domain.ValidInt64)
|
// companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
|
||||||
// Checking to make sure that admin user has a company id in the token
|
// // Checking to make sure that admin user has a company id in the token
|
||||||
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
// if role != domain.RoleSuperAdmin && !companyId.Valid {
|
||||||
h.mongoLoggerSvc.Error("Cannot get company ID from context",
|
// h.mongoLoggerSvc.Error("Cannot get company ID from context",
|
||||||
zap.String("role", string(role)),
|
// zap.String("role", string(role)),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID from context")
|
// return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID from context")
|
||||||
}
|
// }
|
||||||
|
|
||||||
searchQuery := c.Query("query")
|
// searchQuery := c.Query("query")
|
||||||
searchString := domain.ValidString{
|
// searchString := domain.ValidString{
|
||||||
Value: searchQuery,
|
// Value: searchQuery,
|
||||||
Valid: searchQuery != "",
|
// Valid: searchQuery != "",
|
||||||
}
|
// }
|
||||||
|
|
||||||
createdBeforeQuery := c.Query("created_before")
|
// createdBeforeQuery := c.Query("created_before")
|
||||||
var createdBefore domain.ValidTime
|
// var createdBefore domain.ValidTime
|
||||||
if createdBeforeQuery != "" {
|
// if createdBeforeQuery != "" {
|
||||||
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
// createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Info("invalid created_before format",
|
// h.mongoLoggerSvc.Info("invalid created_before format",
|
||||||
zap.String("created_before", createdBeforeQuery),
|
// zap.String("created_before", createdBeforeQuery),
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format")
|
||||||
}
|
// }
|
||||||
createdBefore = domain.ValidTime{
|
// createdBefore = domain.ValidTime{
|
||||||
Value: createdBeforeParsed,
|
// Value: createdBeforeParsed,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
createdAfterQuery := c.Query("created_after")
|
// createdAfterQuery := c.Query("created_after")
|
||||||
var createdAfter domain.ValidTime
|
// var createdAfter domain.ValidTime
|
||||||
if createdAfterQuery != "" {
|
// if createdAfterQuery != "" {
|
||||||
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
// createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Info("invalid created_after format",
|
// h.mongoLoggerSvc.Info("invalid created_after format",
|
||||||
zap.String("created_after", createdAfterQuery),
|
// zap.String("created_after", createdAfterQuery),
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format")
|
||||||
}
|
// }
|
||||||
createdAfter = domain.ValidTime{
|
// createdAfter = domain.ValidTime{
|
||||||
Value: createdAfterParsed,
|
// Value: createdAfterParsed,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
filter := domain.UserFilter{
|
// filter := domain.UserFilter{
|
||||||
Role: string(domain.RoleBranchManager),
|
// Role: string(domain.RoleBranchManager),
|
||||||
CompanyID: companyId,
|
// OrganizationID: companyId,
|
||||||
Page: domain.ValidInt{
|
// Page: domain.ValidInt{
|
||||||
Value: c.QueryInt("page", 1) - 1,
|
// Value: c.QueryInt("page", 1) - 1,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
},
|
// },
|
||||||
PageSize: domain.ValidInt{
|
// PageSize: domain.ValidInt{
|
||||||
Value: c.QueryInt("page_size", 10),
|
// Value: c.QueryInt("page_size", 10),
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
},
|
// },
|
||||||
Query: searchString,
|
// Query: searchString,
|
||||||
CreatedBefore: createdBefore,
|
// CreatedBefore: createdBefore,
|
||||||
CreatedAfter: createdAfter,
|
// CreatedAfter: createdAfter,
|
||||||
}
|
// }
|
||||||
valErrs, ok := h.validator.Validate(c, filter)
|
// valErrs, ok := h.validator.Validate(c, filter)
|
||||||
if !ok {
|
// if !ok {
|
||||||
var errMsg string
|
// var errMsg string
|
||||||
for field, msg := range valErrs {
|
// for field, msg := range valErrs {
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
// errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
}
|
// }
|
||||||
h.mongoLoggerSvc.Info("Failed to validate get all filters",
|
// h.mongoLoggerSvc.Info("Failed to validate get all filters",
|
||||||
zap.Any("filter", filter),
|
// zap.Any("filter", filter),
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.String("errMsg", errMsg),
|
// zap.String("errMsg", errMsg),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
// }
|
||||||
managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
// managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.logger.Error("GetAllManagers failed", "error", err)
|
// h.logger.Error("GetAllManagers failed", "error", err)
|
||||||
h.mongoLoggerSvc.Error("GetAllManagers failed to get all managers",
|
// h.mongoLoggerSvc.Error("GetAllManagers failed to get all managers",
|
||||||
zap.Any("filter", filter),
|
// zap.Any("filter", filter),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Managers"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Managers"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
var result []ManagersRes = make([]ManagersRes, len(managers))
|
// var result []ManagersRes = make([]ManagersRes, len(managers))
|
||||||
for index, manager := range managers {
|
// for index, manager := range managers {
|
||||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), manager.ID)
|
// lastLogin, err := h.authSvc.GetLastLogin(c.Context(), manager.ID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
if err == authentication.ErrRefreshTokenNotFound {
|
// if err == authentication.ErrRefreshTokenNotFound {
|
||||||
lastLogin = &manager.CreatedAt
|
// lastLogin = &manager.CreatedAt
|
||||||
} else {
|
// } else {
|
||||||
h.mongoLoggerSvc.Error("Failed to get user last login",
|
// h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||||
zap.Int64("userID", manager.ID),
|
// zap.Int64("userID", manager.ID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
result[index] = ManagersRes{
|
// result[index] = ManagersRes{
|
||||||
ID: manager.ID,
|
// ID: manager.ID,
|
||||||
FirstName: manager.FirstName,
|
// FirstName: manager.FirstName,
|
||||||
LastName: manager.LastName,
|
// LastName: manager.LastName,
|
||||||
Email: manager.Email,
|
// Email: manager.Email,
|
||||||
PhoneNumber: manager.PhoneNumber,
|
// PhoneNumber: manager.PhoneNumber,
|
||||||
Role: manager.Role,
|
// Role: manager.Role,
|
||||||
EmailVerified: manager.EmailVerified,
|
// EmailVerified: manager.EmailVerified,
|
||||||
PhoneVerified: manager.PhoneVerified,
|
// PhoneVerified: manager.PhoneVerified,
|
||||||
CreatedAt: manager.CreatedAt,
|
// CreatedAt: manager.CreatedAt,
|
||||||
UpdatedAt: manager.UpdatedAt,
|
// UpdatedAt: manager.UpdatedAt,
|
||||||
SuspendedAt: manager.SuspendedAt,
|
// SuspendedAt: manager.SuspendedAt,
|
||||||
Suspended: manager.Suspended,
|
// Suspended: manager.Suspended,
|
||||||
LastLogin: *lastLogin,
|
// LastLogin: *lastLogin,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Managers retrieved successfully", result, nil, filter.Page.Value, int(total))
|
// return response.WritePaginatedJSON(c, fiber.StatusOK, "Managers retrieved successfully", result, nil, filter.Page.Value, int(total))
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
// GetManagerByID godoc
|
// GetManagerByID godoc
|
||||||
// @Summary Get manager by id
|
// @Summary Get manager by id
|
||||||
|
|
@ -281,103 +278,103 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/managers/{id} [get]
|
// @Router /api/v1/managers/{id} [get]
|
||||||
func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
|
// func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
|
||||||
role := c.Locals("role").(domain.Role)
|
// role := c.Locals("role").(domain.Role)
|
||||||
companyId := c.Locals("company_id").(domain.ValidInt64)
|
// companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||||
requestUserID := c.Locals("user_id").(int64)
|
// requestUserID := c.Locals("user_id").(int64)
|
||||||
|
|
||||||
// Only Super Admin / Admin / Branch Manager can view this route
|
// // Only Super Admin / Admin / Branch Manager can view this route
|
||||||
if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager {
|
// if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager {
|
||||||
h.mongoLoggerSvc.Warn("Attempt to access from unauthorized role",
|
// h.mongoLoggerSvc.Warn("Attempt to access from unauthorized role",
|
||||||
zap.Int64("userID", requestUserID),
|
// zap.Int64("userID", requestUserID),
|
||||||
zap.String("role", string(role)),
|
// zap.String("role", string(role)),
|
||||||
zap.Int("status_code", fiber.StatusForbidden),
|
// zap.Int("status_code", fiber.StatusForbidden),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusForbidden, "This role cannot view this route")
|
// return fiber.NewError(fiber.StatusForbidden, "This role cannot view this route")
|
||||||
}
|
// }
|
||||||
|
|
||||||
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
// if role != domain.RoleSuperAdmin && !companyId.Valid {
|
||||||
h.mongoLoggerSvc.Error("Cannot get company ID in context",
|
// h.mongoLoggerSvc.Error("Cannot get company ID in context",
|
||||||
zap.String("role", string(role)),
|
// zap.String("role", string(role)),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID in context")
|
// return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID in context")
|
||||||
}
|
// }
|
||||||
|
|
||||||
userIDstr := c.Params("id")
|
// userIDstr := c.Params("id")
|
||||||
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
// userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid managers ID")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid managers ID")
|
||||||
}
|
// }
|
||||||
|
|
||||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
// user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to get manager by id",
|
// h.mongoLoggerSvc.Error("Failed to get manager by id",
|
||||||
zap.Int64("userID", userID),
|
// zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
// A Branch Manager can only fetch his own branch info
|
// // A Branch Manager can only fetch his own branch info
|
||||||
if role == domain.RoleBranchManager && user.ID != requestUserID {
|
// if role == domain.RoleBranchManager && user.ID != requestUserID {
|
||||||
h.mongoLoggerSvc.Warn("Attempt to access another branch manager info",
|
// h.mongoLoggerSvc.Warn("Attempt to access another branch manager info",
|
||||||
zap.String("userID", userIDstr),
|
// zap.String("userID", userIDstr),
|
||||||
zap.Int("status_code", fiber.StatusForbidden),
|
// zap.Int("status_code", fiber.StatusForbidden),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusForbidden, "User Access Not Allowed")
|
// return fiber.NewError(fiber.StatusForbidden, "User Access Not Allowed")
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Check that only admin from company can view this route
|
// // Check that only admin from company can view this route
|
||||||
if role != domain.RoleSuperAdmin && user.CompanyID.Value != companyId.Value {
|
// if role != domain.RoleSuperAdmin && user.OrganizationID.Value != companyId.Value {
|
||||||
h.mongoLoggerSvc.Warn("Attempt to access info from another company",
|
// h.mongoLoggerSvc.Warn("Attempt to access info from another company",
|
||||||
zap.String("userID", userIDstr),
|
// zap.String("userID", userIDstr),
|
||||||
zap.Int("status_code", fiber.StatusForbidden),
|
// zap.Int("status_code", fiber.StatusForbidden),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusForbidden, "Cannot access another company information")
|
// return fiber.NewError(fiber.StatusForbidden, "Cannot access another company information")
|
||||||
}
|
// }
|
||||||
|
|
||||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
// lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
if err != authentication.ErrRefreshTokenNotFound {
|
// if err != authentication.ErrRefreshTokenNotFound {
|
||||||
h.mongoLoggerSvc.Error("Failed to get user last login",
|
// h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||||
zap.Int64("userID", userID),
|
// zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
lastLogin = &user.CreatedAt
|
// lastLogin = &user.CreatedAt
|
||||||
}
|
// }
|
||||||
|
|
||||||
res := ManagersRes{
|
// res := ManagersRes{
|
||||||
ID: user.ID,
|
// ID: user.ID,
|
||||||
FirstName: user.FirstName,
|
// FirstName: user.FirstName,
|
||||||
LastName: user.LastName,
|
// LastName: user.LastName,
|
||||||
Email: user.Email,
|
// Email: user.Email,
|
||||||
PhoneNumber: user.PhoneNumber,
|
// PhoneNumber: user.PhoneNumber,
|
||||||
Role: user.Role,
|
// Role: user.Role,
|
||||||
EmailVerified: user.EmailVerified,
|
// EmailVerified: user.EmailVerified,
|
||||||
PhoneVerified: user.PhoneVerified,
|
// PhoneVerified: user.PhoneVerified,
|
||||||
CreatedAt: user.CreatedAt,
|
// CreatedAt: user.CreatedAt,
|
||||||
UpdatedAt: user.UpdatedAt,
|
// UpdatedAt: user.UpdatedAt,
|
||||||
SuspendedAt: user.SuspendedAt,
|
// SuspendedAt: user.SuspendedAt,
|
||||||
Suspended: user.Suspended,
|
// Suspended: user.Suspended,
|
||||||
LastLogin: *lastLogin,
|
// LastLogin: *lastLogin,
|
||||||
}
|
// }
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
// return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
|
||||||
}
|
// }
|
||||||
|
|
||||||
type updateManagerReq struct {
|
type updateManagerReq struct {
|
||||||
FirstName string `json:"first_name" example:"John"`
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
|
@ -433,7 +430,7 @@ func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
UserId: ManagersId,
|
UserID: ManagersId,
|
||||||
FirstName: domain.ValidString{
|
FirstName: domain.ValidString{
|
||||||
Value: req.FirstName,
|
Value: req.FirstName,
|
||||||
Valid: req.FirstName != "",
|
Valid: req.FirstName != "",
|
||||||
|
|
@ -446,7 +443,7 @@ func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
|
||||||
Value: req.Suspended,
|
Value: req.Suspended,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
},
|
},
|
||||||
CompanyID: companyID,
|
OrganizationID: companyID,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,9 @@ import (
|
||||||
"Yimaru-Backend/internal/web_server/ws"
|
"Yimaru-Backend/internal/web_server/ws"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
|
@ -131,45 +129,45 @@ func (h *Handler) ConnectSocket(c *fiber.Ctx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
// func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
||||||
type Request struct {
|
// type Request struct {
|
||||||
NotificationIDs []string `json:"notification_ids" validate:"required"`
|
// NotificationIDs []string `json:"notification_ids" validate:"required"`
|
||||||
}
|
// }
|
||||||
|
|
||||||
var req Request
|
// var req Request
|
||||||
if err := c.BodyParser(&req); err != nil {
|
// if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse request body",
|
// h.mongoLoggerSvc.Info("Failed to parse request body",
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||||
}
|
// }
|
||||||
|
|
||||||
userID, ok := c.Locals("user_id").(int64)
|
// userID, ok := c.Locals("user_id").(int64)
|
||||||
if !ok || userID == 0 {
|
// if !ok || userID == 0 {
|
||||||
h.mongoLoggerSvc.Error("Invalid user ID in context",
|
// h.mongoLoggerSvc.Error("Invalid user ID in context",
|
||||||
zap.Int64("userID", userID),
|
// zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "invalid user ID in context")
|
// return fiber.NewError(fiber.StatusInternalServerError, "invalid user ID in context")
|
||||||
}
|
// }
|
||||||
|
|
||||||
fmt.Printf("Notification IDs: %v \n", req.NotificationIDs)
|
// fmt.Printf("Notification IDs: %v \n", req.NotificationIDs)
|
||||||
if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationIDs, userID); err != nil {
|
// if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationIDs, userID); err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to mark notifications as read",
|
// h.mongoLoggerSvc.Error("Failed to mark notifications as read",
|
||||||
zap.String("notificationID", strings.Join(req.NotificationIDs, ",")),
|
// zap.String("notificationID", strings.Join(req.NotificationIDs, ",")),
|
||||||
zap.Int64("userID", userID),
|
// zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update notification status:", err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to update notification status:", err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Notification marked as read"})
|
// return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Notification marked as read"})
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error {
|
func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error {
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
|
@ -373,9 +371,9 @@ func (h *Handler) GetUserNotification(c *fiber.Ctx) error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) GetAllRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
// func (h *Handler) GetAllRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||||
return h.notificationSvc.ListRecipientIDs(ctx, receiver)
|
// return h.notificationSvc.ListRecipientIDs(ctx, receiver)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (h *Handler) CountUnreadNotifications(c *fiber.Ctx) error {
|
func (h *Handler) CountUnreadNotifications(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,23 +26,23 @@ func (h *Handler) CreateReferralCode(c *fiber.Ctx) error {
|
||||||
)
|
)
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
|
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
|
||||||
}
|
}
|
||||||
referralCode, err := h.referralSvc.CreateReferralCode(c.Context(), userID, companyID.Value)
|
// referralCode, err := h.referralSvc.CreateReferralCode(c.Context(), userID, companyID.Value)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to create referral",
|
// h.mongoLoggerSvc.Error("Failed to create referral",
|
||||||
zap.Int64("userID", userID),
|
// zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create referral")
|
||||||
}
|
// }
|
||||||
|
|
||||||
fmt.Printf("Successfully created referral!")
|
fmt.Printf("Successfully created referral!")
|
||||||
|
|
||||||
res := domain.ConvertReferralCodeRes(referralCode)
|
// res := domain.ConvertReferralCodeRes(referralCode)
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Referral created successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) GetReferralCode(c *fiber.Ctx) error {
|
func (h *Handler) GetReferralCode(c *fiber.Ctx) error {
|
||||||
|
|
@ -72,7 +72,7 @@ func (h *Handler) GetReferralCode(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.CompanyID.Valid || user.CompanyID.Value != companyID.Value {
|
if !user.OrganizationID.Valid || user.OrganizationID.Value != companyID.Value {
|
||||||
h.mongoLoggerSvc.Warn("User attempt to login to different company",
|
h.mongoLoggerSvc.Warn("User attempt to login to different company",
|
||||||
zap.Int64("userID", userID),
|
zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
|
@ -82,88 +82,24 @@ func (h *Handler) GetReferralCode(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Failed to retrieve user")
|
return fiber.NewError(fiber.StatusBadRequest, "Failed to retrieve user")
|
||||||
}
|
}
|
||||||
|
|
||||||
referrals, err := h.referralSvc.GetReferralCodesByUser(c.Context(), user.ID)
|
// referrals, err := h.referralSvc.GetReferralCodesByUser(c.Context(), user.ID)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to get user referrals",
|
// h.mongoLoggerSvc.Error("Failed to get user referrals",
|
||||||
zap.Int64("userID", userID),
|
// zap.Int64("userID", userID),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user referral codes")
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user referral codes")
|
||||||
}
|
// }
|
||||||
|
|
||||||
result := domain.ConvertReferralCodeResList(referrals)
|
// result := domain.ConvertReferralCodeResList(referrals)
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Referral Code Fetched Successfully", result, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Referral Code Fetched Successfully", nil, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReferralStats godoc
|
|
||||||
// @Summary Get referral statistics
|
|
||||||
// @Description Retrieves referral statistics for the authenticated user
|
|
||||||
// @Tags referral
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {object} domain.ReferralStats
|
|
||||||
// @Failure 401 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Security Bearer
|
|
||||||
// @Router /api/v1/tenant/{tenant_slug}/referral/stats [get]
|
|
||||||
func (h *Handler) GetReferralStats(c *fiber.Ctx) error {
|
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
|
||||||
if !companyID.Valid {
|
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
|
||||||
}
|
|
||||||
userID, ok := c.Locals("user_id").(int64)
|
|
||||||
if !ok || userID == 0 {
|
|
||||||
h.mongoLoggerSvc.Error("Invalid user ID in context",
|
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user id")
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to get user",
|
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.CompanyID.Valid || user.CompanyID.Value != companyID.Value {
|
|
||||||
h.mongoLoggerSvc.Warn("User attempt to login to different company",
|
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Failed to retrieve user")
|
|
||||||
}
|
|
||||||
|
|
||||||
stats, err := h.referralSvc.GetReferralStats(c.Context(), user.ID, companyID.Value)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to get referral stats",
|
|
||||||
zap.Int64("userID", userID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve referral stats")
|
|
||||||
}
|
|
||||||
|
|
||||||
res := domain.ConvertReferralStatsRes(stats)
|
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Referral stats retrieved successfully", res, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// // UpdateReferralSettings godoc
|
// // UpdateReferralSettings godoc
|
||||||
// // @Summary Update referral settings
|
// // @Summary Update referral settings
|
||||||
// // @Description Updates referral settings (admin only)
|
// // @Description Updates referral settings (admin only)
|
||||||
|
|
|
||||||
|
|
@ -108,85 +108,85 @@ func (h *Handler) UpdateGlobalSettingList(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "setting updated", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "setting updated", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) SaveCompanySettingList(c *fiber.Ctx) error {
|
// func (h *Handler) SaveCompanySettingList(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
|
|
||||||
var req domain.SaveSettingListReq
|
// var req domain.SaveSettingListReq
|
||||||
|
|
||||||
if err := c.BodyParser(&req); err != nil {
|
// if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse SaveSettingListReq",
|
// h.mongoLoggerSvc.Info("Failed to parse SaveSettingListReq",
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
||||||
}
|
// }
|
||||||
valErrs, ok := h.validator.Validate(c, req)
|
// valErrs, ok := h.validator.Validate(c, req)
|
||||||
if !ok {
|
// if !ok {
|
||||||
var errMsg string
|
// var errMsg string
|
||||||
for field, msg := range valErrs {
|
// for field, msg := range valErrs {
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
// errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
}
|
// }
|
||||||
h.mongoLoggerSvc.Info("Failed to validate SaveSettingListReq",
|
// h.mongoLoggerSvc.Info("Failed to validate SaveSettingListReq",
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.String("errMsg", errMsg),
|
// zap.String("errMsg", errMsg),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
// }
|
||||||
settingList := domain.ConvertSaveSettingListReq(req)
|
// // settingList := domain.ConvertSaveSettingListReq(req)
|
||||||
err := h.settingSvc.InsertCompanySettingList(c.Context(), settingList, companyID.Value)
|
// // err := h.settingSvc.InsertCompanySettingList(c.Context(), settingList, companyID.Value)
|
||||||
|
|
||||||
if err != nil {
|
// // if err != nil {
|
||||||
h.mongoLoggerSvc.Info("failed to save setting",
|
// // h.mongoLoggerSvc.Info("failed to save setting",
|
||||||
zap.Any("setting_list", settingList),
|
// // zap.Any("setting_list", settingList),
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// // zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Time("timestamp", time.Now()),
|
// // zap.Time("timestamp", time.Now()),
|
||||||
)
|
// // )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to save setting")
|
// // return fiber.NewError(fiber.StatusInternalServerError, "failed to save setting")
|
||||||
}
|
// // }
|
||||||
|
|
||||||
settingsList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
// settingsList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to fetch settings",
|
// h.mongoLoggerSvc.Error("Failed to fetch settings",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "setting updated", settingsList, nil)
|
// return response.WriteJSON(c, fiber.StatusOK, "setting updated", settingsList, nil)
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (h *Handler) GetCompanySettingList(c *fiber.Ctx) error {
|
// func (h *Handler) GetCompanySettingList(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
|
|
||||||
settingsList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
// settingsList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to fetch settings",
|
// h.mongoLoggerSvc.Error("Failed to fetch settings",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
res := domain.ConvertSettingListRes(settingsList)
|
// res := domain.ConvertSettingListRes(settingsList)
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "All Settings retrieved successfully", res, nil)
|
// return response.WriteJSON(c, fiber.StatusOK, "All Settings retrieved successfully", res, nil)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// /api/v1/{tenant_slug}/settings/{key}
|
// /api/v1/{tenant_slug}/settings/{key}
|
||||||
func (h *Handler) DeleteCompanySetting(c *fiber.Ctx) error {
|
func (h *Handler) DeleteCompanySetting(c *fiber.Ctx) error {
|
||||||
|
|
@ -205,16 +205,16 @@ func (h *Handler) DeleteCompanySetting(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "setting key must be passed")
|
return fiber.NewError(fiber.StatusBadRequest, "setting key must be passed")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := h.settingSvc.DeleteCompanySetting(c.Context(), companyID.Value, settingKey)
|
// err := h.settingSvc.DeleteCompanySetting(c.Context(), companyID.Value, settingKey)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
// h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "setting deleted", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "setting deleted", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
@ -226,16 +226,16 @@ func (h *Handler) DeleteAllCompanySetting(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := h.settingSvc.DeleteAllCompanySetting(c.Context(), companyID.Value)
|
// err := h.settingSvc.DeleteAllCompanySetting(c.Context(), companyID.Value)
|
||||||
|
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
// h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "setting deleted", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "setting deleted", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,77 +33,77 @@ type CreateTransactionApproverReq struct {
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/admin [post]
|
// @Router /api/v1/admin [post]
|
||||||
func (h *Handler) CreateTransactionApprover(c *fiber.Ctx) error {
|
// func (h *Handler) CreateTransactionApprover(c *fiber.Ctx) error {
|
||||||
var companyID domain.ValidInt64
|
// var companyID domain.ValidInt64
|
||||||
var req CreateTransactionApproverReq
|
// var req CreateTransactionApproverReq
|
||||||
|
|
||||||
if err := c.BodyParser(&req); err != nil {
|
// if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("failed to parse CreateAdmin request",
|
// h.mongoLoggerSvc.Info("failed to parse CreateAdmin request",
|
||||||
zap.Int64("status_code", fiber.StatusBadRequest),
|
// zap.Int64("status_code", fiber.StatusBadRequest),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+err.Error())
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
valErrs, ok := h.validator.Validate(c, req)
|
// valErrs, ok := h.validator.Validate(c, req)
|
||||||
if !ok {
|
// if !ok {
|
||||||
var errMsg string
|
// var errMsg string
|
||||||
for field, msg := range valErrs {
|
// for field, msg := range valErrs {
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
// errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
}
|
// }
|
||||||
h.mongoLoggerSvc.Error("validation failed for CreateAdmin request",
|
// h.mongoLoggerSvc.Error("validation failed for CreateAdmin request",
|
||||||
zap.Int64("status_code", fiber.StatusBadRequest),
|
// zap.Int64("status_code", fiber.StatusBadRequest),
|
||||||
zap.Any("validation_errors", valErrs),
|
// zap.Any("validation_errors", valErrs),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// _, err := h.companySvc.GetCompanyByID(c.Context(), req.CompanyID)
|
// // _, err := h.companySvc.GetCompanyByID(c.Context(), req.CompanyID)
|
||||||
// if err != nil {
|
// // if err != nil {
|
||||||
// h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
// // h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
||||||
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
// // zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||||
// zap.Int64("company_id", req.CompanyID),
|
// // zap.Int64("company_id", req.CompanyID),
|
||||||
// zap.Error(err),
|
// // zap.Error(err),
|
||||||
// zap.Time("timestamp", time.Now()),
|
// // zap.Time("timestamp", time.Now()),
|
||||||
// )
|
// // )
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
// // return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
||||||
// }
|
// // }
|
||||||
companyID = domain.ValidInt64{
|
// companyID = domain.ValidInt64{
|
||||||
Value: req.CompanyID,
|
// Value: req.CompanyID,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
}
|
// }
|
||||||
|
|
||||||
user := domain.CreateUserReq{
|
// user := domain.CreateUserReq{
|
||||||
FirstName: req.FirstName,
|
// FirstName: req.FirstName,
|
||||||
LastName: req.LastName,
|
// LastName: req.LastName,
|
||||||
Email: req.Email,
|
// Email: req.Email,
|
||||||
PhoneNumber: req.PhoneNumber,
|
// PhoneNumber: req.PhoneNumber,
|
||||||
Password: req.Password,
|
// Password: req.Password,
|
||||||
Role: string(domain.RoleTransactionApprover),
|
// Role: string(domain.RoleTransactionApprover),
|
||||||
CompanyID: companyID,
|
// OrganizationID: companyID,
|
||||||
}
|
// }
|
||||||
|
|
||||||
newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
// newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("failed to create admin user",
|
// h.mongoLoggerSvc.Error("failed to create admin user",
|
||||||
zap.Int64("status_code", fiber.StatusInternalServerError),
|
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Any("request", req),
|
// zap.Any("request", req),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
h.mongoLoggerSvc.Info("transaction_approver created successfully",
|
// h.mongoLoggerSvc.Info("transaction_approver created successfully",
|
||||||
zap.Int64("transaction_approver_id", newUser.ID),
|
// zap.Int64("transaction_approver_id", newUser.ID),
|
||||||
zap.String("email", newUser.Email),
|
// zap.String("email", newUser.Email),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction Approver created successfully", nil, nil)
|
// return response.WriteJSON(c, fiber.StatusOK, "Transaction Approver created successfully", nil, nil)
|
||||||
}
|
// }
|
||||||
|
|
||||||
type TransactionApproverRes struct {
|
type TransactionApproverRes struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
|
|
@ -134,144 +134,144 @@ type TransactionApproverRes struct {
|
||||||
// @Failure 401 {object} response.APIResponse
|
// @Failure 401 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/t-approver [get]
|
// @Router /api/v1/t-approver [get]
|
||||||
func (h *Handler) GetAllTransactionApprovers(c *fiber.Ctx) error {
|
// func (h *Handler) GetAllTransactionApprovers(c *fiber.Ctx) error {
|
||||||
role := c.Locals("role").(domain.Role)
|
// role := c.Locals("role").(domain.Role)
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
|
||||||
searchQuery := c.Query("query")
|
// searchQuery := c.Query("query")
|
||||||
searchString := domain.ValidString{
|
// searchString := domain.ValidString{
|
||||||
Value: searchQuery,
|
// Value: searchQuery,
|
||||||
Valid: searchQuery != "",
|
// Valid: searchQuery != "",
|
||||||
}
|
// }
|
||||||
|
|
||||||
createdBeforeQuery := c.Query("created_before")
|
// createdBeforeQuery := c.Query("created_before")
|
||||||
var createdBefore domain.ValidTime
|
// var createdBefore domain.ValidTime
|
||||||
if createdBeforeQuery != "" {
|
// if createdBeforeQuery != "" {
|
||||||
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
// createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.logger.Info("invalid start_time format", "error", err)
|
// h.logger.Info("invalid start_time format", "error", err)
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||||
}
|
// }
|
||||||
createdBefore = domain.ValidTime{
|
// createdBefore = domain.ValidTime{
|
||||||
Value: createdBeforeParsed,
|
// Value: createdBeforeParsed,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
createdAfterQuery := c.Query("created_after")
|
// createdAfterQuery := c.Query("created_after")
|
||||||
var createdAfter domain.ValidTime
|
// var createdAfter domain.ValidTime
|
||||||
if createdAfterQuery != "" {
|
// if createdAfterQuery != "" {
|
||||||
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
// createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.logger.Info("invalid start_time format", "error", err)
|
// h.logger.Info("invalid start_time format", "error", err)
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||||
}
|
// }
|
||||||
createdAfter = domain.ValidTime{
|
// createdAfter = domain.ValidTime{
|
||||||
Value: createdAfterParsed,
|
// Value: createdAfterParsed,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
var companyIDFilter domain.ValidInt64
|
// var companyIDFilter domain.ValidInt64
|
||||||
if role == domain.RoleSuperAdmin {
|
// if role == domain.RoleSuperAdmin {
|
||||||
companyIDQuery := int64(c.QueryInt("company_id"))
|
// companyIDQuery := int64(c.QueryInt("company_id"))
|
||||||
companyIDFilter = domain.ValidInt64{
|
// companyIDFilter = domain.ValidInt64{
|
||||||
Value: companyIDQuery,
|
// Value: companyIDQuery,
|
||||||
Valid: companyIDQuery != 0,
|
// Valid: companyIDQuery != 0,
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.logger.Info("invalid companyID")
|
// h.logger.Info("invalid companyID")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Unable to get company ID")
|
// return fiber.NewError(fiber.StatusBadRequest, "Unable to get company ID")
|
||||||
}
|
// }
|
||||||
|
|
||||||
companyIDFilter = companyID
|
// companyIDFilter = companyID
|
||||||
}
|
// }
|
||||||
|
|
||||||
filter := domain.UserFilter{
|
// filter := domain.UserFilter{
|
||||||
Role: string(domain.RoleTransactionApprover),
|
// Role: string(domain.RoleTransactionApprover),
|
||||||
CompanyID: companyIDFilter,
|
// OrganizationID: companyIDFilter,
|
||||||
Page: domain.ValidInt{
|
// Page: domain.ValidInt{
|
||||||
Value: c.QueryInt("page", 1) - 1,
|
// Value: c.QueryInt("page", 1) - 1,
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
},
|
// },
|
||||||
PageSize: domain.ValidInt{
|
// PageSize: domain.ValidInt{
|
||||||
Value: c.QueryInt("page_size", 10),
|
// Value: c.QueryInt("page_size", 10),
|
||||||
Valid: true,
|
// Valid: true,
|
||||||
},
|
// },
|
||||||
Query: searchString,
|
// Query: searchString,
|
||||||
CreatedBefore: createdBefore,
|
// CreatedBefore: createdBefore,
|
||||||
CreatedAfter: createdAfter,
|
// CreatedAfter: createdAfter,
|
||||||
}
|
// }
|
||||||
|
|
||||||
valErrs, ok := h.validator.Validate(c, filter)
|
// valErrs, ok := h.validator.Validate(c, filter)
|
||||||
if !ok {
|
// if !ok {
|
||||||
var errMsg string
|
// var errMsg string
|
||||||
for field, msg := range valErrs {
|
// for field, msg := range valErrs {
|
||||||
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
// errMsg += fmt.Sprintf("%s: %s; ", field, msg)
|
||||||
}
|
// }
|
||||||
h.mongoLoggerSvc.Info("invalid filter values in GetAllAdmins request",
|
// h.mongoLoggerSvc.Info("invalid filter values in GetAllAdmins request",
|
||||||
zap.Int("status_code", fiber.StatusBadRequest),
|
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
zap.Any("validation_errors", valErrs),
|
// zap.Any("validation_errors", valErrs),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
users, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
// users, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
h.mongoLoggerSvc.Error("failed to get users from user service",
|
// h.mongoLoggerSvc.Error("failed to get users from user service",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Any("filter", filter),
|
// zap.Any("filter", filter),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users"+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
result := make([]TransactionApproverRes, len(users))
|
// result := make([]TransactionApproverRes, len(users))
|
||||||
for index, admin := range users {
|
// for index, admin := range users {
|
||||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID)
|
// lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
if err == authentication.ErrRefreshTokenNotFound {
|
// if err == authentication.ErrRefreshTokenNotFound {
|
||||||
lastLogin = &admin.CreatedAt
|
// lastLogin = &admin.CreatedAt
|
||||||
} else {
|
// } else {
|
||||||
h.mongoLoggerSvc.Error("failed to get last login for admin",
|
// h.mongoLoggerSvc.Error("failed to get last login for admin",
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
zap.Int64("admin_id", admin.ID),
|
// zap.Int64("admin_id", admin.ID),
|
||||||
zap.Error(err),
|
// zap.Error(err),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
result[index] = TransactionApproverRes{
|
// result[index] = TransactionApproverRes{
|
||||||
ID: admin.ID,
|
// ID: admin.ID,
|
||||||
FirstName: admin.FirstName,
|
// FirstName: admin.FirstName,
|
||||||
LastName: admin.LastName,
|
// LastName: admin.LastName,
|
||||||
Email: admin.Email,
|
// Email: admin.Email,
|
||||||
PhoneNumber: admin.PhoneNumber,
|
// PhoneNumber: admin.PhoneNumber,
|
||||||
Role: admin.Role,
|
// Role: admin.Role,
|
||||||
EmailVerified: admin.EmailVerified,
|
// EmailVerified: admin.EmailVerified,
|
||||||
PhoneVerified: admin.PhoneVerified,
|
// PhoneVerified: admin.PhoneVerified,
|
||||||
CreatedAt: admin.CreatedAt,
|
// CreatedAt: admin.CreatedAt,
|
||||||
UpdatedAt: admin.UpdatedAt,
|
// UpdatedAt: admin.UpdatedAt,
|
||||||
SuspendedAt: admin.SuspendedAt,
|
// SuspendedAt: admin.SuspendedAt,
|
||||||
Suspended: admin.Suspended,
|
// Suspended: admin.Suspended,
|
||||||
LastLogin: *lastLogin,
|
// LastLogin: *lastLogin,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
h.mongoLoggerSvc.Info("approvers retrieved successfully",
|
// h.mongoLoggerSvc.Info("approvers retrieved successfully",
|
||||||
zap.Int("status_code", fiber.StatusOK),
|
// zap.Int("status_code", fiber.StatusOK),
|
||||||
zap.Int("count", len(result)),
|
// zap.Int("count", len(result)),
|
||||||
zap.Int("page", filter.Page.Value+1),
|
// zap.Int("page", filter.Page.Value+1),
|
||||||
zap.Time("timestamp", time.Now()),
|
// zap.Time("timestamp", time.Now()),
|
||||||
)
|
// )
|
||||||
|
|
||||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total))
|
// return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total))
|
||||||
}
|
// }
|
||||||
|
|
||||||
// GetAdminByID godoc
|
// GetAdminByID godoc
|
||||||
// @Summary Get admin by id
|
// @Summary Get admin by id
|
||||||
|
|
@ -404,7 +404,7 @@ func (h *Handler) UpdateTransactionApprover(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||||
UserId: ApproverID,
|
UserID: ApproverID,
|
||||||
FirstName: domain.ValidString{
|
FirstName: domain.ValidString{
|
||||||
Value: req.FirstName,
|
Value: req.FirstName,
|
||||||
Valid: req.FirstName != "",
|
Valid: req.FirstName != "",
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (h *Handler) GetTenantSlugByToken(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.CompanyID.Valid {
|
if !user.OrganizationID.Valid {
|
||||||
if user.Role == domain.RoleSuperAdmin {
|
if user.Role == domain.RoleSuperAdmin {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Role Super-Admin Doesn't have a company-id")
|
return fiber.NewError(fiber.StatusBadRequest, "Role Super-Admin Doesn't have a company-id")
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ func (h *Handler) GetTenantSlugByToken(c *fiber.Ctx) error {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
res := GetTenantSlugByToken{
|
res := GetTenantSlugByToken{
|
||||||
Slug: strconv.FormatInt(user.CompanyID.Value,10),
|
Slug: strconv.FormatInt(user.OrganizationID.Value, 10),
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Tenant Slug retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Tenant Slug retrieved successfully", res, nil)
|
||||||
|
|
@ -102,11 +102,11 @@ type CheckPhoneEmailExistRes struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/checkPhoneEmailExist [post]
|
// @Router /api/v1/{tenant_slug}/user/checkPhoneEmailExist [post]
|
||||||
func (h *Handler) CheckPhoneEmailExist(c *fiber.Ctx) error {
|
func (h *Handler) CheckPhoneEmailExist(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
var req CheckPhoneEmailExistReq
|
var req CheckPhoneEmailExistReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse CheckPhoneEmailExist request",
|
h.mongoLoggerSvc.Info("Failed to parse CheckPhoneEmailExist request",
|
||||||
|
|
@ -125,7 +125,7 @@ func (h *Handler) CheckPhoneEmailExist(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
emailExist, phoneExist, err := h.userSvc.CheckPhoneEmailExist(c.Context(), req.PhoneNumber, req.Email, companyID)
|
emailExist, phoneExist, err := h.userSvc.CheckPhoneEmailExist(c.Context(), req.PhoneNumber, req.Email, domain.ValidInt64{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to check phone/email existence",
|
h.mongoLoggerSvc.Error("Failed to check phone/email existence",
|
||||||
zap.Any("request", req),
|
zap.Any("request", req),
|
||||||
|
|
@ -160,11 +160,11 @@ type RegisterCodeReq struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/sendRegisterCode [post]
|
// @Router /api/v1/{tenant_slug}/user/sendRegisterCode [post]
|
||||||
func (h *Handler) SendRegisterCode(c *fiber.Ctx) error {
|
func (h *Handler) SendRegisterCode(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
var req RegisterCodeReq
|
var req RegisterCodeReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse SendRegisterCode request",
|
h.mongoLoggerSvc.Info("Failed to parse SendRegisterCode request",
|
||||||
|
|
@ -195,7 +195,7 @@ func (h *Handler) SendRegisterCode(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Email or PhoneNumber must be provided")
|
return fiber.NewError(fiber.StatusBadRequest, "Email or PhoneNumber must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.userSvc.SendRegisterCode(c.Context(), medium, sentTo, domain.AfroMessage, companyID); err != nil {
|
if err := h.userSvc.SendRegisterCode(c.Context(), medium, sentTo, domain.AfroMessage, domain.ValidInt64{}); err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to send register code",
|
h.mongoLoggerSvc.Error("Failed to send register code",
|
||||||
zap.String("Medium", string(medium)),
|
zap.String("Medium", string(medium)),
|
||||||
zap.String("Send To", string(sentTo)),
|
zap.String("Send To", string(sentTo)),
|
||||||
|
|
@ -231,11 +231,6 @@ type RegisterUserReq struct {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/register [post]
|
// @Router /api/v1/{tenant_slug}/user/register [post]
|
||||||
func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
|
||||||
if !companyID.Valid {
|
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
|
||||||
}
|
|
||||||
var req RegisterUserReq
|
var req RegisterUserReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse RegisterUser request",
|
h.mongoLoggerSvc.Info("Failed to parse RegisterUser request",
|
||||||
|
|
@ -254,16 +249,16 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
user := domain.RegisterUserReq{
|
user := domain.RegisterUserReq{
|
||||||
FirstName: req.FirstName,
|
FirstName: req.FirstName,
|
||||||
LastName: req.LastName,
|
LastName: req.LastName,
|
||||||
Email: req.Email,
|
Email: req.Email,
|
||||||
PhoneNumber: req.PhoneNumber,
|
PhoneNumber: req.PhoneNumber,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Otp: req.Otp,
|
Otp: req.Otp,
|
||||||
ReferralCode: req.ReferralCode,
|
ReferralCode: req.ReferralCode,
|
||||||
OtpMedium: domain.OtpMediumEmail,
|
OtpMedium: domain.OtpMediumEmail,
|
||||||
CompanyID: companyID,
|
OrganizationID: domain.ValidInt64{},
|
||||||
Role: string(domain.RoleCustomer),
|
Role: string(domain.RoleStudent),
|
||||||
}
|
}
|
||||||
medium, err := getMedium(req.Email, req.PhoneNumber)
|
medium, err := getMedium(req.Email, req.PhoneNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -279,7 +274,7 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
|
|
||||||
user.OtpMedium = medium
|
user.OtpMedium = medium
|
||||||
|
|
||||||
newUser, err := h.userSvc.RegisterUser(c.Context(), user)
|
_, err = h.userSvc.RegisterUser(c.Context(), user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, domain.ErrOtpAlreadyUsed) {
|
if errors.Is(err, domain.ErrOtpAlreadyUsed) {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Otp already used")
|
return fiber.NewError(fiber.StatusBadRequest, "Otp already used")
|
||||||
|
|
@ -303,44 +298,6 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to register user:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to register user:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// _, err = h.walletSvc.CreateCustomerWallet(c.Context(), newUser.ID)
|
|
||||||
// if err != nil {
|
|
||||||
// h.mongoLoggerSvc.Error("Failed to create wallet for user",
|
|
||||||
// zap.Int64("userID", newUser.ID),
|
|
||||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
// zap.Error(err),
|
|
||||||
// zap.Time("timestamp", time.Now()),
|
|
||||||
// )
|
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create user wallet:"+err.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
if req.ReferralCode != "" {
|
|
||||||
err = h.referralSvc.ProcessReferral(c.Context(), newUser.ID, req.ReferralCode, companyID.Value)
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to process referral during registration",
|
|
||||||
zap.String("phone", req.PhoneNumber),
|
|
||||||
zap.String("code", req.ReferralCode),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove later
|
|
||||||
// _, err = h.walletSvc.AddToWallet(
|
|
||||||
// c.Context(), newWallet.RegularID, domain.ToCurrency(10000.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
|
||||||
// "Added 10000.0 to wallet only as test for deployment")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
h.mongoLoggerSvc.Error("Failed to update wallet for user",
|
|
||||||
zap.Int64("userID", newUser.ID),
|
|
||||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
zap.Error(err),
|
|
||||||
zap.Time("timestamp", time.Now()),
|
|
||||||
)
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update user wallet:"+err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Registration successful", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Registration successful", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,11 +381,11 @@ func (h *Handler) SendResetCode(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/sendResetCode [post]
|
// @Router /api/v1/{tenant_slug}/user/sendResetCode [post]
|
||||||
func (h *Handler) SendTenantResetCode(c *fiber.Ctx) error {
|
func (h *Handler) SendTenantResetCode(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
var req ResetCodeReq
|
var req ResetCodeReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
h.mongoLoggerSvc.Info("Failed to parse SendResetCode request",
|
h.mongoLoggerSvc.Info("Failed to parse SendResetCode request",
|
||||||
|
|
@ -465,7 +422,7 @@ func (h *Handler) SendTenantResetCode(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Email or PhoneNumber must be provided")
|
return fiber.NewError(fiber.StatusBadRequest, "Email or PhoneNumber must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.userSvc.SendResetCode(c.Context(), medium, sentTo, domain.AfroMessage, companyID); err != nil {
|
if err := h.userSvc.SendResetCode(c.Context(), medium, sentTo, domain.AfroMessage, domain.ValidInt64{}); err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to send reset code",
|
h.mongoLoggerSvc.Error("Failed to send reset code",
|
||||||
zap.String("medium", string(medium)),
|
zap.String("medium", string(medium)),
|
||||||
zap.String("sentTo", string(sentTo)),
|
zap.String("sentTo", string(sentTo)),
|
||||||
|
|
@ -562,11 +519,11 @@ func (h *Handler) ResetPassword(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/resetPassword [post]
|
// @Router /api/v1/{tenant_slug}/user/resetPassword [post]
|
||||||
func (h *Handler) ResetTenantPassword(c *fiber.Ctx) error {
|
func (h *Handler) ResetTenantPassword(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
|
|
||||||
var req ResetPasswordReq
|
var req ResetPasswordReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
@ -599,12 +556,12 @@ func (h *Handler) ResetTenantPassword(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
resetReq := domain.ResetPasswordReq{
|
resetReq := domain.ResetPasswordReq{
|
||||||
Email: req.Email,
|
Email: req.Email,
|
||||||
PhoneNumber: req.PhoneNumber,
|
PhoneNumber: req.PhoneNumber,
|
||||||
Password: req.Password,
|
Password: req.Password,
|
||||||
Otp: req.Otp,
|
Otp: req.Otp,
|
||||||
OtpMedium: medium,
|
OtpMedium: medium,
|
||||||
CompanyID: companyID.Value,
|
OrganizationID: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.userSvc.ResetPassword(c.Context(), resetReq); err != nil {
|
if err := h.userSvc.ResetPassword(c.Context(), resetReq); err != nil {
|
||||||
|
|
@ -852,9 +809,14 @@ func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
// strCompanyID := fmt.Sprintf("%v", companyID)
|
||||||
|
role, err := strconv.ParseInt(string(*req.Role), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "failed to get users"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, req.Role, companyID)
|
users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, &role, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to get user by name or phone",
|
h.mongoLoggerSvc.Error("Failed to get user by name or phone",
|
||||||
zap.Any("request", req),
|
zap.Any("request", req),
|
||||||
|
|
@ -912,11 +874,11 @@ func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error {
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/user/search [post]
|
// @Router /api/v1/{tenant_slug}/user/search [post]
|
||||||
func (h *Handler) SearchCompanyUserByNameOrPhone(c *fiber.Ctx) error {
|
func (h *Handler) SearchCompanyUserByNameOrPhone(c *fiber.Ctx) error {
|
||||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||||
if !companyID.Valid {
|
// if !companyID.Valid {
|
||||||
h.BadRequestLogger().Error("invalid company id")
|
// h.BadRequestLogger().Error("invalid company id")
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
// return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||||
}
|
// }
|
||||||
|
|
||||||
var req SearchUserByNameOrPhoneReq
|
var req SearchUserByNameOrPhoneReq
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
@ -937,7 +899,13 @@ func (h *Handler) SearchCompanyUserByNameOrPhone(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, req.Role, companyID)
|
// strCompanyID := fmt.Sprintf("%v", companyID)
|
||||||
|
role, err := strconv.ParseInt(string(*req.Role), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "failed to get users"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := h.userSvc.SearchUserByNameOrPhone(c.Context(), req.SearchString, &role, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to get user by name or phone",
|
h.mongoLoggerSvc.Error("Failed to get user by name or phone",
|
||||||
zap.Any("request", req),
|
zap.Any("request", req),
|
||||||
|
|
@ -1162,43 +1130,3 @@ func (h *Handler) UpdateUserSuspend(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "User suspend status updated successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "User suspend status updated successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBetByUserID godoc
|
|
||||||
// @Summary Gets user bets
|
|
||||||
// @Description Gets user bets
|
|
||||||
// @Tags user
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {array} domain.BetRes
|
|
||||||
// @Failure 400 {object} response.APIResponse
|
|
||||||
// @Failure 500 {object} response.APIResponse
|
|
||||||
// @Router /api/v1/{tenant_slug}/user/bets [get]
|
|
||||||
// func (h *Handler) GetBetByUserID(c *fiber.Ctx) error {
|
|
||||||
// userID, ok := c.Locals("user_id").(int64)
|
|
||||||
// if !ok || userID == 0 {
|
|
||||||
// h.mongoLoggerSvc.Error("Invalid user ID in context",
|
|
||||||
// zap.Int64("userID", userID),
|
|
||||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
// zap.Time("timestamp", time.Now()),
|
|
||||||
// )
|
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // bets, err := h.betSvc.GetBetByUserID(c.Context(), userID)
|
|
||||||
// // if err != nil {
|
|
||||||
// // h.mongoLoggerSvc.Error("Failed to get bets",
|
|
||||||
// // zap.Int64("userID", userID),
|
|
||||||
// // zap.Int("status_code", fiber.StatusInternalServerError),
|
|
||||||
// // zap.Error(err),
|
|
||||||
// // zap.Time("timestamp", time.Now()),
|
|
||||||
// // )
|
|
||||||
// // return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets:"+err.Error())
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // res := make([]domain.BetRes, len(bets))
|
|
||||||
// // for i, bet := range bets {
|
|
||||||
// // res[i] = domain.ConvertBet(bet)
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// return response.WriteJSON(c, fiber.StatusOK, "User bets retrieved successfully", res, nil)
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,6 @@ type UserClaim struct {
|
||||||
CompanyID domain.NullJwtInt64
|
CompanyID domain.NullJwtInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PopOKClaim struct {
|
|
||||||
jwt.RegisteredClaims
|
|
||||||
UserID int64 `json:"user_id"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Lang string `json:"lang"`
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
SessionID string `json:"session_id"`
|
|
||||||
CompanyID domain.NullJwtInt64 `json:"company_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type JwtConfig struct {
|
type JwtConfig struct {
|
||||||
JwtAccessKey string
|
JwtAccessKey string
|
||||||
JwtAccessExpiry int
|
JwtAccessExpiry int
|
||||||
|
|
@ -42,9 +31,9 @@ type JwtConfig struct {
|
||||||
func CreateJwt(userId int64, Role domain.Role, CompanyID domain.ValidInt64, key string, expiry int) (string, error) {
|
func CreateJwt(userId int64, Role domain.Role, CompanyID domain.ValidInt64, key string, expiry int) (string, error) {
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim{
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim{
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
Issuer: "fortune-bet",
|
Issuer: "yimaru.com",
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
Audience: jwt.ClaimStrings{"api.fortunebets.net"},
|
Audience: jwt.ClaimStrings{"api.yimaru.com"},
|
||||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expiry) * time.Second)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expiry) * time.Second)),
|
||||||
},
|
},
|
||||||
|
|
@ -59,29 +48,6 @@ func CreateJwt(userId int64, Role domain.Role, CompanyID domain.ValidInt64, key
|
||||||
return jwtToken, err
|
return jwtToken, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePopOKJwt(userID int64, CompanyID domain.ValidInt64, username, currency, lang, mode, sessionID, key string, expiry time.Duration) (string, error) {
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, PopOKClaim{
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
Issuer: "fortune-bet",
|
|
||||||
Audience: jwt.ClaimStrings{"popokgaming.com"},
|
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
||||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiry)),
|
|
||||||
},
|
|
||||||
UserID: userID,
|
|
||||||
Username: username, // ✅ Must be a valid string
|
|
||||||
Currency: currency,
|
|
||||||
Lang: lang,
|
|
||||||
Mode: mode,
|
|
||||||
SessionID: sessionID,
|
|
||||||
CompanyID: domain.NullJwtInt64{
|
|
||||||
Value: CompanyID.Value,
|
|
||||||
Valid: CompanyID.Valid,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return token.SignedString([]byte(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseJwt(jwtToken string, key string) (*UserClaim, error) {
|
func ParseJwt(jwtToken string, key string) (*UserClaim, error) {
|
||||||
token, err := jwt.ParseWithClaims(jwtToken, &UserClaim{}, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.ParseWithClaims(jwtToken, &UserClaim{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
return []byte(key), nil
|
return []byte(key), nil
|
||||||
|
|
@ -101,22 +67,3 @@ func ParseJwt(jwtToken string, key string) (*UserClaim, error) {
|
||||||
}
|
}
|
||||||
return nil, errors.New("invalid token claims")
|
return nil, errors.New("invalid token claims")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParsePopOKJwt(jwtToken string, key string) (*PopOKClaim, error) {
|
|
||||||
token, err := jwt.ParseWithClaims(jwtToken, &PopOKClaim{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return []byte(key), nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, jwt.ErrTokenExpired) {
|
|
||||||
return nil, ErrExpiredToken
|
|
||||||
}
|
|
||||||
if errors.Is(err, jwt.ErrTokenMalformed) {
|
|
||||||
return nil, ErrMalformedToken
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if claims, ok := token.Claims.(*PopOKClaim); ok && token.Valid {
|
|
||||||
return claims, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("invalid PopOK token claims")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ package jwtutil
|
||||||
// // Verify that the claims match the user and other values
|
// // Verify that the claims match the user and other values
|
||||||
// assert.Equal(t, strconv.Itoa(int(user.ID)), claims.UserId, "User ID should match")
|
// assert.Equal(t, strconv.Itoa(int(user.ID)), claims.UserId, "User ID should match")
|
||||||
// assert.Equal(t, "github.com/lafetz/snippitstash", claims.Issuer, "Issuer should match")
|
// assert.Equal(t, "github.com/lafetz/snippitstash", claims.Issuer, "Issuer should match")
|
||||||
// assert.Equal(t, "fortune.com", claims.Audience[0], "Audience should match")
|
|
||||||
// assert.True(t, claims.ExpiresAt.Time.After(time.Now()), "Token should not be expired yet")
|
// assert.True(t, claims.ExpiresAt.Time.After(time.Now()), "Token should not be expired yet")
|
||||||
|
|
||||||
// // Ensure the parsing fails when using an invalid token
|
// // Ensure the parsing fails when using an invalid token
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ func (a *App) SuperAdminOnly(c *fiber.Ctx) error {
|
||||||
func (a *App) CompanyOnly(c *fiber.Ctx) error {
|
func (a *App) CompanyOnly(c *fiber.Ctx) error {
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
userRole := c.Locals("role").(domain.Role)
|
userRole := c.Locals("role").(domain.Role)
|
||||||
if userRole == domain.RoleCustomer {
|
if userRole == domain.RoleStudent {
|
||||||
a.mongoLoggerSvc.Warn("Attempt to access restricted CompanyOnly route",
|
a.mongoLoggerSvc.Warn("Attempt to access restricted CompanyOnly route",
|
||||||
zap.Int64("userID", userID),
|
zap.Int64("userID", userID),
|
||||||
zap.String("role", string(userRole)),
|
zap.String("role", string(userRole)),
|
||||||
|
|
@ -159,7 +159,7 @@ func (a *App) OnlyAdminAndAbove(c *fiber.Ctx) error {
|
||||||
func (a *App) OnlyBranchManagerAndAbove(c *fiber.Ctx) error {
|
func (a *App) OnlyBranchManagerAndAbove(c *fiber.Ctx) error {
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
userRole := c.Locals("role").(domain.Role)
|
userRole := c.Locals("role").(domain.Role)
|
||||||
if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin && userRole != domain.RoleBranchManager {
|
if userRole != domain.RoleSuperAdmin && userRole != domain.RoleAdmin {
|
||||||
a.mongoLoggerSvc.Warn("Attempt to access restricted OnlyBranchMangerAndAbove route",
|
a.mongoLoggerSvc.Warn("Attempt to access restricted OnlyBranchMangerAndAbove route",
|
||||||
zap.Int64("userID", userID),
|
zap.Int64("userID", userID),
|
||||||
zap.String("role", string(userRole)),
|
zap.String("role", string(userRole)),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ func (a *App) initAppRoutes() {
|
||||||
a.settingSvc,
|
a.settingSvc,
|
||||||
a.NotidicationStore,
|
a.NotidicationStore,
|
||||||
a.validator,
|
a.validator,
|
||||||
a.referralSvc,
|
|
||||||
a.recommendationSvc,
|
a.recommendationSvc,
|
||||||
a.userSvc,
|
a.userSvc,
|
||||||
a.transactionSvc,
|
a.transactionSvc,
|
||||||
|
|
@ -70,20 +69,12 @@ func (a *App) initAppRoutes() {
|
||||||
// Get S
|
// Get S
|
||||||
groupV1.Get("/tenant", a.authMiddleware, h.GetTenantSlugByToken)
|
groupV1.Get("/tenant", a.authMiddleware, h.GetTenantSlugByToken)
|
||||||
|
|
||||||
//Direct_deposit
|
|
||||||
// groupV1.Post("/direct-deposits", a.authMiddleware, h.CreateDirectDeposit)
|
|
||||||
// groupV1.Post("/direct-deposits/:depositID/approve", a.authMiddleware, h.ApproveDirectDeposit)
|
|
||||||
// groupV1.Post("/direct-deposits/:depositID/reject", a.authMiddleware, h.RejectDirectDeposit)
|
|
||||||
// groupV1.Get("/direct-deposits", a.authMiddleware, h.GetDirectDepositsByStatus)
|
|
||||||
// groupV1.Get("/direct-deposits/:depositID", a.authMiddleware, h.GetDirectDepositByID)
|
|
||||||
// groupV1.Delete("/direct-deposits/:depositID", a.authMiddleware, h.DeleteDirectDeposit)
|
|
||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
||||||
|
|
||||||
groupV1.Get("/", func(c *fiber.Ctx) error {
|
groupV1.Get("/", func(c *fiber.Ctx) error {
|
||||||
return c.JSON(fiber.Map{
|
return c.JSON(fiber.Map{
|
||||||
"message": "FortuneBet API V1",
|
"message": "Welcome to Yimaru Backend API v1",
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -128,23 +119,7 @@ func (a *App) initAppRoutes() {
|
||||||
// groupV1.Post("/arifpay/b2c/transfer", a.authMiddleware, h.ExecuteArifpayB2CTransfer)
|
// groupV1.Post("/arifpay/b2c/transfer", a.authMiddleware, h.ExecuteArifpayB2CTransfer)
|
||||||
// groupV1.Post("/arifpay/transaction-id/verify-transaction", a.authMiddleware, h.ArifpayVerifyByTransactionIDHandler)
|
// groupV1.Post("/arifpay/transaction-id/verify-transaction", a.authMiddleware, h.ArifpayVerifyByTransactionIDHandler)
|
||||||
// groupV1.Get("/arifpay/session-id/verify-transaction/:session_id", a.authMiddleware, h.ArifpayVerifyBySessionIDHandler)
|
// groupV1.Get("/arifpay/session-id/verify-transaction/:session_id", a.authMiddleware, h.ArifpayVerifyBySessionIDHandler)
|
||||||
// groupV1.Get("/arifpay/payment-methods", a.authMiddleware, h.GetArifpayPaymentMethodsHandler)
|
// groupV1.Get("/arifpay/payment-methods", a.authMiddleware, h.GetArifpayPaymentMethodsHandler
|
||||||
|
|
||||||
//Telebirr
|
|
||||||
// groupV1.Post("/telebirr/init-payment", a.authMiddleware, h.CreateTelebirrPaymentHandler)
|
|
||||||
// groupV1.Post("/telebirr/callback", h.HandleTelebirrCallback)
|
|
||||||
|
|
||||||
//Santimpay
|
|
||||||
// groupV1.Post("/santimpay/init-payment", a.authMiddleware, h.InititateSantimPayPaymentHandler)
|
|
||||||
// groupV1.Post("/santimpay/callback", h.ProcessSantimPayCallbackHandler)
|
|
||||||
// groupV1.Post("/santimpay/direct-payment", a.authMiddleware, h.ProcessSantimPayDirectPaymentHandler)
|
|
||||||
// groupV1.Get("/santimpay/b2c/partners", h.GetSantimPayB2CPartnersHandler)
|
|
||||||
// groupV1.Post("/santimpay/b2c/withdraw", a.authMiddleware, h.ProcessSantimPayB2CWithdrawalHandler)
|
|
||||||
// groupV1.Post("/santimpay/transaction/verify", a.authMiddleware, h.CheckSantimPayTransactionStatusHandler)
|
|
||||||
|
|
||||||
// groupV1.Post("/arifpay/b2c/transfer", a.authMiddleware, h.B2CTransferHandler)
|
|
||||||
// groupV1.Post("/arifpay/transaction-id/verify-transaction", a.authMiddleware, h.ArifpayVerifyByTransactionIDHandler)
|
|
||||||
// groupV1.Get("/arifpay/session-id/verify-transaction/:session_id", a.authMiddleware, h.ArifpayVerifyBySessionIDHandler)
|
|
||||||
|
|
||||||
// User Routes
|
// User Routes
|
||||||
groupV1.Post("/user/resetPassword", h.ResetPassword)
|
groupV1.Post("/user/resetPassword", h.ResetPassword)
|
||||||
|
|
@ -159,272 +134,26 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
groupV1.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
||||||
|
|
||||||
tenant.Get("/user/customer-profile", a.authMiddleware, h.CustomerProfile)
|
tenant.Get("/user/customer-profile", a.authMiddleware, h.CustomerProfile)
|
||||||
// tenant.Get("/user/bets", a.authMiddleware, h.GetBetByUserID)
|
|
||||||
|
|
||||||
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
||||||
groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
||||||
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
||||||
groupV1.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
|
groupV1.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
|
||||||
// tenant.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet)
|
|
||||||
|
|
||||||
// Referral Routes
|
|
||||||
tenant.Post("/referral/create", a.authMiddleware, h.CreateReferralCode)
|
|
||||||
tenant.Get("/referral/code", a.authMiddleware, h.GetReferralCode)
|
|
||||||
tenant.Get("/referral/stats", a.authMiddleware, h.GetReferralStats)
|
|
||||||
|
|
||||||
// groupV1.Post("/referral/settings", a.authMiddleware, h.CreateReferralSettings)
|
|
||||||
// groupV1.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings)
|
|
||||||
// groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
|
|
||||||
|
|
||||||
// Raffle Routes
|
|
||||||
// tenant.Get("/raffle/list", h.GetTenantRaffles)
|
|
||||||
// a.fiber.Get("/raffle/standing/:id/:limit", h.GetRaffleStanding) //This needs to be accessible by non-login user
|
|
||||||
// a.fiber.Post("/raffle/create", a.authMiddleware, h.CreateRaffle)
|
|
||||||
// a.fiber.Post("/raffle/add-filter", a.authMiddleware, h.AddRaffleFilter)
|
|
||||||
// a.fiber.Get("/raffle/delete/:id", a.authMiddleware, h.DeleteRaffle)
|
|
||||||
// a.fiber.Get("/raffle/company/:id", a.authMiddleware, h.GetRafflesOfCompany)
|
|
||||||
// a.fiber.Get("raffle/winners/:id/:limit", a.authMiddleware, h.GetRaffleWinners)
|
|
||||||
|
|
||||||
// a.fiber.Post("/raffle-ticket/create", a.authMiddleware, h.CreateRaffleTicket)
|
|
||||||
// a.fiber.Get("/raffle-ticket/:id", a.authMiddleware, h.GetUserRaffleTickets)
|
|
||||||
// a.fiber.Get("/raffle-ticket/suspend/:id", a.authMiddleware, h.SuspendRaffleTicket)
|
|
||||||
// a.fiber.Get("/raffle-ticket/unsuspend/:id", a.authMiddleware, h.UnSuspendRaffleTicket)
|
|
||||||
|
|
||||||
// Bonus Routes
|
|
||||||
// tenant.Get("/bonus", a.authMiddleware, h.GetBonusesByUserID)
|
|
||||||
// tenant.Get("/bonus/stats", a.authMiddleware, h.GetBonusStats)
|
|
||||||
// tenant.Post("/bonus/claim/:id", a.authMiddleware, h.ClaimBonus)
|
|
||||||
// groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier)
|
|
||||||
// groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier)
|
|
||||||
|
|
||||||
groupV1.Get("/cashiers", a.authMiddleware, a.CompanyOnly, h.GetAllCashiers)
|
|
||||||
groupV1.Get("/cashiers/:id", a.authMiddleware, a.CompanyOnly, h.GetCashierByID)
|
|
||||||
groupV1.Post("/cashiers", a.authMiddleware, a.CompanyOnly, h.CreateCashier)
|
|
||||||
groupV1.Put("/cashiers/:id", a.authMiddleware, a.CompanyOnly, h.UpdateCashier)
|
|
||||||
|
|
||||||
// tenant.Get("/customer", a.authMiddleware, a.CompanyOnly, h.GetAllTenantCustomers)
|
|
||||||
// tenant.Get("/customer/:id", a.authMiddleware, a.CompanyOnly, h.GetTenantCustomerByID)
|
|
||||||
// tenant.Put("/customer/:id", a.authMiddleware, a.CompanyOnly, h.UpdateTenantCustomer)
|
|
||||||
// // tenant.Get("/customer/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetTenantCustomerBets)
|
|
||||||
|
|
||||||
// groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers)
|
|
||||||
// groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID)
|
|
||||||
// groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer)
|
|
||||||
// groupV1.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets)
|
|
||||||
|
|
||||||
groupV1.Get("/admin", a.authMiddleware, a.SuperAdminOnly, h.GetAllAdmins)
|
groupV1.Get("/admin", a.authMiddleware, a.SuperAdminOnly, h.GetAllAdmins)
|
||||||
groupV1.Get("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.GetAdminByID)
|
groupV1.Get("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.GetAdminByID)
|
||||||
groupV1.Post("/admin", a.authMiddleware, a.SuperAdminOnly, h.CreateAdmin)
|
groupV1.Post("/admin", a.authMiddleware, a.SuperAdminOnly, h.CreateAdmin)
|
||||||
groupV1.Put("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAdmin)
|
groupV1.Put("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAdmin)
|
||||||
|
|
||||||
groupV1.Get("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllTransactionApprovers)
|
// groupV1.Get("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllTransactionApprovers)
|
||||||
groupV1.Get("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetTransactionApproverByID)
|
// groupV1.Get("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetTransactionApproverByID)
|
||||||
groupV1.Post("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateTransactionApprover)
|
// groupV1.Post("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateTransactionApprover)
|
||||||
groupV1.Put("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateTransactionApprover)
|
// groupV1.Put("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateTransactionApprover)
|
||||||
|
|
||||||
groupV1.Get("/managers", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllManagers)
|
|
||||||
groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID)
|
|
||||||
groupV1.Post("/managers", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateManager)
|
|
||||||
groupV1.Put("/managers/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateManagers)
|
|
||||||
// groupV1.Get("/manager/:id/branch", a.authMiddleware, a.OnlyAdminAndAbove, h.GetBranchByManagerID)
|
|
||||||
|
|
||||||
// groupV1.Get("/odds", a.authMiddleware, a.SuperAdminOnly, h.GetAllOdds)
|
|
||||||
// groupV1.Get("/odds/upcoming/:upcoming_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByUpcomingID)
|
|
||||||
// groupV1.Get("/odds/upcoming/:upcoming_id/market/:market_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByMarketID)
|
|
||||||
// groupV1.Post("/odds/settings", a.authMiddleware, a.SuperAdminOnly, h.SaveOddSettings)
|
|
||||||
// groupV1.Get("/odds/market-settings", a.authMiddleware, a.SuperAdminOnly, h.GetAllGlobalMarketSettings)
|
|
||||||
// groupV1.Put("/odds/bet-outcome/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAllBetOutcomeStatusByOddID)
|
|
||||||
// groupV1.Put("/odds/bet-outcome", a.authMiddleware, a.SuperAdminOnly, h.BulkUpdateAllBetOutcomeStatusByOddID)
|
|
||||||
|
|
||||||
// tenant.Get("/odds", h.GetAllTenantOdds)
|
|
||||||
// tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
|
|
||||||
// tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID)
|
|
||||||
// tenant.Post("/odds/settings", a.authMiddleware, a.CompanyOnly, h.SaveTenantOddsSetting)
|
|
||||||
// tenant.Delete("/odds/settings/:id", a.authMiddleware, a.CompanyOnly, h.RemoveOddsSettings)
|
|
||||||
// tenant.Delete("/odds/settings", a.authMiddleware, a.CompanyOnly, h.RemoveAllOddsSettings)
|
|
||||||
// tenant.Post("/odds/market-settings", a.authMiddleware, a.CompanyOnly, h.InsertCompanyMarketSettings)
|
|
||||||
// tenant.Get("/odds/market-settings", a.authMiddleware, a.CompanyOnly, h.GetAllTenantMarketSettings)
|
|
||||||
// tenant.Delete("/odds/market-settings", a.authMiddleware, a.CompanyOnly, h.DeleteAllCompanyMarketSettings)
|
|
||||||
// tenant.Delete("/odds/market-settings/:id", a.authMiddleware, a.CompanyOnly, h.DeleteCompanyMarketSettings)
|
|
||||||
|
|
||||||
// groupV1.Get("/events", h.GetAllEvents)
|
|
||||||
// groupV1.Get("/events/:id", a.authMiddleware, h.GetEventByID)
|
|
||||||
// groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved)
|
|
||||||
// groupV1.Patch("/events/:id/is_monitored", a.authMiddleware, a.SuperAdminOnly, h.SetEventIsMonitored)
|
|
||||||
// groupV1.Put("/events/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
|
|
||||||
// groupV1.Get("/events/:id/bets", a.authMiddleware, a.SuperAdminOnly, h.GetBetsByEventID)
|
|
||||||
|
|
||||||
// tenant.Get("/upcoming-events", h.GetTenantUpcomingEvents)
|
|
||||||
// tenant.Get("/top-leagues", h.GetTopLeagues)
|
|
||||||
// tenant.Get("/events", h.GetTenantEvents)
|
|
||||||
// tenant.Get("/events/:id", h.GetTenantEventByID)
|
|
||||||
// tenant.Put("/events/:id/settings", a.authMiddleware, a.CompanyOnly, h.UpdateTenantEventSettings)
|
|
||||||
// tenant.Get("/events/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetTenantBetsByEventID)
|
|
||||||
|
|
||||||
//EnetPulse
|
|
||||||
// groupV1.Get("/odds/pre-match", h.GetPreMatchOdds)
|
|
||||||
// groupV1.Get("/sports", h.GetAllSports)
|
|
||||||
// groupV1.Get("/tournament_templates", h.GetAllTournamentTemplates)
|
|
||||||
// groupV1.Get("/tournaments", h.GetAllTournaments)
|
|
||||||
// groupV1.Get("/tournament_stages", h.GetAllTournamentStages)
|
|
||||||
// groupV1.Get("/fixtures", h.GetFixturesByDate)
|
|
||||||
// groupV1.Get("/results", h.GetAllResults)
|
|
||||||
// groupV1.Get("/preodds", h.GetAllPreoddsWithBettingOffers)
|
|
||||||
// groupV1.Get("/bettingoffers", h.GetAllBettingOffers)
|
|
||||||
// groupV1.Get("/fixtures/preodds", h.GetFixturesWithPreodds)
|
|
||||||
|
|
||||||
// // Leagues
|
|
||||||
// groupV1.Get("/leagues", a.authMiddleware, a.SuperAdminOnly, h.GetAllLeagues)
|
|
||||||
// groupV1.Put("/leagues/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalLeagueSetting)
|
|
||||||
|
|
||||||
// tenant.Get("/leagues", h.GetAllLeagues)
|
|
||||||
// tenant.Put("/leagues/:id/featured", a.authMiddleware, a.CompanyOnly, h.SetLeagueFeatured)
|
|
||||||
// tenant.Put("/leagues/:id/set-active", a.authMiddleware, a.CompanyOnly, h.SetLeagueActive)
|
|
||||||
|
|
||||||
// groupV1.Get("/result/b365/:id", h.GetBet365ResultsByEventID)
|
|
||||||
|
|
||||||
// Branch
|
|
||||||
// groupV1.Post("/branch", a.authMiddleware, a.CompanyOnly, h.CreateBranch)
|
|
||||||
// groupV1.Get("/branch", a.authMiddleware, a.CompanyOnly, h.GetAllBranches)
|
|
||||||
// groupV1.Get("/branch/:id", a.authMiddleware, a.CompanyOnly, h.GetBranchByID)
|
|
||||||
// groupV1.Post("/branch/:id/return", a.authMiddleware, a.CompanyOnly, h.ReturnBranchWallet)
|
|
||||||
// // groupV1.Get("/branch/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetBetByBranchID)
|
|
||||||
// groupV1.Put("/branch/:id", a.authMiddleware, a.CompanyOnly, h.UpdateBranch)
|
|
||||||
// groupV1.Put("/branch/:id/set-active", a.authMiddleware, a.CompanyOnly, h.UpdateBranchStatus)
|
|
||||||
// groupV1.Put("/branch/:id/set-inactive", a.authMiddleware, a.CompanyOnly, h.UpdateBranchStatus)
|
|
||||||
// groupV1.Delete("/branch/:id", a.authMiddleware, a.CompanyOnly, h.DeleteBranch)
|
|
||||||
|
|
||||||
// groupV1.Get("/search/branch", a.authMiddleware, a.CompanyOnly, h.SearchBranch)
|
|
||||||
|
|
||||||
// groupV1.Get("/branchLocation", a.authMiddleware, a.CompanyOnly, h.GetAllBranchLocations)
|
|
||||||
|
|
||||||
// groupV1.Get("/branch/:id/cashiers", a.authMiddleware, a.CompanyOnly, h.GetBranchCashiers)
|
|
||||||
// groupV1.Get("/branchCashier", a.authMiddleware, a.CompanyOnly, h.GetBranchForCashier)
|
|
||||||
|
|
||||||
// // Branch Operation
|
|
||||||
// groupV1.Get("/supportedOperation", a.authMiddleware, h.GetAllSupportedOperations)
|
|
||||||
// groupV1.Post("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.CreateSupportedOperation)
|
|
||||||
// groupV1.Post("/operation", a.authMiddleware, a.CompanyOnly, h.CreateBranchOperation)
|
|
||||||
// groupV1.Get("/branch/:id/operation", a.authMiddleware, a.CompanyOnly, h.GetBranchOperations)
|
|
||||||
|
|
||||||
// groupV1.Delete("/branch/:id/operation/:opID", a.authMiddleware, a.CompanyOnly, h.DeleteBranchOperation)
|
|
||||||
|
|
||||||
// // Company
|
|
||||||
// groupV1.Post("/company", a.authMiddleware, a.SuperAdminOnly, h.CreateCompany)
|
|
||||||
// groupV1.Get("/company", a.authMiddleware, a.SuperAdminOnly, h.GetAllCompanies)
|
|
||||||
// groupV1.Get("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCompanyByID)
|
|
||||||
// groupV1.Put("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCompany)
|
|
||||||
// groupV1.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany)
|
|
||||||
// groupV1.Get("/company/:id/branch", a.authMiddleware, a.CompanyOnly, h.GetBranchByCompanyID)
|
|
||||||
// groupV1.Get("/search/company", a.authMiddleware, a.CompanyOnly, h.SearchCompany)
|
|
||||||
// groupV1.Get("/admin-company", a.authMiddleware, a.CompanyOnly, h.GetCompanyForAdmin)
|
|
||||||
|
|
||||||
// groupV1.Get("/ticket", h.GetAllTickets)
|
|
||||||
// groupV1.Get("/ticket/:id", h.GetTicketByID)
|
|
||||||
|
|
||||||
// Ticket Routes
|
|
||||||
// tenant.Post("/ticket", h.CreateTenantTicket)
|
|
||||||
// tenant.Get("/ticket", h.GetAllTenantTickets)
|
|
||||||
// tenant.Get("/ticket/:id", h.GetTenantTicketByID)
|
|
||||||
|
|
||||||
// Bet Routes
|
|
||||||
// tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet)
|
|
||||||
// tenant.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode)
|
|
||||||
// tenant.Get("/sport/bet/fastcode/:fast_code", h.GetBetByFastCode)
|
|
||||||
// tenant.Get("/sport/bet", a.authMiddleware, a.CompanyOnly, h.GetAllTenantBets)
|
|
||||||
// tenant.Get("/sport/bet/:id", a.authMiddleware, h.GetTenantBetByID)
|
|
||||||
// tenant.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut)
|
|
||||||
// tenant.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteTenantBet)
|
|
||||||
|
|
||||||
// groupV1.Get("/sport/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetBetByID)
|
|
||||||
// groupV1.Get("/sport/bet", a.authMiddleware, a.SuperAdminOnly, h.GetAllBet)
|
|
||||||
// groupV1.Delete("/sport/bet/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteBet)
|
|
||||||
|
|
||||||
// tenant.Post("/sport/random/bet", a.authMiddleware, h.RandomBet)
|
|
||||||
|
|
||||||
// // Wallet
|
|
||||||
// groupV1.Get("/wallet", h.GetAllWallets)
|
|
||||||
// groupV1.Get("/wallet/:id", h.GetWalletByID)
|
|
||||||
// groupV1.Put("/wallet/:id", h.UpdateWalletActive)
|
|
||||||
// groupV1.Get("/branchWallet", a.authMiddleware, h.GetAllBranchWallets)
|
|
||||||
// groupV1.Get("/customerWallet", a.authMiddleware, h.GetAllCustomerWallets)
|
|
||||||
// groupV1.Get("/cashierWallet", a.authMiddleware, h.GetWalletForCashier)
|
|
||||||
|
|
||||||
// Transfer
|
|
||||||
// /transfer/wallet - transfer from one wallet to another wallet
|
|
||||||
// groupV1.Post("/transfer/wallet/:id", a.authMiddleware, h.TransferToWallet)
|
|
||||||
// groupV1.Get("/transfer/wallet/:id", a.authMiddleware, h.GetTransfersByWallet)
|
|
||||||
// groupV1.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet)
|
|
||||||
|
|
||||||
//Chapa Routes
|
|
||||||
// groupV1.Post("/chapa/payments/webhook/verify", h.WebhookCallback)
|
|
||||||
// groupV1.Get("/chapa/transaction/manual/verify/:tx_ref", a.authMiddleware, h.ManualVerifyTransaction)
|
|
||||||
// groupV1.Put("/chapa/transaction/cancel/:tx_ref", a.authMiddleware, h.CancelDeposit)
|
|
||||||
// groupV1.Get("/chapa/transactions", a.authMiddleware, h.FetchAllTransactions)
|
|
||||||
// groupV1.Get("/chapa/transaction/events/:ref_id", a.authMiddleware, h.GetTransactionEvents)
|
|
||||||
// groupV1.Post("/chapa/payments/deposit", a.authMiddleware, h.InitiateDeposit)
|
|
||||||
// groupV1.Post("/chapa/payments/withdraw", a.authMiddleware, h.InitiateWithdrawal)
|
|
||||||
// groupV1.Get("/chapa/banks", h.GetSupportedBanks)
|
|
||||||
// groupV1.Get("/chapa/payments/receipt/:chapa_ref", a.authMiddleware, h.GetPaymentReceipt)
|
|
||||||
// groupV1.Get("/chapa/transfers", a.authMiddleware, h.GetAllTransfers)
|
|
||||||
// groupV1.Get("/chapa/balance", a.authMiddleware, h.GetAccountBalance)
|
|
||||||
// groupV1.Post("/chapa/swap", a.authMiddleware, h.SwapCurrency)
|
|
||||||
|
|
||||||
// Currencies
|
|
||||||
groupV1.Get("/currencies", h.GetSupportedCurrencies)
|
|
||||||
groupV1.Get("/currencies/convert", h.ConvertCurrency)
|
|
||||||
|
|
||||||
//Report Routes
|
|
||||||
// groupV1.Get("/reports/dashboard", a.authMiddleware, a.OnlyAdminAndAbove, h.GetDashboardReport)
|
|
||||||
// groupV1.Get("/report-files/download/:filename", h.DownloadReportFile)
|
|
||||||
// groupV1.Get("/report-files/list", a.authMiddleware, a.OnlyAdminAndAbove, h.ListReportFiles)
|
|
||||||
|
|
||||||
// groupV1.Post("/reports/requests", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateReportRequest)
|
|
||||||
// groupV1.Get("/reports/requests", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllReportRequests)
|
|
||||||
// groupV1.Get("/reports/download/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.DownloadReportByID)
|
|
||||||
|
|
||||||
//Alea Play Virtual Game Routes
|
|
||||||
// groupV1.Get("/alea-play/launch", a.authMiddleware, h.LaunchAleaGame)
|
|
||||||
// groupV1.Post("/webhooks/alea-play", a.authMiddleware, h.HandleAleaCallback)
|
|
||||||
|
|
||||||
// //Veli Virtual Game Routes
|
|
||||||
// groupV1.Post("/veli/providers", h.GetProviders)
|
|
||||||
// groupV1.Post("/veli/games-list", h.GetGamesByProvider)
|
|
||||||
// groupV1.Post("/veli/start-game", a.authMiddleware, h.StartGame)
|
|
||||||
// groupV1.Post("/veli/start-demo-game", h.StartDemoGame)
|
|
||||||
// a.fiber.Post("/balance", h.GetBalance)
|
|
||||||
// groupV1.Post("/veli/gaming-activity", a.authMiddleware, h.GetGamingActivity)
|
|
||||||
// groupV1.Post("/veli/huge-wins", a.authMiddleware, h.GetHugeWins)
|
|
||||||
// groupV1.Post("/veli/credit-balances", a.authMiddleware, h.GetCreditBalances)
|
|
||||||
|
|
||||||
// //Atlas Virtual Game Routes
|
|
||||||
// groupV1.Get("/atlas/games", h.GetAtlasVGames)
|
|
||||||
// groupV1.Post("/atlas/init-game", a.authMiddleware, h.InitAtlasGame)
|
|
||||||
// a.fiber.Post("/account", h.AtlasGetUserDataCallback)
|
|
||||||
// a.fiber.Post("/betwin", h.HandleAtlasBetWin)
|
|
||||||
// a.fiber.Post("/result", h.HandleRoundResult)
|
|
||||||
// a.fiber.Post("/rollback", h.HandleRollback)
|
|
||||||
// a.fiber.Post("/freespin", h.FreeSpinResultCallback)
|
|
||||||
// a.fiber.Post("/jackpot", h.JackpotCallback)
|
|
||||||
// groupV1.Post("/atlas/freespin", a.authMiddleware, h.CreateFreeSpin)
|
|
||||||
|
|
||||||
//mongoDB logs
|
//mongoDB logs
|
||||||
groupV1.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(context.Background()))
|
groupV1.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(context.Background()))
|
||||||
|
|
||||||
// Recommendation Routes
|
|
||||||
// group.Get("/virtual-games/recommendations/:userID", h.GetRecommendations)
|
|
||||||
|
|
||||||
// Transactions /shop/transactions
|
|
||||||
// groupV1.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet)
|
|
||||||
// groupV1.Get("/shop/bet", a.authMiddleware, a.CompanyOnly, h.GetAllShopBets)
|
|
||||||
// groupV1.Get("/shop/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByBetID)
|
|
||||||
// groupV1.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
|
||||||
// groupV1.Post("/shop/bet/:id/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
|
||||||
// groupV1.Get("/shop/cashout/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByCashoutID)
|
|
||||||
// groupV1.Post("/shop/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutByCashoutID)
|
|
||||||
// groupV1.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer)
|
|
||||||
// groupV1.Get("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer)
|
|
||||||
|
|
||||||
// groupV1.Get("/shop/transaction", a.authMiddleware, a.CompanyOnly, h.GetAllTransactions)
|
// groupV1.Get("/shop/transaction", a.authMiddleware, a.CompanyOnly, h.GetAllTransactions)
|
||||||
// groupV1.Get("/shop/transaction/:id", a.authMiddleware, a.CompanyOnly, h.GetTransactionByID)
|
// groupV1.Get("/shop/transaction/:id", a.authMiddleware, a.CompanyOnly, h.GetTransactionByID)
|
||||||
// groupV1.Get("/shop/transaction/:id/bet", a.authMiddleware, a.CompanyOnly, h.GetShopBetByTransactionID)
|
// groupV1.Get("/shop/transaction/:id/bet", a.authMiddleware, a.CompanyOnly, h.GetShopBetByTransactionID)
|
||||||
|
|
@ -434,33 +163,10 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Get("/ws/connect", a.WebsocketAuthMiddleware, h.ConnectSocket)
|
groupV1.Get("/ws/connect", a.WebsocketAuthMiddleware, h.ConnectSocket)
|
||||||
groupV1.Get("/notifications", a.authMiddleware, h.GetUserNotification)
|
groupV1.Get("/notifications", a.authMiddleware, h.GetUserNotification)
|
||||||
groupV1.Get("/notifications/all", a.authMiddleware, h.GetAllNotifications)
|
groupV1.Get("/notifications/all", a.authMiddleware, h.GetAllNotifications)
|
||||||
groupV1.Post("/notifications/mark-as-read", a.authMiddleware, h.MarkNotificationAsRead)
|
// groupV1.Post("/notifications/mark-as-read", a.authMiddleware, h.MarkNotificationAsRead)
|
||||||
groupV1.Get("/notifications/unread", a.authMiddleware, h.CountUnreadNotifications)
|
groupV1.Get("/notifications/unread", a.authMiddleware, h.CountUnreadNotifications)
|
||||||
groupV1.Post("/notifications/create", a.authMiddleware, h.CreateAndSendNotification)
|
groupV1.Post("/notifications/create", a.authMiddleware, h.CreateAndSendNotification)
|
||||||
|
|
||||||
// Virtual Game Routes
|
|
||||||
// a.fiber.Post("/virtual-game/launch", a.authMiddleware, h.LaunchVirtualGame)
|
|
||||||
// a.fiber.Post("/virtual-game/callback", h.HandleVirtualGameCallback)
|
|
||||||
// a.fiber.Post("/playerInfo", h.HandlePlayerInfo)
|
|
||||||
// a.fiber.Post("/bet", h.HandleBet)
|
|
||||||
// a.fiber.Post("/win", h.HandleWin)
|
|
||||||
// a.fiber.Post("/cancel", h.HandleCancel)
|
|
||||||
// a.fiber.Post("/promoWin ", h.HandlePromoWin)
|
|
||||||
// a.fiber.Post("/tournamentWin ", h.HandleTournamentWin)
|
|
||||||
// a.fiber.Get("/popok/games", h.GetGameList)
|
|
||||||
// a.fiber.Get("/popok/games/recommend", a.authMiddleware, h.RecommendGames)
|
|
||||||
// groupV1.Post("/virtual-game/favorites", a.authMiddleware, h.AddFavorite)
|
|
||||||
// groupV1.Delete("/virtual-game/favorites/:gameID", a.authMiddleware, h.RemoveFavorite)
|
|
||||||
// groupV1.Get("/virtual-game/favorites", a.authMiddleware, h.ListFavorites)
|
|
||||||
|
|
||||||
// groupV1.Get("/orchestrator/virtual-game/provider-reports/asc", a.OnlyAdminAndAbove, h.ListVirtualGameProviderReportsAscHandler)
|
|
||||||
// groupV1.Get("/orchestrator/virtual-game/provider-reports/desc", a.OnlyAdminAndAbove, h.ListVirtualGameProviderReportsDescHandler)
|
|
||||||
// groupV1.Delete("/virtual-game/orchestrator/providers/:provideID", a.authMiddleware, h.RemoveProvider)
|
|
||||||
// groupV1.Get("/virtual-game/orchestrator/providers/:provideID", a.authMiddleware, h.GetProviderByID)
|
|
||||||
// groupV1.Get("/virtual-game/orchestrator/games", h.ListVirtualGames)
|
|
||||||
// groupV1.Get("/virtual-game/orchestrator/providers", h.ListProviders)
|
|
||||||
// groupV1.Patch("/virtual-game/orchestrator/providers/:provideID/status", a.authMiddleware, h.SetProviderEnabled)
|
|
||||||
|
|
||||||
//Issue Reporting Routes
|
//Issue Reporting Routes
|
||||||
// groupV1.Post("/issues", a.authMiddleware, h.CreateIssue) //anyone who has logged can report a
|
// groupV1.Post("/issues", a.authMiddleware, h.CreateIssue) //anyone who has logged can report a
|
||||||
// groupV1.Get("/issues/customer/:customer_id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetUserIssues)
|
// groupV1.Get("/issues/customer/:customer_id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetUserIssues)
|
||||||
|
|
@ -473,12 +179,4 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
|
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
|
||||||
groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
|
groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
|
||||||
|
|
||||||
tenant.Get("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.GetCompanySettingList)
|
|
||||||
tenant.Put("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.SaveCompanySettingList)
|
|
||||||
tenant.Delete("/settings/:key", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteCompanySetting)
|
|
||||||
tenant.Delete("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteAllCompanySetting)
|
|
||||||
|
|
||||||
// groupV1.Get("/stats/total/events", h.GetTotalEventStats)
|
|
||||||
// groupV1.Get("/stats/interval/events", h.GetTotalEventStatsByInterval)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
makefile
26
makefile
|
|
@ -10,7 +10,7 @@ coverage:
|
||||||
@mkdir -p coverage
|
@mkdir -p coverage
|
||||||
@docker compose up -d test
|
@docker compose up -d test
|
||||||
@docker compose exec test sh -c "go test -coverprofile=coverage.out ./internal/... && go tool cover -func=coverage.out -o coverage/coverage.txt"
|
@docker compose exec test sh -c "go test -coverprofile=coverage.out ./internal/... && go tool cover -func=coverage.out -o coverage/coverage.txt"
|
||||||
@docker cp $(shell docker ps -q -f "name=fortunebet-test-1"):/app/coverage ./ || true
|
@docker cp $(shell docker ps -q -f "name=yimaru-test-1"):/app/coverage ./ || true
|
||||||
@docker compose stop test
|
@docker compose stop test
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
|
@ -46,45 +46,45 @@ postgres:
|
||||||
.PHONY: backup
|
.PHONY: backup
|
||||||
backup:
|
backup:
|
||||||
@mkdir -p backup
|
@mkdir -p backup
|
||||||
@docker exec -t fortunebet-backend-postgres-1 pg_dump -U root --data-only --exclude-table=schema_migrations gh | gzip > backup/dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.gz
|
@docker exec -t yimaru-backend-postgres-1 pg_dump -U root --data-only --exclude-table=schema_migrations gh | gzip > backup/dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.gz
|
||||||
|
|
||||||
restore:
|
restore:
|
||||||
@echo "Restoring latest backup..."
|
@echo "Restoring latest backup..."
|
||||||
@latest_file=$$(ls -t backup/dump_*.sql.gz | head -n 1); \
|
@latest_file=$$(ls -t backup/dump_*.sql.gz | head -n 1); \
|
||||||
echo "Restoring from $$latest_file"; \
|
echo "Restoring from $$latest_file"; \
|
||||||
gunzip -c $$latest_file | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh
|
gunzip -c $$latest_file | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh
|
||||||
restore_file:
|
restore_file:
|
||||||
@echo "Restoring latest backup..."
|
@echo "Restoring latest backup..."
|
||||||
gunzip -c $(file) | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh
|
gunzip -c $(file) | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh
|
||||||
|
|
||||||
.PHONY: seed_data
|
.PHONY: seed_data
|
||||||
seed_data:
|
seed_data:
|
||||||
|
|
||||||
@echo "Waiting for PostgreSQL to be ready..."
|
@echo "Waiting for PostgreSQL to be ready..."
|
||||||
@until docker exec fortunebet-backend-postgres-1 pg_isready -U root -d gh; do \
|
@until docker exec yimaru-backend-postgres-1 pg_isready -U root -d gh; do \
|
||||||
echo "PostgreSQL is not ready yet..."; \
|
echo "PostgreSQL is not ready yet..."; \
|
||||||
sleep 1; \
|
sleep 1; \
|
||||||
done
|
done
|
||||||
@for file in db/data/*.sql; do \
|
@for file in db/data/*.sql; do \
|
||||||
echo "Seeding $$file..."; \
|
echo "Seeding $$file..."; \
|
||||||
cat $$file | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh; \
|
cat $$file | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh; \
|
||||||
done
|
done
|
||||||
.PHONY: seed_dev_data
|
.PHONY: seed_dev_data
|
||||||
seed_dev_data:
|
seed_dev_data:
|
||||||
@echo "Waiting for PostgreSQL to be ready..."
|
@echo "Waiting for PostgreSQL to be ready..."
|
||||||
@until docker exec fortunebet-backend-postgres-1 pg_isready -U root -d gh; do \
|
@until docker exec yimaru-backend-postgres-1 pg_isready -U root -d gh; do \
|
||||||
echo "PostgreSQL is not ready yet..."; \
|
echo "PostgreSQL is not ready yet..."; \
|
||||||
sleep 1; \
|
sleep 1; \
|
||||||
done
|
done
|
||||||
cat db/scripts/fix_autoincrement_desync.sql | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh;
|
cat db/scripts/fix_autoincrement_desync.sql | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh;
|
||||||
@for file in db/dev_data/*.sql; do \
|
@for file in db/dev_data/*.sql; do \
|
||||||
if [ -f "$$file" ]; then \
|
if [ -f "$$file" ]; then \
|
||||||
echo "Seeding $$file..."; \
|
echo "Seeding $$file..."; \
|
||||||
cat $$file | docker exec -i fortunebet-backend-postgres-1 psql -U root -d gh; \
|
cat $$file | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
postgres_log:
|
postgres_log:
|
||||||
docker logs fortunebet-backend-postgres-1
|
docker logs yimaru-backend-postgres-1
|
||||||
.PHONY: swagger
|
.PHONY: swagger
|
||||||
swagger:
|
swagger:
|
||||||
@swag init -g cmd/main.go
|
@swag init -g cmd/main.go
|
||||||
|
|
@ -94,15 +94,15 @@ logs:
|
||||||
db-up: | logs
|
db-up: | logs
|
||||||
@mkdir -p logs
|
@mkdir -p logs
|
||||||
@docker compose up -d postgres migrate mongo
|
@docker compose up -d postgres migrate mongo
|
||||||
@docker logs fortunebet-backend-postgres-1 > logs/postgres.log 2>&1 &
|
@docker logs yimaru-backend-postgres-1 > logs/postgres.log 2>&1 &
|
||||||
.PHONY: db-down
|
.PHONY: db-down
|
||||||
db-down:
|
db-down:
|
||||||
@docker compose down -v
|
@docker compose down -v
|
||||||
# @docker volume rm fortunebet-backend_postgres_data
|
# @docker volume rm yimaru-backend_postgres_data
|
||||||
.PHONY: sqlc-gen
|
.PHONY: sqlc-gen
|
||||||
sqlc-gen:
|
sqlc-gen:
|
||||||
@sqlc generate
|
@sqlc generate
|
||||||
app_log:
|
app_log:
|
||||||
@mkdir -p app_logs
|
@mkdir -p app_logs
|
||||||
export_logs: | app_log
|
export_logs: | app_log
|
||||||
@docker exec fortunebet-mongo mongoexport --db=logdb --collection=applogs -u root -p secret --authenticationDatabase=admin --out - > app_logs/log_`date +%Y-%m-%d"_"%H_%M_%S`.json
|
@docker exec yimaru-mongo mongoexport --db=logdb --collection=applogs -u root -p secret --authenticationDatabase=admin --out - > app_logs/log_`date +%Y-%m-%d"_"%H_%M_%S`.json
|
||||||
|
|
|
||||||
108
makefile copy
Normal file
108
makefile copy
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
include .env
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
@docker compose up -d test
|
||||||
|
@docker compose exec test go test ./...
|
||||||
|
@docker compose stop test
|
||||||
|
|
||||||
|
.PHONY: coverage
|
||||||
|
coverage:
|
||||||
|
@mkdir -p coverage
|
||||||
|
@docker compose up -d test
|
||||||
|
@docker compose exec test sh -c "go test -coverprofile=coverage.out ./internal/... && go tool cover -func=coverage.out -o coverage/coverage.txt"
|
||||||
|
@docker cp $(shell docker ps -q -f "name=yimaru-test-1"):/app/coverage ./ || true
|
||||||
|
@docker compose stop test
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
@docker compose build app
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
@docker compose up
|
||||||
|
|
||||||
|
.PHONY: stop
|
||||||
|
stop:
|
||||||
|
@docker compose down
|
||||||
|
|
||||||
|
.PHONY: air
|
||||||
|
air:
|
||||||
|
@echo "Running air locally (not in Docker)"
|
||||||
|
@air -c .air.toml
|
||||||
|
.PHONY: migrations/new
|
||||||
|
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...'
|
||||||
|
@docker compose up migrate
|
||||||
|
|
||||||
|
.PHONY: postgres
|
||||||
|
postgres:
|
||||||
|
@echo 'Running postgres db...'
|
||||||
|
docker compose -f docker-compose.yml exec postgres psql -U root -d gh
|
||||||
|
.PHONY: backup
|
||||||
|
backup:
|
||||||
|
@mkdir -p backup
|
||||||
|
@docker exec -t yimaru-backend-postgres-1 pg_dump -U root --data-only --exclude-table=schema_migrations gh | gzip > backup/dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.gz
|
||||||
|
|
||||||
|
restore:
|
||||||
|
@echo "Restoring latest backup..."
|
||||||
|
@latest_file=$$(ls -t backup/dump_*.sql.gz | head -n 1); \
|
||||||
|
echo "Restoring from $$latest_file"; \
|
||||||
|
gunzip -c $$latest_file | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh
|
||||||
|
restore_file:
|
||||||
|
@echo "Restoring latest backup..."
|
||||||
|
gunzip -c $(file) | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh
|
||||||
|
|
||||||
|
.PHONY: seed_data
|
||||||
|
seed_data:
|
||||||
|
|
||||||
|
@echo "Waiting for PostgreSQL to be ready..."
|
||||||
|
@until docker exec yimaru-backend-postgres-1 pg_isready -U root -d gh; do \
|
||||||
|
echo "PostgreSQL is not ready yet..."; \
|
||||||
|
sleep 1; \
|
||||||
|
done
|
||||||
|
@for file in db/data/*.sql; do \
|
||||||
|
echo "Seeding $$file..."; \
|
||||||
|
cat $$file | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh; \
|
||||||
|
done
|
||||||
|
.PHONY: seed_dev_data
|
||||||
|
seed_dev_data:
|
||||||
|
@echo "Waiting for PostgreSQL to be ready..."
|
||||||
|
@until docker exec yimaru-backend-postgres-1 pg_isready -U root -d gh; do \
|
||||||
|
echo "PostgreSQL is not ready yet..."; \
|
||||||
|
sleep 1; \
|
||||||
|
done
|
||||||
|
cat db/scripts/fix_autoincrement_desync.sql | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh;
|
||||||
|
@for file in db/dev_data/*.sql; do \
|
||||||
|
if [ -f "$$file" ]; then \
|
||||||
|
echo "Seeding $$file..."; \
|
||||||
|
cat $$file | docker exec -i yimaru-backend-postgres-1 psql -U root -d gh; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
|
postgres_log:
|
||||||
|
docker logs yimaru-backend-postgres-1
|
||||||
|
.PHONY: swagger
|
||||||
|
swagger:
|
||||||
|
@swag init -g cmd/main.go
|
||||||
|
.PHONY: db-up
|
||||||
|
logs:
|
||||||
|
@mkdir -p logs
|
||||||
|
db-up: | logs
|
||||||
|
@mkdir -p logs
|
||||||
|
@docker compose up -d postgres migrate mongo
|
||||||
|
@docker logs yimaru-backend-postgres-1 > logs/postgres.log 2>&1 &
|
||||||
|
.PHONY: db-down
|
||||||
|
db-down:
|
||||||
|
@docker compose down -v
|
||||||
|
# @docker volume rm yimaru-backend_postgres_data
|
||||||
|
.PHONY: sqlc-gen
|
||||||
|
sqlc-gen:
|
||||||
|
@sqlc generate
|
||||||
|
app_log:
|
||||||
|
@mkdir -p app_logs
|
||||||
|
export_logs: | app_log
|
||||||
|
@docker exec yimaru-mongo mongoexport --db=logdb --collection=applogs -u root -p secret --authenticationDatabase=admin --out - > app_logs/log_`date +%Y-%m-%d"_"%H_%M_%S`.json
|
||||||
Loading…
Reference in New Issue
Block a user