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/services/arifpay"
|
||||
"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"
|
||||
"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/user"
|
||||
httpserver "Yimaru-Backend/internal/web_server"
|
||||
|
|
@ -71,14 +75,14 @@ func main() {
|
|||
v := customvalidator.NewCustomValidator(validator.New())
|
||||
|
||||
// Initialize services
|
||||
// settingRepo := repository.NewSettingStore(store)
|
||||
settingRepo := repository.NewSettingStore(store)
|
||||
|
||||
// if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil {
|
||||
// log.Fatalf("failed to ensure settings: %v", err)
|
||||
// }
|
||||
// settingSvc := settings.NewService(settingRepo)
|
||||
if err := settingRepo.EnsureAllSettingsExist(context.Background()); err != nil {
|
||||
log.Fatalf("failed to ensure settings: %v", err)
|
||||
}
|
||||
settingSvc := settings.NewService(settingRepo)
|
||||
|
||||
// messengerSvc := messenger.NewService(settingSvc, cfg)
|
||||
messengerSvc := messenger.NewService(settingSvc, cfg)
|
||||
// statSvc := stats.NewService(
|
||||
// repository.NewCompanyStatStore(store),
|
||||
// repository.NewBranchStatStore(store),
|
||||
|
|
@ -92,7 +96,7 @@ func main() {
|
|||
userSvc := user.NewService(
|
||||
repository.NewUserStore(store),
|
||||
repository.NewOTPStore(store),
|
||||
// messengerSvc,
|
||||
messengerSvc,
|
||||
cfg,
|
||||
)
|
||||
// leagueSvc := league.New(repository.NewLeagueStore(store))
|
||||
|
|
@ -146,8 +150,8 @@ func main() {
|
|||
// logger,
|
||||
// )
|
||||
|
||||
branchSvc := branch.NewService(repository.NewBranchStore(store))
|
||||
companySvc := company.NewService(repository.NewCompanyStore(store))
|
||||
// branchSvc := branch.NewService(repository.NewBranchStore(store))
|
||||
// companySvc := company.NewService(repository.NewCompanyStore(store))
|
||||
|
||||
// ticketSvc := ticke.NewService(
|
||||
// repository.NewTicketStore(store),
|
||||
|
|
@ -184,25 +188,25 @@ func main() {
|
|||
// *userSvc,
|
||||
// )
|
||||
|
||||
bonusSvc := bonus.NewService(
|
||||
repository.NewBonusStore(store),
|
||||
settingSvc,
|
||||
notificationSvc,
|
||||
domain.MongoDBLogger,
|
||||
)
|
||||
// bonusSvc := bonus.NewService(
|
||||
// repository.NewBonusStore(store),
|
||||
// settingSvc,
|
||||
// notificationSvc,
|
||||
// domain.MongoDBLogger,
|
||||
// )
|
||||
// virtualGamesRepo := repository.NewVirtualGameRepository(store)
|
||||
recommendationRepo := repository.NewRecommendationRepository(store)
|
||||
|
||||
referalSvc := referralservice.New(
|
||||
repository.NewReferralStore(store),
|
||||
*settingSvc,
|
||||
cfg,
|
||||
logger,
|
||||
domain.MongoDBLogger,
|
||||
)
|
||||
raffleSvc := raffle.NewService(
|
||||
repository.NewRaffleStore(store),
|
||||
)
|
||||
// referalSvc := referralservice.New(
|
||||
// repository.NewReferralStore(store),
|
||||
// *settingSvc,
|
||||
// cfg,
|
||||
// logger,
|
||||
// domain.MongoDBLogger,
|
||||
// )
|
||||
// raffleSvc := raffle.NewService(
|
||||
// repository.NewRaffleStore(store),
|
||||
// )
|
||||
// virtualGameSvc := virtualgameservice.New(virtualGamesRepo,, store, cfg, logger)
|
||||
// aleaService := alea.NewAleaPlayService(virtualGamesRepo,, cfg, logger)
|
||||
// veliCLient := veli.NewClient(cfg)
|
||||
|
|
@ -224,15 +228,14 @@ func main() {
|
|||
// chapaClient,
|
||||
// )
|
||||
|
||||
currRepo := repository.NewCurrencyPostgresRepository(store)
|
||||
// currRepo := repository.NewCurrencyPostgresRepository(store)
|
||||
|
||||
fixerFertcherSvc := currency.NewFixerFetcher(
|
||||
cfg.FIXER_API_KEY,
|
||||
cfg.FIXER_BASE_URL,
|
||||
)
|
||||
// fixerFertcherSvc := currency.NewFixerFetcher(
|
||||
// cfg.FIXER_API_KEY,
|
||||
// cfg.FIXER_BASE_URL,
|
||||
// )
|
||||
transactionSvc := transaction.NewService(
|
||||
repository.NewTransactionStore(store),
|
||||
*branchSvc,
|
||||
*userSvc,
|
||||
)
|
||||
|
||||
|
|
@ -263,8 +266,8 @@ func main() {
|
|||
// go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop")
|
||||
// go httpserver.ProcessBetCashback(context.TODO(), betSvc)
|
||||
|
||||
bankRepository := repository.NewBankRepository(store)
|
||||
instSvc := institutions.New(bankRepository)
|
||||
// bankRepository := repository.NewBankRepository(store)
|
||||
// instSvc := institutions.New(bankRepository)
|
||||
// Initialize report worker with CSV exporter
|
||||
// csvExporter := infrastructure.CSVExporter{
|
||||
// ExportPath: cfg.ReportExportPath, // Make sure to add this to your config
|
||||
|
|
@ -297,11 +300,11 @@ func main() {
|
|||
// 5*time.Minute,
|
||||
// )
|
||||
|
||||
currSvc := currency.NewService(
|
||||
currRepo,
|
||||
cfg.BASE_CURRENCY,
|
||||
fixerFertcherSvc,
|
||||
)
|
||||
// currSvc := currency.NewService(
|
||||
// currRepo,
|
||||
// cfg.BASE_CURRENCY,
|
||||
// fixerFertcherSvc,
|
||||
// )
|
||||
|
||||
// exchangeWorker := currency.NewExchangeRateWorker(fixerFertcherSvc, logger, cfg)
|
||||
// exchangeWorker.Start(context.Background())
|
||||
|
|
@ -330,13 +333,8 @@ func main() {
|
|||
|
||||
// Initialize and start HTTP server
|
||||
app := httpserver.NewApp(
|
||||
// directdeposit,
|
||||
// telebirrSvc,
|
||||
arifpaySvc,
|
||||
// santimpaySvc,
|
||||
issueReportingSvc,
|
||||
instSvc,
|
||||
currSvc,
|
||||
cfg.Port,
|
||||
v,
|
||||
settingSvc,
|
||||
|
|
@ -347,16 +345,9 @@ func main() {
|
|||
JwtAccessExpiry: cfg.AccessExpiry,
|
||||
},
|
||||
userSvc,
|
||||
// chapaSvc,
|
||||
transactionSvc,
|
||||
branchSvc,
|
||||
companySvc,
|
||||
notificationSvc,
|
||||
referalSvc,
|
||||
raffleSvc,
|
||||
bonusSvc,
|
||||
recommendationSvc,
|
||||
statSvc,
|
||||
cfg,
|
||||
domain.MongoDBLogger,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ VALUES
|
|||
'Sarah',
|
||||
'Connor',
|
||||
'SarahC',
|
||||
'sarah.connor@yimaru.com',
|
||||
'yaredyemane1@gmail.com',
|
||||
NULL,
|
||||
crypt('password@123', gen_salt('bf'))::bytea,
|
||||
'SUPER_ADMIN',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
-- =========================================
|
||||
-- Notifications
|
||||
-- =========================================
|
||||
DROP TABLE IF EXISTS global_settings;
|
||||
|
||||
-- =========================================
|
||||
-- Notifications
|
||||
-- =========================================
|
||||
|
|
@ -48,4 +53,4 @@ DROP TABLE IF EXISTS otps;
|
|||
-- =========================================
|
||||
-- Users
|
||||
-- =========================================
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
|
@ -192,4 +192,4 @@ CREATE TABLE IF NOT EXISTS reported_issues (
|
|||
metadata JSONB,
|
||||
created_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
|
||||
INSERT INTO refresh_tokens (user_id, token, expires_at, created_at, revoked)
|
||||
VALUES ($1, $2, $3, $4, $5);
|
||||
|
|
|
|||
|
|
@ -1,37 +1,37 @@
|
|||
-- -- name: CreateReportedIssue :one
|
||||
-- INSERT INTO reported_issues (
|
||||
-- user_id,
|
||||
-- user_role,
|
||||
-- subject,
|
||||
-- description,
|
||||
-- issue_type,
|
||||
-- metadata
|
||||
-- )
|
||||
-- VALUES ($1, $2, $3, $4, $5, $6)
|
||||
-- RETURNING *;
|
||||
-- -- name: ListReportedIssues :many
|
||||
-- SELECT *
|
||||
-- FROM reported_issues
|
||||
-- ORDER BY created_at DESC
|
||||
-- LIMIT $1 OFFSET $2;
|
||||
-- -- name: ListReportedIssuesByUser :many
|
||||
-- SELECT *
|
||||
-- FROM reported_issues
|
||||
-- WHERE user_id = $1
|
||||
-- ORDER BY created_at DESC
|
||||
-- LIMIT $2 OFFSET $3;
|
||||
-- -- name: CountReportedIssues :one
|
||||
-- SELECT COUNT(*)
|
||||
-- FROM reported_issues;
|
||||
-- -- name: CountReportedIssuesByUser :one
|
||||
-- SELECT COUNT(*)
|
||||
-- FROM reported_issues
|
||||
-- WHERE user_id = $1;
|
||||
-- -- name: UpdateReportedIssueStatus :exec
|
||||
-- UPDATE reported_issues
|
||||
-- SET status = $2,
|
||||
-- updated_at = NOW()
|
||||
-- WHERE id = $1;
|
||||
-- -- name: DeleteReportedIssue :exec
|
||||
-- DELETE FROM reported_issues
|
||||
-- WHERE id = $1;
|
||||
-- name: CreateReportedIssue :one
|
||||
INSERT INTO reported_issues (
|
||||
user_id,
|
||||
user_role,
|
||||
subject,
|
||||
description,
|
||||
issue_type,
|
||||
metadata
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING *;
|
||||
-- name: ListReportedIssues :many
|
||||
SELECT *
|
||||
FROM reported_issues
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2;
|
||||
-- name: ListReportedIssuesByUser :many
|
||||
SELECT *
|
||||
FROM reported_issues
|
||||
WHERE user_id = $1
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2 OFFSET $3;
|
||||
-- name: CountReportedIssues :one
|
||||
SELECT COUNT(*)
|
||||
FROM reported_issues;
|
||||
-- name: CountReportedIssuesByUser :one
|
||||
SELECT COUNT(*)
|
||||
FROM reported_issues
|
||||
WHERE user_id = $1;
|
||||
-- name: UpdateReportedIssueStatus :exec
|
||||
UPDATE reported_issues
|
||||
SET status = $2,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1;
|
||||
-- name: DeleteReportedIssue :exec
|
||||
DELETE FROM reported_issues
|
||||
WHERE id = $1;
|
||||
|
|
@ -1,99 +1,72 @@
|
|||
-- -- name: CreateNotification :one
|
||||
-- INSERT INTO notifications (
|
||||
-- id,
|
||||
-- recipient_id,
|
||||
-- type,
|
||||
-- level,
|
||||
-- error_severity,
|
||||
-- reciever,
|
||||
-- is_read,
|
||||
-- delivery_status,
|
||||
-- delivery_channel,
|
||||
-- payload,
|
||||
-- priority,
|
||||
-- timestamp,
|
||||
-- expires,
|
||||
-- img,
|
||||
-- metadata
|
||||
-- )
|
||||
-- VALUES (
|
||||
-- $1,
|
||||
-- $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: CreateNotification :one
|
||||
INSERT INTO notifications (
|
||||
user_id,
|
||||
type,
|
||||
level,
|
||||
channel,
|
||||
title,
|
||||
message,
|
||||
payload
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
-- -- name: DeleteOldNotifications :exec
|
||||
-- DELETE FROM notifications
|
||||
-- WHERE expires < now();
|
||||
-- name: GetNotification :one
|
||||
SELECT *
|
||||
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
|
||||
-- INSERT INTO global_settings (key, value)
|
||||
-- VALUES ($1, $2) ON CONFLICT (key) DO
|
||||
-- UPDATE
|
||||
-- SET value = EXCLUDED.value;
|
||||
-- -- name: GetGlobalSettings :many
|
||||
-- SELECT *
|
||||
-- FROM global_settings;
|
||||
-- -- name: GetGlobalSetting :one
|
||||
-- SELECT *
|
||||
-- FROM global_settings
|
||||
-- WHERE key = $1;
|
||||
-- -- name: UpdateGlobalSetting :exec
|
||||
-- UPDATE global_settings
|
||||
-- SET value = $2,
|
||||
-- updated_at = CURRENT_TIMESTAMP
|
||||
-- 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;
|
||||
-- name: InsertGlobalSetting :exec
|
||||
INSERT INTO global_settings (key, value)
|
||||
VALUES ($1, $2) ON CONFLICT (key) DO
|
||||
UPDATE
|
||||
SET value = EXCLUDED.value;
|
||||
-- name: GetGlobalSettings :many
|
||||
SELECT *
|
||||
FROM global_settings;
|
||||
-- name: GetGlobalSetting :one
|
||||
SELECT *
|
||||
FROM global_settings
|
||||
WHERE key = $1;
|
||||
-- name: UpdateGlobalSetting :exec
|
||||
UPDATE global_settings
|
||||
SET value = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE key = $1;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@ SELECT *
|
|||
FROM users
|
||||
WHERE id = $1;
|
||||
-- name: GetAllUsers :many
|
||||
SELECT id,
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
first_name,
|
||||
last_name,
|
||||
nick_name,
|
||||
|
|
@ -81,29 +83,30 @@ SELECT id,
|
|||
suspended_at,
|
||||
organization_id
|
||||
FROM users
|
||||
wHERE (
|
||||
WHERE (
|
||||
role = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
organization_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
first_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR last_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
created_at > sqlc.narg('created_before')
|
||||
OR sqlc.narg('created_before') IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
created_at < sqlc.narg('created_after')
|
||||
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
|
||||
SELECT COUNT(*)
|
||||
FROM users
|
||||
|
|
@ -159,12 +162,6 @@ WHERE id = $4;
|
|||
UPDATE users
|
||||
SET organization_id = $1
|
||||
WHERE id = $2;
|
||||
-- name: SuspendUser :exec
|
||||
UPDATE users
|
||||
SET suspended = $1,
|
||||
suspended_at = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $3;
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users
|
||||
WHERE id = $1;
|
||||
|
|
@ -183,14 +180,16 @@ SELECT EXISTS (
|
|||
AND users.email IS NOT NULL
|
||||
AND users.organization_id = $2
|
||||
) AS email_exists;
|
||||
-- name: GetUserByEmail :one
|
||||
SELECT id,
|
||||
-- name: GetUserByEmailPhone :one
|
||||
SELECT
|
||||
id,
|
||||
first_name,
|
||||
last_name,
|
||||
nick_name,
|
||||
email,
|
||||
phone_number,
|
||||
role,
|
||||
password, -- added this line
|
||||
age,
|
||||
education_level,
|
||||
country,
|
||||
|
|
@ -203,30 +202,12 @@ SELECT id,
|
|||
suspended_at,
|
||||
organization_id
|
||||
FROM users
|
||||
WHERE email = $1
|
||||
AND organization_id = $2;
|
||||
-- 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;
|
||||
WHERE organization_id = $3
|
||||
AND (
|
||||
(email = $1 AND $1 IS NOT NULL)
|
||||
OR (phone_number = $2 AND $2 IS NOT NULL)
|
||||
)
|
||||
LIMIT 1;
|
||||
-- name: UpdatePassword :exec
|
||||
UPDATE users
|
||||
SET password = $1,
|
||||
|
|
@ -239,4 +220,10 @@ WHERE (
|
|||
SELECT users.*
|
||||
FROM organizations
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
UPDATE refresh_tokens
|
||||
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
|
||||
SELECT id,
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
first_name,
|
||||
last_name,
|
||||
nick_name,
|
||||
|
|
@ -224,29 +226,30 @@ SELECT id,
|
|||
suspended_at,
|
||||
organization_id
|
||||
FROM users
|
||||
wHERE (
|
||||
WHERE (
|
||||
role = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
organization_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
first_name ILIKE '%' || $3 || '%'
|
||||
OR last_name ILIKE '%' || $3 || '%'
|
||||
OR phone_number ILIKE '%' || $3 || '%'
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
created_at > $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
AND (
|
||||
created_at < $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
LIMIT $7 OFFSET $6
|
||||
LIMIT $7
|
||||
OFFSET $6
|
||||
`
|
||||
|
||||
type GetAllUsersParams struct {
|
||||
|
|
@ -260,6 +263,7 @@ type GetAllUsersParams struct {
|
|||
}
|
||||
|
||||
type GetAllUsersRow struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
ID int64 `json:"id"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
|
|
@ -298,6 +302,7 @@ func (q *Queries) GetAllUsers(ctx context.Context, arg GetAllUsersParams) ([]Get
|
|||
for rows.Next() {
|
||||
var i GetAllUsersRow
|
||||
if err := rows.Scan(
|
||||
&i.TotalCount,
|
||||
&i.ID,
|
||||
&i.FirstName,
|
||||
&i.LastName,
|
||||
|
|
@ -386,14 +391,16 @@ func (q *Queries) GetTotalUsers(ctx context.Context, arg GetTotalUsersParams) (i
|
|||
return count, err
|
||||
}
|
||||
|
||||
const GetUserByEmail = `-- name: GetUserByEmail :one
|
||||
SELECT id,
|
||||
const GetUserByEmailPhone = `-- name: GetUserByEmailPhone :one
|
||||
SELECT
|
||||
id,
|
||||
first_name,
|
||||
last_name,
|
||||
nick_name,
|
||||
email,
|
||||
phone_number,
|
||||
role,
|
||||
password, -- added this line
|
||||
age,
|
||||
education_level,
|
||||
country,
|
||||
|
|
@ -406,16 +413,21 @@ SELECT id,
|
|||
suspended_at,
|
||||
organization_id
|
||||
FROM users
|
||||
WHERE email = $1
|
||||
AND organization_id = $2
|
||||
WHERE organization_id = $3
|
||||
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"`
|
||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
||||
}
|
||||
|
||||
type GetUserByEmailRow struct {
|
||||
type GetUserByEmailPhoneRow struct {
|
||||
ID int64 `json:"id"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
|
|
@ -423,6 +435,7 @@ type GetUserByEmailRow struct {
|
|||
Email pgtype.Text `json:"email"`
|
||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||
Role string `json:"role"`
|
||||
Password []byte `json:"password"`
|
||||
Age pgtype.Int4 `json:"age"`
|
||||
EducationLevel pgtype.Text `json:"education_level"`
|
||||
Country pgtype.Text `json:"country"`
|
||||
|
|
@ -436,9 +449,9 @@ type GetUserByEmailRow struct {
|
|||
OrganizationID pgtype.Int8 `json:"organization_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams) (GetUserByEmailRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetUserByEmail, arg.Email, arg.OrganizationID)
|
||||
var i GetUserByEmailRow
|
||||
func (q *Queries) GetUserByEmailPhone(ctx context.Context, arg GetUserByEmailPhoneParams) (GetUserByEmailPhoneRow, error) {
|
||||
row := q.db.QueryRow(ctx, GetUserByEmailPhone, arg.Email, arg.PhoneNumber, arg.OrganizationID)
|
||||
var i GetUserByEmailPhoneRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.FirstName,
|
||||
|
|
@ -447,6 +460,7 @@ func (q *Queries) GetUserByEmail(ctx context.Context, arg GetUserByEmailParams)
|
|||
&i.Email,
|
||||
&i.PhoneNumber,
|
||||
&i.Role,
|
||||
&i.Password,
|
||||
&i.Age,
|
||||
&i.EducationLevel,
|
||||
&i.Country,
|
||||
|
|
@ -495,82 +509,6 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
|
|||
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
|
||||
SELECT id,
|
||||
first_name,
|
||||
|
|
|
|||
9
go.mod
9
go.mod
|
|
@ -6,7 +6,6 @@ toolchain go1.24.11
|
|||
|
||||
require (
|
||||
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/joho/godotenv v1.5.1
|
||||
github.com/resend/resend-go/v2 v2.28.0
|
||||
|
|
@ -16,6 +15,8 @@ require (
|
|||
golang.org/x/crypto v0.45.0
|
||||
)
|
||||
|
||||
require github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.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/universal-translator v0.18.1 // 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/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // 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/mailru/easyjson v0.7.6 // 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/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // 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
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
|
|
@ -66,7 +65,7 @@ require (
|
|||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/uuid v1.6.0
|
||||
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/klauspost/compress v1.17.9 // 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/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
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/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
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/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
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.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/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
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.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
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/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-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.52.10 h1:jRHROi2BuNti6NYXmZ6gbNSfT3zj/8c0xy94GOU5elY=
|
||||
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.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
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/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/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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/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/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/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/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/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
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/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
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.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
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/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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
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.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.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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/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/go.mod h1:zt6UU74K6Z6oMOYJbJzYpYucqdcQwSMPBEdSvGiaUMw=
|
||||
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.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
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/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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
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.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
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/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/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/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/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.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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
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.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.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.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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
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.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
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/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/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/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/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/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-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-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-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/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.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/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-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-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
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-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.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/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-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.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/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-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-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-20210330210617-4fbd30eecc44/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-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.5.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/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-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.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.4/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.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/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-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-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-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.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.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/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-20191011141410-1b5146add898/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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
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")
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
case RoleAdmin:
|
||||
return NotificationRecieverSideAdmin
|
||||
case RoleCashier:
|
||||
return NotificationRecieverSideCashier
|
||||
case RoleBranchManager:
|
||||
return NotificationRecieverSideBranchManager
|
||||
case RoleCustomer:
|
||||
case RoleSuperAdmin:
|
||||
return NotificationRecieverSideAdmin
|
||||
case RoleStudent:
|
||||
return NotificationRecieverSideCustomer
|
||||
case RoleInstructor:
|
||||
return NotificationRecieverSideCustomer
|
||||
default:
|
||||
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
|
||||
|
||||
const (
|
||||
RoleSuperAdmin Role = "super_admin"
|
||||
RoleAdmin Role = "admin"
|
||||
RoleBranchManager Role = "branch_manager"
|
||||
RoleCustomer Role = "customer"
|
||||
RoleCashier Role = "cashier"
|
||||
RoleTransactionApprover Role = "transaction_approver"
|
||||
RoleSuperAdmin Role = "super_admin"
|
||||
RoleAdmin Role = "admin"
|
||||
RoleStudent Role = "student"
|
||||
RoleInstructor Role = "instructor"
|
||||
RoleSupport Role = "support"
|
||||
)
|
||||
|
||||
func (r Role) IsValid() bool {
|
||||
switch r {
|
||||
case RoleSuperAdmin, RoleAdmin, RoleBranchManager, RoleCustomer, RoleCashier, RoleTransactionApprover:
|
||||
case RoleSuperAdmin, RoleAdmin, RoleStudent, RoleInstructor, RoleSupport:
|
||||
return true
|
||||
default:
|
||||
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
|
||||
|
||||
// import (
|
||||
// "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// dbgen "Yimaru-Backend/gen/db"
|
||||
// )
|
||||
type Setting struct {
|
||||
Key string
|
||||
Value string
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// type Setting struct {
|
||||
// Key string
|
||||
// Value string
|
||||
// UpdatedAt time.Time
|
||||
// }
|
||||
type CreateSetting struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// type CreateSetting struct {
|
||||
// Key string
|
||||
// Value string
|
||||
// }
|
||||
type SettingRes struct {
|
||||
Key string `json:"key"`
|
||||
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 {
|
||||
// Key string `json:"key"`
|
||||
// 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 CompanySettingRes struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// type CompanySettingRes struct {
|
||||
// Key string `json:"key"`
|
||||
// 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 ConvertSetting(setting Setting) SettingRes {
|
||||
return SettingRes(setting)
|
||||
}
|
||||
|
||||
// func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
|
||||
// return CompanySetting{
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import (
|
|||
|
||||
type NotificationStore interface {
|
||||
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)
|
||||
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)
|
||||
UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error)
|
||||
ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error)
|
||||
DeleteOldNotifications(ctx context.Context) error
|
||||
// UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error)
|
||||
// ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error)
|
||||
// DeleteOldNotifications(ctx context.Context) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
package ports
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
type SettingStore interface {
|
||||
// GetGlobalSettingList(ctx context.Context) (domain.SettingList, error)
|
||||
// GetGlobalSettings(ctx context.Context) ([]domain.Setting, error)
|
||||
// GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error)
|
||||
// UpdateGlobalSetting(ctx context.Context, key, value string) error
|
||||
// UpdateGlobalSettingList(ctx context.Context, settingList domain.ValidSettingList) error
|
||||
GetGlobalSettingList(ctx context.Context) (domain.SettingList, error)
|
||||
GetGlobalSettings(ctx context.Context) ([]domain.Setting, error)
|
||||
GetGlobalSetting(ctx context.Context, key string) (domain.Setting, error)
|
||||
UpdateGlobalSetting(ctx context.Context, key, value string) error
|
||||
UpdateGlobalSettingList(ctx context.Context, settingList domain.ValidSettingList) error
|
||||
|
||||
// InsertCompanySetting(ctx context.Context, key, value string, 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)
|
||||
// GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,34 +2,53 @@ package ports
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"Yimaru-Backend/internal/domain"
|
||||
)
|
||||
|
||||
type UserStore interface {
|
||||
CreateUser(ctx context.Context, user domain.User, usedOtpId int64, is_company bool) (domain.User, error)
|
||||
CreateUserWithoutOtp(ctx context.Context, user domain.User, 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) (domain.User, error)
|
||||
GetUserByID(ctx context.Context, id int64) (domain.User, error)
|
||||
GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error)
|
||||
// GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([]domain.GetCashier, int64, error)
|
||||
// GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error)
|
||||
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
|
||||
GetAdminByCompanyID(ctx context.Context, companyID int64) (domain.User, error)
|
||||
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
|
||||
UpdateUserCompany(ctx context.Context, id int64, companyID int64) error
|
||||
GetAllUsers(
|
||||
ctx context.Context,
|
||||
role *string,
|
||||
organizationID *int64,
|
||||
query *string,
|
||||
createdBefore, createdAfter *time.Time,
|
||||
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
|
||||
DeleteUser(ctx context.Context, id int64) error
|
||||
CheckPhoneEmailExist(ctx context.Context, phoneNum, email string, companyID domain.ValidInt64) (bool, bool, error)
|
||||
GetUserByEmail(ctx context.Context, email 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)
|
||||
UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64, companyId int64) error
|
||||
GetUserByEmailPhone(ctx context.Context, email, phone string, companyID domain.ValidInt64) (domain.User, 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)
|
||||
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)
|
||||
|
||||
// UpdateUser(ctx context.Context, user domain.UpdateUserReq) 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)
|
||||
// GetUserByEmail(ctx context.Context, email 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)
|
||||
// UpdatePassword(ctx context.Context, identifier string, password []byte, usedOtpId int64, companyId int64) error
|
||||
// GetUserByEmailPhone(ctx context.Context, email, phone string, companyID domain.ValidInt64) (domain.User, 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 {
|
||||
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
|
||||
|
||||
// import (
|
||||
// "context"
|
||||
// "encoding/json"
|
||||
// "fmt"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
// dbgen "Yimaru-Backend/gen/db"
|
||||
// "Yimaru-Backend/internal/domain"
|
||||
// "Yimaru-Backend/internal/ports"
|
||||
// "github.com/jackc/pgx/v5/pgtype"
|
||||
// )
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"Yimaru-Backend/internal/ports"
|
||||
|
||||
// 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) {
|
||||
// var errorSeverity pgtype.Text
|
||||
// if notification.ErrorSeverity != "" {
|
||||
// errorSeverity.String = string(notification.ErrorSeverity)
|
||||
// errorSeverity.Valid = true
|
||||
// }
|
||||
func NewNotificationStore(s *Store) ports.NotificationStore {
|
||||
return s
|
||||
}
|
||||
|
||||
// var deliveryChannel pgtype.Text
|
||||
// if notification.DeliveryChannel != "" {
|
||||
// deliveryChannel.String = string(notification.DeliveryChannel)
|
||||
// deliveryChannel.Valid = true
|
||||
// }
|
||||
/* =========================
|
||||
Create
|
||||
========================= */
|
||||
|
||||
// var priority pgtype.Int4
|
||||
// if notification.Priority != 0 {
|
||||
// priority.Int32 = int32(notification.Priority)
|
||||
// priority.Valid = true
|
||||
// }
|
||||
func (r *Store) CreateNotification(
|
||||
ctx context.Context,
|
||||
n *domain.Notification,
|
||||
) (*domain.Notification, error) {
|
||||
|
||||
// params := dbgen.CreateNotificationParams{
|
||||
// ID: notification.ID,
|
||||
// RecipientID: notification.RecipientID,
|
||||
// Type: string(notification.Type),
|
||||
// Level: string(notification.Level),
|
||||
// ErrorSeverity: errorSeverity,
|
||||
// Reciever: string(notification.Reciever),
|
||||
// IsRead: notification.IsRead,
|
||||
// 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,
|
||||
// }
|
||||
params := dbgen.CreateNotificationParams{
|
||||
UserID: n.RecipientID,
|
||||
Type: string(n.Type),
|
||||
Level: string(n.Level),
|
||||
Channel: pgtype.Text{String: string(n.DeliveryChannel)},
|
||||
Title: n.Payload.Headline,
|
||||
Message: n.Payload.Message,
|
||||
Payload: marshalPayload(n.Payload),
|
||||
}
|
||||
|
||||
// dbNotification, err := r.queries.CreateNotification(ctx, params)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
dbNotif, err := r.queries.CreateNotification(ctx, params)
|
||||
if err != nil {
|
||||
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{
|
||||
// ID: id,
|
||||
// DeliveryStatus: status,
|
||||
// IsRead: isRead,
|
||||
// Metadata: metadata,
|
||||
// }
|
||||
/* =========================
|
||||
Read
|
||||
========================= */
|
||||
|
||||
// dbNotification, err := r.queries.UpdateNotificationStatus(ctx, params)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
func (r *Store) GetUserNotifications(
|
||||
ctx context.Context,
|
||||
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) {
|
||||
// params := dbgen.GetUserNotificationsParams{
|
||||
// RecipientID: recipientID,
|
||||
// Limit: int32(limit),
|
||||
// Offset: int32(offset),
|
||||
// }
|
||||
rows, err := r.queries.GetUserNotifications(ctx, params)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// dbNotifications, err := r.queries.GetUserNotifications(ctx, params)
|
||||
// if err != nil {
|
||||
// return nil, 0, err
|
||||
// }
|
||||
total, err := r.queries.GetUserNotificationCount(ctx, userID)
|
||||
if err != nil {
|
||||
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 nil, 0, err
|
||||
// }
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
||||
// for _, dbNotif := range dbNotifications {
|
||||
// domainNotif := r.mapDBToDomain(&dbNotif)
|
||||
// result = append(result, *domainNotif)
|
||||
// }
|
||||
func (r *Store) GetAllNotifications(
|
||||
ctx context.Context,
|
||||
limit, offset int,
|
||||
) ([]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{
|
||||
// Limit: int32(limit),
|
||||
// Offset: int32(offset),
|
||||
// })
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
||||
// for _, dbNotif := range dbNotifications {
|
||||
// domainNotif := r.mapDBToDomain(&dbNotif)
|
||||
// result = append(result, *domainNotif)
|
||||
// }
|
||||
// return result, nil
|
||||
// }
|
||||
func (r *Store) CountUnreadNotifications(
|
||||
ctx context.Context,
|
||||
userID int64,
|
||||
) (int64, error) {
|
||||
return r.queries.CountUnreadNotifications(ctx, userID)
|
||||
}
|
||||
|
||||
// func (r *Store) ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error) {
|
||||
// dbNotifications, err := r.queries.ListFailedNotifications(ctx, int32(limit))
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
/* =========================
|
||||
Update
|
||||
========================= */
|
||||
|
||||
// var result []domain.Notification
|
||||
// for _, dbNotif := range dbNotifications {
|
||||
// domainNotif := r.mapDBToDomain(&dbNotif)
|
||||
// result = append(result, *domainNotif)
|
||||
// }
|
||||
func (r *Store) MarkNotificationAsRead(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (*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 r.queries.ListRecipientIDsByReceiver(ctx, string(receiver))
|
||||
// }
|
||||
return mapDBToDomain(&dbNotif), nil
|
||||
}
|
||||
|
||||
// func (s *Store) DeleteOldNotifications(ctx context.Context) error {
|
||||
// return s.queries.DeleteOldNotifications(ctx)
|
||||
// }
|
||||
func (r *Store) MarkAllUserNotificationsAsRead(
|
||||
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
|
||||
// if dbNotif.ErrorSeverity.Valid {
|
||||
// errorSeverity = domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String)
|
||||
/* =========================
|
||||
Delete
|
||||
========================= */
|
||||
|
||||
// } else {
|
||||
// errorSeverity = ""
|
||||
// }
|
||||
func (r *Store) DeleteUserNotifications(
|
||||
ctx context.Context,
|
||||
userID int64,
|
||||
) error {
|
||||
return r.queries.DeleteUserNotifications(ctx, userID)
|
||||
}
|
||||
|
||||
// var deliveryChannel domain.DeliveryChannel
|
||||
// if dbNotif.DeliveryChannel.Valid {
|
||||
// deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String)
|
||||
// } else {
|
||||
// deliveryChannel = ""
|
||||
// }
|
||||
/* =========================
|
||||
Mapping
|
||||
========================= */
|
||||
|
||||
// var priority int
|
||||
// if dbNotif.Priority.Valid {
|
||||
// priority = int(dbNotif.Priority.Int32)
|
||||
// }
|
||||
func mapDBToDomain(db *dbgen.Notification) *domain.Notification {
|
||||
payload, err := unmarshalPayload(db.Payload)
|
||||
if err != nil {
|
||||
payload = domain.NotificationPayload{}
|
||||
}
|
||||
|
||||
// payload, err := unmarshalPayload(dbNotif.Payload)
|
||||
// if err != nil {
|
||||
// payload = domain.NotificationPayload{}
|
||||
// }
|
||||
var channel domain.DeliveryChannel
|
||||
if db.Channel.Valid {
|
||||
channel = domain.DeliveryChannel(db.Channel.String)
|
||||
}
|
||||
|
||||
// return &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,
|
||||
// Expires: dbNotif.Expires.Time,
|
||||
// Image: dbNotif.Img.String,
|
||||
// Metadata: dbNotif.Metadata,
|
||||
// }
|
||||
// }
|
||||
return &domain.Notification{
|
||||
ID: string(db.ID),
|
||||
RecipientID: db.UserID,
|
||||
Type: domain.NotificationType(db.Type),
|
||||
Level: domain.NotificationLevel(db.Level),
|
||||
DeliveryChannel: channel,
|
||||
DeliveryStatus: "PENDING",
|
||||
Payload: domain.NotificationPayload{
|
||||
Headline: payload.Headline,
|
||||
Message: payload.Message,
|
||||
},
|
||||
IsRead: db.IsRead,
|
||||
Timestamp: db.CreatedAt.Time,
|
||||
// ReadAt: db.ReadAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
// func marshalPayload(payload domain.NotificationPayload) []byte {
|
||||
// data, _ := json.Marshal(payload)
|
||||
// return data
|
||||
// }
|
||||
/* =========================
|
||||
JSON Helpers
|
||||
========================= */
|
||||
|
||||
// func unmarshalPayload(data []byte) (domain.NotificationPayload, error) {
|
||||
// var payload domain.NotificationPayload
|
||||
// if err := json.Unmarshal(data, &payload); err != nil {
|
||||
// return domain.NotificationPayload{}, err
|
||||
// }
|
||||
// return payload, nil
|
||||
// }
|
||||
func marshalPayload(p domain.NotificationPayload) []byte {
|
||||
b, _ := json.Marshal(p)
|
||||
return b
|
||||
}
|
||||
|
||||
// func (r *Store) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
||||
// return r.queries.CountUnreadNotifications(ctx, recipient_id)
|
||||
// }
|
||||
|
||||
// func (r *Store) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error) {
|
||||
// rows, err := r.queries.GetNotificationCounts(ctx)
|
||||
// if err != nil {
|
||||
// return 0, 0, 0, fmt.Errorf("failed to get notification counts: %w", err)
|
||||
// }
|
||||
|
||||
// // 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
|
||||
// // }
|
||||
func unmarshalPayload(b []byte) (domain.NotificationPayload, error) {
|
||||
var p domain.NotificationPayload
|
||||
if len(b) == 0 {
|
||||
return p, nil
|
||||
}
|
||||
if err := json.Unmarshal(b, &p); err != nil {
|
||||
return p, err
|
||||
}
|
||||
return p, 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 (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"Yimaru-Backend/internal/ports"
|
||||
"Yimaru-Backend/internal/services/authentication"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"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
|
||||
func (s *Store) CreateUser(ctx context.Context, user domain.User, usedOtpId int64) (domain.User, error) {
|
||||
// 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
|
||||
func (s *Store) GetAllUsers(ctx context.Context, role *string, organizationID *int64, query *string, createdBefore, createdAfter *time.Time, limit, offset int32) ([]domain.User, error) {
|
||||
rows, err := s.queries.GetAllUsers(ctx, dbgen.GetAllUsersParams{
|
||||
Role: *role,
|
||||
OrganizationID: pgtype.Int8{Int64: *organizationID},
|
||||
Query: pgtype.Text{String: *query},
|
||||
CreatedBefore: pgtype.Timestamptz{Time: *createdBefore},
|
||||
CreatedAfter: pgtype.Timestamptz{Time: *createdAfter},
|
||||
Limit: pgtype.Int4{Int32: limit},
|
||||
Offset: pgtype.Int4{Int32: offset},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Store) GetAllUsers(
|
||||
ctx context.Context,
|
||||
role *string,
|
||||
organizationID *int64,
|
||||
query *string,
|
||||
createdBefore, createdAfter *time.Time,
|
||||
limit, offset int32,
|
||||
) ([]domain.User, int64, error) {
|
||||
|
||||
params := dbgen.GetAllUsersParams{
|
||||
Limit: pgtype.Int4{Int32: limit, Valid: true},
|
||||
Offset: pgtype.Int4{Int32: offset, Valid: true},
|
||||
}
|
||||
|
||||
users := make([]domain.User, len(rows))
|
||||
for i, u := range rows {
|
||||
users[i] = domain.User{
|
||||
if role != nil {
|
||||
params.Role = *role
|
||||
}
|
||||
|
||||
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,
|
||||
FirstName: u.FirstName,
|
||||
LastName: u.LastName,
|
||||
|
|
@ -149,13 +231,16 @@ func (s *Store) GetAllUsers(ctx context.Context, role *string, organizationID *i
|
|||
PhoneVerified: u.PhoneVerified,
|
||||
Suspended: u.Suspended,
|
||||
SuspendedAt: u.SuspendedAt.Time,
|
||||
OrganizationID: domain.ValidInt64{Value: u.OrganizationID.Int64, Valid: u.OrganizationID.Valid},
|
||||
CreatedAt: u.CreatedAt.Time,
|
||||
UpdatedAt: u.UpdatedAt.Time,
|
||||
}
|
||||
OrganizationID: domain.ValidInt64{
|
||||
Value: u.OrganizationID.Int64,
|
||||
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
|
||||
|
|
@ -241,11 +326,11 @@ func (s *Store) DeleteUser(ctx context.Context, userID int64) error {
|
|||
}
|
||||
|
||||
// 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{
|
||||
PhoneNumber: pgtype.Text{String: phone},
|
||||
Email: pgtype.Text{String: email},
|
||||
OrganizationID: pgtype.Int8{Int64: organizationID},
|
||||
OrganizationID: pgtype.Int8{Int64: organizationID.Value},
|
||||
})
|
||||
if err != nil {
|
||||
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
|
||||
func (s *Store) GetUserByEmail(ctx context.Context, email string, organizationID int64) (domain.User, error) {
|
||||
userRes, err := s.queries.GetUserByEmail(ctx, dbgen.GetUserByEmailParams{
|
||||
Email: pgtype.Text{String: email},
|
||||
OrganizationID: pgtype.Int8{Int64: organizationID},
|
||||
})
|
||||
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
|
||||
}
|
||||
func (s *Store) GetUserByEmailPhone(
|
||||
ctx context.Context,
|
||||
email string,
|
||||
phone string,
|
||||
organizationID domain.ValidInt64,
|
||||
) (domain.User, error) {
|
||||
|
||||
// GetUserByPhone retrieves a user by phone and organization
|
||||
func (s *Store) GetUserByPhone(ctx context.Context, phone string, organizationID int64) (domain.User, error) {
|
||||
userRes, err := s.queries.GetUserByPhone(ctx, dbgen.GetUserByPhoneParams{
|
||||
PhoneNumber: pgtype.Text{String: phone},
|
||||
OrganizationID: pgtype.Int8{Int64: organizationID},
|
||||
user, err := s.queries.GetUserByEmailPhone(ctx, dbgen.GetUserByEmailPhoneParams{
|
||||
Email: pgtype.Text{
|
||||
String: email,
|
||||
Valid: email != "",
|
||||
},
|
||||
PhoneNumber: pgtype.Text{
|
||||
String: phone,
|
||||
Valid: phone != "",
|
||||
},
|
||||
OrganizationID: organizationID.ToPG(),
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return domain.User{}, authentication.ErrUserNotFound
|
||||
}
|
||||
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,
|
||||
ID: user.ID,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
NickName: user.NickName.String,
|
||||
Email: user.Email.String,
|
||||
PhoneNumber: user.PhoneNumber.String,
|
||||
Password: user.Password,
|
||||
Role: domain.Role(user.Role),
|
||||
Age: int(user.Age.Int32),
|
||||
EducationLevel: user.EducationLevel.String,
|
||||
Country: user.Country.String,
|
||||
Region: user.Region.String,
|
||||
EmailVerified: user.EmailVerified,
|
||||
PhoneVerified: user.PhoneVerified,
|
||||
Suspended: user.Suspended,
|
||||
SuspendedAt: user.SuspendedAt.Time,
|
||||
OrganizationID: domain.ValidInt64{
|
||||
Value: user.OrganizationID.Int64,
|
||||
Valid: user.OrganizationID.Valid,
|
||||
},
|
||||
CreatedAt: user.CreatedAt.Time,
|
||||
UpdatedAt: user.UpdatedAt.Time,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +411,21 @@ func (s *Store) GetOwnerByOrganizationID(ctx context.Context, organizationID int
|
|||
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
|
||||
func mapUser(u dbgen.User) 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 {
|
||||
apiKey := s.config.ResendApiKey
|
||||
client := resend.NewClient(apiKey)
|
||||
formattedSenderEmail := "FortuneBets <" + s.config.ResendSenderEmail + ">"
|
||||
formattedSenderEmail := "Y <" + s.config.ResendSenderEmail + ">"
|
||||
params := &resend.SendEmailRequest{
|
||||
From: formattedSenderEmail,
|
||||
To: []string{receiverEmail},
|
||||
|
|
|
|||
|
|
@ -19,21 +19,21 @@ var (
|
|||
func (s *Service) SendSMS(ctx context.Context, receiverPhone, message string, companyID domain.ValidInt64) error {
|
||||
|
||||
var settingsList domain.SettingList
|
||||
var err error
|
||||
// var err error
|
||||
|
||||
if companyID.Valid {
|
||||
settingsList, err = s.settingSvc.GetOverrideSettingsList(ctx, companyID.Value)
|
||||
if err != nil {
|
||||
// TODO: Send a log about the error
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
settingsList, err = s.settingSvc.GetGlobalSettingList(ctx)
|
||||
if err != nil {
|
||||
// TODO: Send a log about the error
|
||||
return err
|
||||
}
|
||||
}
|
||||
// if companyID.Valid {
|
||||
// settingsList, err = s.settingSvc.GetOverrideSettingsList(ctx, companyID.Value)
|
||||
// if err != nil {
|
||||
// // TODO: Send a log about the error
|
||||
// return err
|
||||
// }
|
||||
// } else {
|
||||
// settingsList, err = s.settingSvc.GetGlobalSettingList(ctx)
|
||||
// if err != nil {
|
||||
// // TODO: Send a log about the error
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
|
||||
switch settingsList.SMSProvider {
|
||||
case domain.AfroMessage:
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func New(
|
|||
|
||||
go hub.Run()
|
||||
go svc.startWorker()
|
||||
go svc.startRetryWorker()
|
||||
// go svc.startRetryWorker()
|
||||
// go svc.RunRedisSubscriber(context.Background())
|
||||
// go svc.StartKafkaConsumer(context.Background())
|
||||
|
||||
|
|
@ -123,42 +123,42 @@ func (s *Service) SendNotification(ctx context.Context, notification *domain.Not
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) MarkAsRead(ctx context.Context, notificationIDs []string, recipientID int64) error {
|
||||
for _, notificationID := range notificationIDs {
|
||||
_, err := s.store.UpdateNotificationStatus(ctx, notificationID, string(domain.DeliveryStatusSent), true, nil)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error("[NotificationSvc.MarkAsRead] Failed to mark notification as read",
|
||||
zap.String("notificationID", notificationID),
|
||||
zap.Int64("recipientID", recipientID),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return err
|
||||
}
|
||||
// func (s *Service) MarkAsRead(ctx context.Context, notificationIDs []string, recipientID int64) error {
|
||||
// for _, notificationID := range notificationIDs {
|
||||
// _, err := s.store.UpdateNotificationStatus(ctx, notificationID, string(domain.DeliveryStatusSent), true, nil)
|
||||
// if err != nil {
|
||||
// s.mongoLogger.Error("[NotificationSvc.MarkAsRead] Failed to mark notification as read",
|
||||
// zap.String("notificationID", notificationID),
|
||||
// zap.Int64("recipientID", recipientID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return err
|
||||
// }
|
||||
|
||||
// count, err := s.store.CountUnreadNotifications(ctx, recipientID)
|
||||
// if err != nil {
|
||||
// s.logger.Error("[NotificationSvc.MarkAsRead] Failed to count unread notifications", "recipientID", recipientID, "error", err)
|
||||
// return err
|
||||
// }
|
||||
// // count, err := s.store.CountUnreadNotifications(ctx, recipientID)
|
||||
// // if err != nil {
|
||||
// // s.logger.Error("[NotificationSvc.MarkAsRead] Failed to count unread notifications", "recipientID", recipientID, "error", err)
|
||||
// // return err
|
||||
// // }
|
||||
|
||||
// s.Hub.Broadcast <- map[string]interface{}{
|
||||
// "type": "COUNT_NOT_OPENED_NOTIFICATION",
|
||||
// "recipient_id": recipientID,
|
||||
// "payload": map[string]int{
|
||||
// "not_opened_notifications_count": int(count),
|
||||
// },
|
||||
// }
|
||||
// // s.Hub.Broadcast <- map[string]interface{}{
|
||||
// // "type": "COUNT_NOT_OPENED_NOTIFICATION",
|
||||
// // "recipient_id": recipientID,
|
||||
// // "payload": map[string]int{
|
||||
// // "not_opened_notifications_count": int(count),
|
||||
// // },
|
||||
// // }
|
||||
|
||||
s.mongoLogger.Info("[NotificationSvc.MarkAsRead] Notification marked as read",
|
||||
zap.String("notificationID", notificationID),
|
||||
zap.Int64("recipientID", recipientID),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
}
|
||||
// s.mongoLogger.Info("[NotificationSvc.MarkAsRead] Notification marked as read",
|
||||
// zap.String("notificationID", notificationID),
|
||||
// zap.Int64("recipientID", recipientID),
|
||||
// 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) {
|
||||
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) {
|
||||
return s.store.ListRecipientIDs(ctx, receiver)
|
||||
}
|
||||
// func (s *Service) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||
// return s.store.ListRecipientIDs(ctx, receiver)
|
||||
// }
|
||||
|
||||
func (s *Service) handleNotification(notification *domain.Notification) {
|
||||
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 {
|
||||
s.mongoLogger.Error("[NotificationSvc.HandleNotification] Failed to update notification status",
|
||||
zap.String("id", notification.ID),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
}
|
||||
// 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",
|
||||
// zap.String("id", notification.ID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (s *Service) startRetryWorker() {
|
||||
ticker := time.NewTicker(1 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
// func (s *Service) startRetryWorker() {
|
||||
// ticker := time.NewTicker(1 * time.Minute)
|
||||
// defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.retryFailedNotifications()
|
||||
case <-s.stopCh:
|
||||
s.mongoLogger.Info("[NotificationSvc.StartRetryWorker] Retry worker stopped",
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// for {
|
||||
// select {
|
||||
// case <-ticker.C:
|
||||
// s.retryFailedNotifications()
|
||||
// case <-s.stopCh:
|
||||
// s.mongoLogger.Info("[NotificationSvc.StartRetryWorker] Retry worker stopped",
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func (s *Service) retryFailedNotifications() {
|
||||
ctx := context.Background()
|
||||
failedNotifications, err := s.store.ListFailedNotifications(ctx, 100)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to list failed notifications",
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return
|
||||
}
|
||||
// func (s *Service) retryFailedNotifications() {
|
||||
// ctx := context.Background()
|
||||
// failedNotifications, err := s.store.ListFailedNotifications(ctx, 100)
|
||||
// if err != nil {
|
||||
// s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Failed to list failed notifications",
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return
|
||||
// }
|
||||
|
||||
for _, n := range failedNotifications {
|
||||
notification := &n
|
||||
go func(notification *domain.Notification) {
|
||||
for attempt := 0; attempt < 3; attempt++ {
|
||||
time.Sleep(time.Duration(attempt) * time.Second)
|
||||
switch notification.DeliveryChannel {
|
||||
case domain.DeliveryChannelSMS:
|
||||
if err := s.SendNotificationSMS(ctx, notification.RecipientID, notification.Payload.Message); err == nil {
|
||||
notification.DeliveryStatus = domain.DeliveryStatusSent
|
||||
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",
|
||||
zap.String("id", notification.ID),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
} else {
|
||||
s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
||||
zap.String("id", notification.ID),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
}
|
||||
// for _, n := range failedNotifications {
|
||||
// notification := &n
|
||||
// go func(notification *domain.Notification) {
|
||||
// for attempt := 0; attempt < 3; attempt++ {
|
||||
// time.Sleep(time.Duration(attempt) * time.Second)
|
||||
// switch notification.DeliveryChannel {
|
||||
// case domain.DeliveryChannelSMS:
|
||||
// if err := s.SendNotificationSMS(ctx, notification.RecipientID, notification.Payload.Message); err == nil {
|
||||
// notification.DeliveryStatus = domain.DeliveryStatusSent
|
||||
// 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",
|
||||
// zap.String("id", notification.ID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// } else {
|
||||
// s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
||||
// zap.String("id", notification.ID),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
case domain.DeliveryChannelEmail:
|
||||
if err := s.SendNotificationEmail(ctx, notification.RecipientID, notification.Payload.Message, notification.Payload.Headline); err == nil {
|
||||
notification.DeliveryStatus = domain.DeliveryStatusSent
|
||||
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",
|
||||
zap.String("id", notification.ID),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
} else {
|
||||
s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
||||
zap.String("id", notification.ID),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
}
|
||||
// return
|
||||
// }
|
||||
// case domain.DeliveryChannelEmail:
|
||||
// if err := s.SendNotificationEmail(ctx, notification.RecipientID, notification.Payload.Message, notification.Payload.Headline); err == nil {
|
||||
// notification.DeliveryStatus = domain.DeliveryStatusSent
|
||||
// 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",
|
||||
// zap.String("id", notification.ID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// } else {
|
||||
// s.mongoLogger.Info("[NotificationSvc.RetryFailedNotifications] Successfully retried notification",
|
||||
// zap.String("id", notification.ID),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Max retries reached for notification",
|
||||
zap.String("id", notification.ID),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
}(notification)
|
||||
}
|
||||
}
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// s.mongoLogger.Error("[NotificationSvc.RetryFailedNotifications] Max retries reached for notification",
|
||||
// zap.String("id", notification.ID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// }(notification)
|
||||
// }
|
||||
// }
|
||||
|
||||
func (s *Service) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
||||
return s.store.CountUnreadNotifications(ctx, recipient_id)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteOldNotifications(ctx context.Context) error {
|
||||
return s.store.DeleteOldNotifications(ctx)
|
||||
}
|
||||
// func (s *Service) DeleteOldNotifications(ctx context.Context) error {
|
||||
// return s.store.DeleteOldNotifications(ctx)
|
||||
// }
|
||||
|
||||
// func (s *Service) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error){
|
||||
// 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)
|
||||
}
|
||||
|
||||
func (s *Service) InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error {
|
||||
return s.settingStore.InsertCompanySetting(ctx, key, value, companyID)
|
||||
}
|
||||
func (s *Service) InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error {
|
||||
return s.settingStore.InsertCompanySettingList(ctx, settingList, companyID)
|
||||
}
|
||||
func (s *Service) GetAllCompanySettings(ctx context.Context) ([]domain.CompanySetting, error) {
|
||||
return s.settingStore.GetAllCompanySettings(ctx)
|
||||
}
|
||||
func (s *Service) GetCompanySettingsByKey(ctx context.Context, key string) ([]domain.CompanySetting, error) {
|
||||
return s.settingStore.GetCompanySettingsByKey(ctx, key)
|
||||
}
|
||||
func (s *Service) GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error) {
|
||||
return s.settingStore.GetOverrideSettings(ctx, companyID)
|
||||
}
|
||||
func (s *Service) GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) {
|
||||
return s.settingStore.GetOverrideSettingsList(ctx, companyID)
|
||||
}
|
||||
// func (s *Service) InsertCompanySetting(ctx context.Context, key, value string, companyID int64) error {
|
||||
// return s.settingStore.InsertCompanySetting(ctx, key, value, companyID)
|
||||
// }
|
||||
// func (s *Service) InsertCompanySettingList(ctx context.Context, settingList domain.ValidSettingList, companyID int64) error {
|
||||
// return s.settingStore.InsertCompanySettingList(ctx, settingList, companyID)
|
||||
// }
|
||||
// func (s *Service) GetAllCompanySettings(ctx context.Context) ([]domain.CompanySetting, error) {
|
||||
// return s.settingStore.GetAllCompanySettings(ctx)
|
||||
// }
|
||||
// func (s *Service) GetCompanySettingsByKey(ctx context.Context, key string) ([]domain.CompanySetting, error) {
|
||||
// return s.settingStore.GetCompanySettingsByKey(ctx, key)
|
||||
// }
|
||||
// func (s *Service) GetOverrideSettings(ctx context.Context, companyID int64) ([]domain.Setting, error) {
|
||||
// return s.settingStore.GetOverrideSettings(ctx, companyID)
|
||||
// }
|
||||
// func (s *Service) GetOverrideSettingsList(ctx context.Context, companyID int64) (domain.SettingList, error) {
|
||||
// return s.settingStore.GetOverrideSettingsList(ctx, companyID)
|
||||
// }
|
||||
|
||||
func (s *Service) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
|
||||
return s.settingStore.DeleteCompanySetting(ctx, companyID, key)
|
||||
}
|
||||
// func (s *Service) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
|
||||
// return s.settingStore.DeleteCompanySetting(ctx, companyID, key)
|
||||
// }
|
||||
|
||||
func (s *Service) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
|
||||
return s.settingStore.DeleteAllCompanySetting(ctx, companyID)
|
||||
}
|
||||
// func (s *Service) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
|
||||
// return s.settingStore.DeleteAllCompanySetting(ctx, companyID)
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -134,39 +134,41 @@ func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role dom
|
|||
// var companyID int64
|
||||
|
||||
switch role {
|
||||
case domain.RoleAdmin, domain.RoleBranchManager, domain.RoleSuperAdmin:
|
||||
case domain.RoleAdmin, domain.RoleSuperAdmin:
|
||||
if branchID == nil {
|
||||
// h.logger.Error("CashoutReq Branch ID is required for this user role")
|
||||
return nil, nil, ErrBranchRequiredForRole
|
||||
}
|
||||
branch, err := s.branchSvc.GetBranchByID(ctx, *branchID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq no branches")
|
||||
return nil, nil, err
|
||||
}
|
||||
// branch, err := s.branchSvc.GetBranchByID(ctx, *branchID)
|
||||
// if err != nil {
|
||||
// // h.logger.Error("CashoutReq no branches")
|
||||
// return nil, nil, err
|
||||
// }
|
||||
|
||||
// Check if the user has access to the company
|
||||
if role != domain.RoleSuperAdmin {
|
||||
if userCompanyID.Valid && userCompanyID.Value != branch.CompanyID {
|
||||
return nil, nil, ErrUnauthorizedCompanyID
|
||||
}
|
||||
// if userCompanyID.Valid && userCompanyID.Value != branch.CompanyID {
|
||||
// return nil, nil, ErrUnauthorizedCompanyID
|
||||
// }
|
||||
}
|
||||
|
||||
if role == domain.RoleBranchManager {
|
||||
if branch.BranchManagerID != userID {
|
||||
return nil, nil, ErrUnauthorizedBranchManager
|
||||
}
|
||||
}
|
||||
// if role == domain.RoleBranchManager {
|
||||
// // if branch.BranchManagerID != userID {
|
||||
// // return nil, nil, ErrUnauthorizedBranchManager
|
||||
// // }
|
||||
// }
|
||||
|
||||
return &branch.ID, &branch.CompanyID, nil
|
||||
case domain.RoleCashier:
|
||||
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq failed, branch id invalid")
|
||||
return nil, nil, ErrInvalidBranchID
|
||||
}
|
||||
return &branch.ID, &branch.CompanyID, nil
|
||||
// return &branch.ID, &branch.CompanyID, nil
|
||||
case domain.RoleInstructor:
|
||||
// branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||
// if err != nil {
|
||||
// // h.logger.Error("CashoutReq failed, branch id invalid")
|
||||
// return nil, nil, ErrInvalidBranchID
|
||||
// }
|
||||
// return &branch.ID, &branch.CompanyID, nil
|
||||
default:
|
||||
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 {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,17 +25,17 @@ func (s *Service) CreateUser(ctx context.Context, User domain.CreateUserReq, is_
|
|||
}
|
||||
|
||||
return s.userStore.CreateUserWithoutOtp(ctx, domain.User{
|
||||
FirstName: User.FirstName,
|
||||
LastName: User.LastName,
|
||||
Email: User.Email,
|
||||
PhoneNumber: User.PhoneNumber,
|
||||
Password: hashedPassword,
|
||||
Role: domain.Role(User.Role),
|
||||
EmailVerified: true,
|
||||
PhoneVerified: true,
|
||||
Suspended: User.Suspended,
|
||||
CompanyID: User.CompanyID,
|
||||
}, is_company)
|
||||
FirstName: User.FirstName,
|
||||
LastName: User.LastName,
|
||||
Email: User.Email,
|
||||
PhoneNumber: User.PhoneNumber,
|
||||
Password: hashedPassword,
|
||||
Role: domain.Role(User.Role),
|
||||
EmailVerified: true,
|
||||
PhoneVerified: true,
|
||||
Suspended: User.Suspended,
|
||||
OrganizationID: User.OrganizationID,
|
||||
})
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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) {
|
||||
|
||||
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
|
||||
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 {
|
||||
var err error
|
||||
// check if user exists
|
||||
switch medium {
|
||||
case domain.OtpMediumEmail:
|
||||
_, err = s.userStore.GetUserByEmail(ctx, sentTo, companyID)
|
||||
_, err = s.userStore.GetUserByEmailPhone(ctx, sentTo, "", companyID)
|
||||
case domain.OtpMediumSms:
|
||||
_, err = s.userStore.GetUserByPhone(ctx, sentTo, companyID)
|
||||
_, err = s.userStore.GetUserByEmailPhone(ctx, "", sentTo, companyID)
|
||||
}
|
||||
|
||||
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
|
||||
return s.SendOtp(ctx, sentTo, domain.OtpRegister, medium, provider)
|
||||
}
|
||||
|
||||
func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterUserReq) (domain.User, error) { // normal
|
||||
// get otp
|
||||
|
||||
|
|
@ -59,18 +61,18 @@ func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterU
|
|||
return domain.User{}, err
|
||||
}
|
||||
userR := domain.User{
|
||||
FirstName: registerReq.FirstName,
|
||||
LastName: registerReq.LastName,
|
||||
Email: registerReq.Email,
|
||||
PhoneNumber: registerReq.PhoneNumber,
|
||||
Password: hashedPassword,
|
||||
Role: domain.RoleCustomer,
|
||||
EmailVerified: registerReq.OtpMedium == domain.OtpMediumEmail,
|
||||
PhoneVerified: registerReq.OtpMedium == domain.OtpMediumSms,
|
||||
CompanyID: registerReq.CompanyID,
|
||||
FirstName: registerReq.FirstName,
|
||||
LastName: registerReq.LastName,
|
||||
Email: registerReq.Email,
|
||||
PhoneNumber: registerReq.PhoneNumber,
|
||||
Password: hashedPassword,
|
||||
Role: domain.RoleStudent,
|
||||
EmailVerified: registerReq.OtpMedium == domain.OtpMediumEmail,
|
||||
PhoneVerified: registerReq.OtpMedium == domain.OtpMediumSms,
|
||||
OrganizationID: registerReq.OrganizationID,
|
||||
}
|
||||
// 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 {
|
||||
return domain.User{}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ func (s *Service) SendResetCode(ctx context.Context, medium domain.OtpMedium, se
|
|||
// check if user exists
|
||||
switch medium {
|
||||
case domain.OtpMediumEmail:
|
||||
_, err = s.userStore.GetUserByEmail(ctx, sentTo, companyID)
|
||||
_, err = s.userStore.GetUserByEmailPhone(ctx, sentTo, "", companyID)
|
||||
case domain.OtpMediumSms:
|
||||
_, err = s.userStore.GetUserByPhone(ctx, sentTo, companyID)
|
||||
_, err = s.userStore.GetUserByEmailPhone(ctx, "", sentTo, companyID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -51,13 +51,13 @@ func (s *Service) ResetPassword(ctx context.Context, resetReq domain.ResetPasswo
|
|||
return domain.ErrInvalidOtp
|
||||
}
|
||||
// hash password
|
||||
hashedPassword, err := hashPassword(resetReq.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// hashedPassword, err := hashPassword(resetReq.Password)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,21 +5,34 @@ import (
|
|||
"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
|
||||
return s.userStore.SearchUserByNameOrPhone(ctx, searchString, role, companyID)
|
||||
|
||||
}
|
||||
func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
|
||||
// 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 {
|
||||
// update user
|
||||
return s.userStore.UpdateUserCompany(ctx, id, companyID)
|
||||
}
|
||||
// func (s *Service) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error {
|
||||
// // update user
|
||||
// return s.userStore.UpdateUserCompany(ctx, id, companyID)
|
||||
// }
|
||||
|
||||
func (s *Service) UpdateUserSuspend(ctx context.Context, id int64, status bool) error {
|
||||
// update user
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import (
|
|||
"Yimaru-Backend/internal/config"
|
||||
"Yimaru-Backend/internal/services/arifpay"
|
||||
"Yimaru-Backend/internal/services/authentication"
|
||||
issuereporting "Yimaru-Backend/internal/services/issue_reporting"
|
||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||
"Yimaru-Backend/internal/services/recommendation"
|
||||
referralservice "Yimaru-Backend/internal/services/referal"
|
||||
|
||||
"Yimaru-Backend/internal/services/settings"
|
||||
"Yimaru-Backend/internal/services/transaction"
|
||||
"Yimaru-Backend/internal/services/user"
|
||||
|
|
@ -23,60 +24,36 @@ import (
|
|||
)
|
||||
|
||||
type App struct {
|
||||
// directDepositSvc *directdeposit.Service
|
||||
// telebirrSvc *telebirr.TelebirrService
|
||||
arifpaySvc *arifpay.ArifpayService
|
||||
// santimpaySvc *santimpay.SantimPayService
|
||||
// issueReportingSvc *issuereporting.Service
|
||||
// instSvc *institutions.Service
|
||||
// currSvc *currency.Service
|
||||
arifpaySvc *arifpay.ArifpayService
|
||||
issueReportingSvc *issuereporting.Service
|
||||
fiber *fiber.App
|
||||
recommendationSvc recommendation.RecommendationService
|
||||
cfg *config.Config
|
||||
logger *slog.Logger
|
||||
NotidicationStore *notificationservice.Service
|
||||
referralSvc *referralservice.Service
|
||||
// raffleSvc *raffle.Service
|
||||
// bonusSvc *bonus.Service
|
||||
port int
|
||||
settingSvc *settings.Service
|
||||
authSvc *authentication.Service
|
||||
userSvc *user.Service
|
||||
// chapaSvc *chapa.Service
|
||||
transactionSvc *transaction.Service
|
||||
// branchSvc *branch.Service
|
||||
// companySvc *company.Service
|
||||
validator *customvalidator.CustomValidator
|
||||
JwtConfig jwtutil.JwtConfig
|
||||
Logger *slog.Logger
|
||||
// statSvc *stats.Service
|
||||
mongoLoggerSvc *zap.Logger
|
||||
port int
|
||||
settingSvc *settings.Service
|
||||
authSvc *authentication.Service
|
||||
userSvc *user.Service
|
||||
transactionSvc *transaction.Service
|
||||
validator *customvalidator.CustomValidator
|
||||
JwtConfig jwtutil.JwtConfig
|
||||
Logger *slog.Logger
|
||||
mongoLoggerSvc *zap.Logger
|
||||
}
|
||||
|
||||
func NewApp(
|
||||
// directDepositSvc *directdeposit.Service,
|
||||
// telebirrSvc *telebirr.TelebirrService,
|
||||
arifpaySvc *arifpay.ArifpayService,
|
||||
// santimpaySvc *santimpay.SantimPayService,
|
||||
// issueReportingSvc *issuereporting.Service,
|
||||
// instSvc *institutions.Service,
|
||||
// currSvc *currency.Service,
|
||||
issueReportingSvc *issuereporting.Service,
|
||||
port int, validator *customvalidator.CustomValidator,
|
||||
settingSvc *settings.Service,
|
||||
authSvc *authentication.Service,
|
||||
logger *slog.Logger,
|
||||
JwtConfig jwtutil.JwtConfig,
|
||||
userSvc *user.Service,
|
||||
// chapaSvc *chapa.Service,
|
||||
transactionSvc *transaction.Service,
|
||||
// branchSvc *branch.Service,
|
||||
// companySvc *company.Service,
|
||||
notidicationStore *notificationservice.Service,
|
||||
referralSvc *referralservice.Service,
|
||||
// raffleSvc *raffle.Service,
|
||||
// bonusSvc *bonus.Service,
|
||||
recommendationSvc recommendation.RecommendationService,
|
||||
// statSvc *stats.Service,
|
||||
cfg *config.Config,
|
||||
mongoLoggerSvc *zap.Logger,
|
||||
) *App {
|
||||
|
|
@ -97,35 +74,22 @@ func NewApp(
|
|||
app.Static("/static", "./static")
|
||||
|
||||
s := &App{
|
||||
// directDepositSvc: directDepositSvc,
|
||||
// telebirrSvc: telebirrSvc,
|
||||
arifpaySvc: arifpaySvc,
|
||||
// santimpaySvc: santimpaySvc,
|
||||
arifpaySvc: arifpaySvc,
|
||||
// issueReportingSvc: issueReportingSvc,
|
||||
// instSvc: instSvc,
|
||||
// currSvc: currSvc,
|
||||
fiber: app,
|
||||
port: port,
|
||||
settingSvc: settingSvc,
|
||||
authSvc: authSvc,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
JwtConfig: JwtConfig,
|
||||
userSvc: userSvc,
|
||||
// ticketSvc: ticketSvc,
|
||||
// chapaSvc: chapaSvc,
|
||||
transactionSvc: transactionSvc,
|
||||
// branchSvc: branchSvc,
|
||||
// companySvc: companySvc,
|
||||
fiber: app,
|
||||
port: port,
|
||||
settingSvc: settingSvc,
|
||||
authSvc: authSvc,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
JwtConfig: JwtConfig,
|
||||
userSvc: userSvc,
|
||||
transactionSvc: transactionSvc,
|
||||
NotidicationStore: notidicationStore,
|
||||
referralSvc: referralSvc,
|
||||
// raffleSvc: raffleSvc,
|
||||
// bonusSvc: bonusSvc,
|
||||
Logger: logger,
|
||||
recommendationSvc: recommendationSvc,
|
||||
// statSvc: statSvc,
|
||||
cfg: cfg,
|
||||
mongoLoggerSvc: mongoLoggerSvc,
|
||||
cfg: cfg,
|
||||
mongoLoggerSvc: mongoLoggerSvc,
|
||||
}
|
||||
|
||||
s.initAppRoutes()
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ import (
|
|||
)
|
||||
|
||||
type CreateAdminReq 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"`
|
||||
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
|
||||
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"`
|
||||
OrganizationID *int64 `json:"company_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
// CreateAdmin godoc
|
||||
|
|
@ -34,7 +34,7 @@ type CreateAdminReq struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/admin [post]
|
||||
func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
||||
var companyID domain.ValidInt64
|
||||
var OrganizationID domain.ValidInt64
|
||||
var req CreateAdminReq
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if req.CompanyID == nil {
|
||||
companyID = domain.ValidInt64{
|
||||
if req.OrganizationID == nil {
|
||||
OrganizationID = domain.ValidInt64{
|
||||
Value: 0,
|
||||
Valid: false,
|
||||
}
|
||||
} else {
|
||||
// _, err := h.companySvc.GetCompanyByID(c.Context(), *req.CompanyID)
|
||||
// _, err := h.companySvc.GetCompanyByID(c.Context(), *req.OrganizationID)
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
||||
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Int64("company_id", *req.CompanyID),
|
||||
// zap.Int64("company_id", *req.OrganizationID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
||||
// }
|
||||
companyID = domain.ValidInt64{
|
||||
Value: *req.CompanyID,
|
||||
OrganizationID = domain.ValidInt64{
|
||||
Value: *req.OrganizationID,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
user := domain.CreateUserReq{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Role: string(domain.RoleAdmin),
|
||||
CompanyID: companyID,
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Role: string(domain.RoleAdmin),
|
||||
OrganizationID: OrganizationID,
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
// if req.CompanyID != nil {
|
||||
// if req.OrganizationID != nil {
|
||||
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
|
||||
// ID: *req.CompanyID,
|
||||
// ID: *req.OrganizationID,
|
||||
// AdminID: domain.ValidInt64{
|
||||
// Value: newUser.ID,
|
||||
// Valid: true,
|
||||
|
|
@ -114,7 +114,7 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
|
|||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("failed to update company with new admin",
|
||||
// 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.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
|
|
@ -200,7 +200,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
|
|||
companyFilter := int64(c.QueryInt("company_id"))
|
||||
filter := domain.UserFilter{
|
||||
Role: string(domain.RoleAdmin),
|
||||
CompanyID: domain.ValidInt64{
|
||||
OrganizationID: domain.ValidInt64{
|
||||
Value: companyFilter,
|
||||
Valid: companyFilter != 0,
|
||||
},
|
||||
|
|
@ -362,10 +362,10 @@ func (h *Handler) GetAdminByID(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
type updateAdminReq struct {
|
||||
FirstName string `json:"first_name" example:"John"`
|
||||
LastName string `json:"last_name" example:"Doe"`
|
||||
Suspended bool `json:"suspended" example:"false"`
|
||||
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
|
||||
FirstName string `json:"first_name" example:"John"`
|
||||
LastName string `json:"last_name" example:"Doe"`
|
||||
Suspended bool `json:"suspended" example:"false"`
|
||||
OrganizationID *int64 `json:"company_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
// UpdateAdmin godoc
|
||||
|
|
@ -417,16 +417,16 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
|
|||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Admin ID")
|
||||
}
|
||||
|
||||
var companyID domain.ValidInt64
|
||||
if req.CompanyID != nil {
|
||||
companyID = domain.ValidInt64{
|
||||
Value: *req.CompanyID,
|
||||
var OrganizationID domain.ValidInt64
|
||||
if req.OrganizationID != nil {
|
||||
OrganizationID = domain.ValidInt64{
|
||||
Value: *req.OrganizationID,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
|
||||
UserId: AdminID,
|
||||
UserID: AdminID,
|
||||
FirstName: domain.ValidString{
|
||||
Value: req.FirstName,
|
||||
Valid: req.FirstName != "",
|
||||
|
|
@ -439,7 +439,7 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
|
|||
Value: req.Suspended,
|
||||
Valid: true,
|
||||
},
|
||||
CompanyID: companyID,
|
||||
OrganizationID: OrganizationID,
|
||||
})
|
||||
if err != nil {
|
||||
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())
|
||||
}
|
||||
|
||||
// if req.CompanyID != nil {
|
||||
// if req.OrganizationID != nil {
|
||||
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
|
||||
// ID: *req.CompanyID,
|
||||
// ID: *req.OrganizationID,
|
||||
// AdminID: domain.ValidInt64{
|
||||
// Value: AdminID,
|
||||
// Valid: true,
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ type loginCustomerRes struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/customer-login [post]
|
||||
func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
if !companyID.Valid {
|
||||
OrganizationID := c.Locals("company_id").(domain.ValidInt64)
|
||||
if !OrganizationID.Valid {
|
||||
h.BadRequestLogger().Error("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)
|
||||
}
|
||||
|
||||
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 {
|
||||
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",
|
||||
zap.Int("status_code", fiber.StatusForbidden),
|
||||
zap.String("role", string(successRes.Role)),
|
||||
|
|
@ -167,8 +167,8 @@ type LoginAdminRes struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/admin-login [post]
|
||||
func (h *Handler) LoginAdmin(c *fiber.Ctx) error {
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
if !companyID.Valid {
|
||||
OrganizationID := c.Locals("company_id").(domain.ValidInt64)
|
||||
if !OrganizationID.Valid {
|
||||
h.BadRequestLogger().Error("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)
|
||||
}
|
||||
|
||||
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 {
|
||||
switch {
|
||||
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",
|
||||
zap.Int("status_code", fiber.StatusForbidden),
|
||||
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())
|
||||
}
|
||||
|
||||
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 {
|
||||
h.mongoLoggerSvc.Error("Failed to create new access token",
|
||||
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
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// @Summary Get supported currencies
|
||||
// @Description Returns list of supported currencies
|
||||
// @Tags Multi-Currency
|
||||
// @Produce json
|
||||
// @Success 200 {object} domain.Response{data=[]domain.Currency}
|
||||
// @Router /api/v1/currencies [get]
|
||||
func (h *Handler) GetSupportedCurrencies(c *fiber.Ctx) error {
|
||||
currencies, err := h.currSvc.GetSupportedCurrencies(c.Context())
|
||||
if err != nil {
|
||||
return domain.UnExpectedErrorResponse(c)
|
||||
}
|
||||
// func (h *Handler) GetSupportedCurrencies(c *fiber.Ctx) error {
|
||||
// currencies, err := h.currSvc.GetSupportedCurrencies(c.Context())
|
||||
// if err != nil {
|
||||
// return domain.UnExpectedErrorResponse(c)
|
||||
// }
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
Success: true,
|
||||
Message: "Supported currencies retrieved successfully",
|
||||
Data: currencies,
|
||||
StatusCode: fiber.StatusOK,
|
||||
})
|
||||
}
|
||||
// return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
// Success: true,
|
||||
// Message: "Supported currencies retrieved successfully",
|
||||
// Data: currencies,
|
||||
// StatusCode: fiber.StatusOK,
|
||||
// })
|
||||
// }
|
||||
|
||||
// @Summary Convert currency
|
||||
// @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}
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/currencies/convert [get]
|
||||
func (h *Handler) ConvertCurrency(c *fiber.Ctx) error {
|
||||
from := domain.IntCurrency(c.Query("from"))
|
||||
to := domain.IntCurrency(c.Query("to"))
|
||||
amount := c.QueryFloat("amount", 0)
|
||||
// if err != nil {
|
||||
// return domain.BadRequestResponse(c)
|
||||
// }
|
||||
// func (h *Handler) ConvertCurrency(c *fiber.Ctx) error {
|
||||
// from := domain.IntCurrency(c.Query("from"))
|
||||
// to := domain.IntCurrency(c.Query("to"))
|
||||
// amount := c.QueryFloat("amount", 0)
|
||||
// // if err != nil {
|
||||
// // return domain.BadRequestResponse(c)
|
||||
// // }
|
||||
|
||||
converted, err := h.currSvc.Convert(c.Context(), amount, from, to)
|
||||
if err != nil {
|
||||
return domain.UnExpectedErrorResponse(c)
|
||||
}
|
||||
// converted, err := h.currSvc.Convert(c.Context(), amount, from, to)
|
||||
// if err != nil {
|
||||
// return domain.UnExpectedErrorResponse(c)
|
||||
// }
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
Success: true,
|
||||
Message: "Currency converted successfully",
|
||||
Data: converted,
|
||||
StatusCode: fiber.StatusOK,
|
||||
})
|
||||
}
|
||||
// return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
// Success: true,
|
||||
// Message: "Currency converted successfully",
|
||||
// Data: converted,
|
||||
// StatusCode: fiber.StatusOK,
|
||||
// })
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -4,10 +4,9 @@ import (
|
|||
"Yimaru-Backend/internal/config"
|
||||
"Yimaru-Backend/internal/services/arifpay"
|
||||
"Yimaru-Backend/internal/services/authentication"
|
||||
"Yimaru-Backend/internal/services/currency"
|
||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||
"Yimaru-Backend/internal/services/recommendation"
|
||||
referralservice "Yimaru-Backend/internal/services/referal"
|
||||
// referralservice "Yimaru-Backend/internal/services/referal"
|
||||
|
||||
"Yimaru-Backend/internal/services/settings"
|
||||
|
||||
|
|
@ -22,13 +21,10 @@ import (
|
|||
|
||||
type Handler struct {
|
||||
arifpaySvc *arifpay.ArifpayService
|
||||
// instSvc *institutions.Service
|
||||
currSvc *currency.Service
|
||||
logger *slog.Logger
|
||||
settingSvc *settings.Service
|
||||
notificationSvc *notificationservice.Service
|
||||
userSvc *user.Service
|
||||
referralSvc *referralservice.Service
|
||||
transactionSvc *transaction.Service
|
||||
recommendationSvc recommendation.RecommendationService
|
||||
authSvc *authentication.Service
|
||||
|
|
@ -39,23 +35,14 @@ type Handler struct {
|
|||
}
|
||||
|
||||
func New(
|
||||
// directDepositSvc *directdeposit.Service,
|
||||
// telebirrSvc *telebirr.TelebirrService,
|
||||
arifpaySvc *arifpay.ArifpayService,
|
||||
// santimpaySvc *santimpay.SantimPayService,
|
||||
// instSvc *institutions.Service,
|
||||
currSvc *currency.Service,
|
||||
logger *slog.Logger,
|
||||
settingSvc *settings.Service,
|
||||
notificationSvc *notificationservice.Service,
|
||||
validator *customvalidator.CustomValidator,
|
||||
// reportSvc report.ReportService,
|
||||
// chapaSvc *chapa.Service,
|
||||
referralSvc *referralservice.Service,
|
||||
recommendationSvc recommendation.RecommendationService,
|
||||
userSvc *user.Service,
|
||||
transactionSvc *transaction.Service,
|
||||
// ticketSvc *ticket.Service,
|
||||
authSvc *authentication.Service,
|
||||
jwtConfig jwtutil.JwtConfig,
|
||||
cfg *config.Config,
|
||||
|
|
@ -63,12 +50,9 @@ func New(
|
|||
) *Handler {
|
||||
return &Handler{
|
||||
arifpaySvc: arifpaySvc,
|
||||
instSvc: instSvc,
|
||||
currSvc: currSvc,
|
||||
logger: logger,
|
||||
settingSvc: settingSvc,
|
||||
notificationSvc: notificationSvc,
|
||||
referralSvc: referralSvc,
|
||||
validator: validator,
|
||||
userSvc: userSvc,
|
||||
transactionSvc: transactionSvc,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// @Summary Create a new bank
|
||||
// @Tags Institutions - Banks
|
||||
// @Accept json
|
||||
|
|
@ -16,18 +8,18 @@ import (
|
|||
// @Success 201 {object} domain.Bank
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/banks [post]
|
||||
func (h *Handler) CreateBank(c *fiber.Ctx) error {
|
||||
var bank domain.Bank
|
||||
if err := c.BodyParser(&bank); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||
}
|
||||
// func (h *Handler) CreateBank(c *fiber.Ctx) error {
|
||||
// var bank domain.Bank
|
||||
// if err := c.BodyParser(&bank); err != nil {
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||
// }
|
||||
|
||||
err := h.instSvc.Create(c.Context(), &bank)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.Status(fiber.StatusCreated).JSON(bank)
|
||||
}
|
||||
// // err := h.instSvc.Create(c.Context(), &bank)
|
||||
// // if err != nil {
|
||||
// // return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
// // }
|
||||
// return c.Status(fiber.StatusCreated).JSON(bank)
|
||||
// }
|
||||
|
||||
// @Summary Get a bank by ID
|
||||
// @Tags Institutions - Banks
|
||||
|
|
@ -38,19 +30,19 @@ func (h *Handler) CreateBank(c *fiber.Ctx) error {
|
|||
// @Failure 404 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/banks/{id} [get]
|
||||
func (h *Handler) GetBankByID(c *fiber.Ctx) error {
|
||||
id, err := c.ParamsInt("id")
|
||||
if err != nil || id <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||
}
|
||||
// func (h *Handler) GetBankByID(c *fiber.Ctx) error {
|
||||
// id, err := c.ParamsInt("id")
|
||||
// if err != nil || id <= 0 {
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||
// }
|
||||
|
||||
bank, err := h.instSvc.GetByID(c.Context(), int64(id))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "bank not found"})
|
||||
}
|
||||
// // bank, err := h.instSvc.GetByID(c.Context(), int64(id))
|
||||
// // if err != nil {
|
||||
// // return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "bank not found"})
|
||||
// // }
|
||||
|
||||
return c.JSON(bank)
|
||||
}
|
||||
// return c.JSON(bank)
|
||||
// }
|
||||
|
||||
// @Summary Update a bank
|
||||
// @Tags Institutions - Banks
|
||||
|
|
@ -63,42 +55,42 @@ func (h *Handler) GetBankByID(c *fiber.Ctx) error {
|
|||
// @Failure 404 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/banks/{id} [put]
|
||||
func (h *Handler) UpdateBank(c *fiber.Ctx) error {
|
||||
id, err := c.ParamsInt("id")
|
||||
if err != nil || id <= 0 {
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||
Message: "Failed to update bank",
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// func (h *Handler) UpdateBank(c *fiber.Ctx) error {
|
||||
// id, err := c.ParamsInt("id")
|
||||
// if err != nil || id <= 0 {
|
||||
// // return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||
// Message: "Failed to update bank",
|
||||
// Error: err.Error(),
|
||||
// })
|
||||
// }
|
||||
|
||||
var bank domain.Bank
|
||||
if err := c.BodyParser(&bank); err != nil {
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||
Message: "Failed to update bank",
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
bank.ID = id
|
||||
// var bank domain.Bank
|
||||
// if err := c.BodyParser(&bank); err != nil {
|
||||
// // return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||
// Message: "Failed to update bank",
|
||||
// Error: err.Error(),
|
||||
// })
|
||||
// }
|
||||
// bank.ID = id
|
||||
|
||||
err = h.instSvc.Update(c.Context(), &bank)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||
Message: "Failed to update bank",
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// err = h.instSvc.Update(c.Context(), &bank)
|
||||
// if err != nil {
|
||||
// return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||
// Message: "Failed to update bank",
|
||||
// Error: err.Error(),
|
||||
// })
|
||||
// }
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
Message: "Bank updated successfully",
|
||||
StatusCode: fiber.StatusOK,
|
||||
Success: true,
|
||||
Data: bank,
|
||||
})
|
||||
// return c.JSON(bank)
|
||||
}
|
||||
// return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
// Message: "Bank updated successfully",
|
||||
// StatusCode: fiber.StatusOK,
|
||||
// Success: true,
|
||||
// Data: bank,
|
||||
// })
|
||||
// // return c.JSON(bank)
|
||||
// }
|
||||
|
||||
// @Summary Delete a bank
|
||||
// @Tags Institutions - Banks
|
||||
|
|
@ -109,19 +101,19 @@ func (h *Handler) UpdateBank(c *fiber.Ctx) error {
|
|||
// @Failure 404 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/banks/{id} [delete]
|
||||
func (h *Handler) DeleteBank(c *fiber.Ctx) error {
|
||||
id, err := c.ParamsInt("id")
|
||||
if err != nil || id <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||
}
|
||||
// func (h *Handler) DeleteBank(c *fiber.Ctx) error {
|
||||
// id, err := c.ParamsInt("id")
|
||||
// if err != nil || id <= 0 {
|
||||
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid bank ID"})
|
||||
// }
|
||||
|
||||
err = h.instSvc.Delete(c.Context(), int64(id))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
// err = h.instSvc.Delete(c.Context(), int64(id))
|
||||
// if err != nil {
|
||||
// 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
|
||||
// @Tags Institutions - Banks
|
||||
|
|
@ -135,51 +127,51 @@ func (h *Handler) DeleteBank(c *fiber.Ctx) error {
|
|||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/banks [get]
|
||||
func (h *Handler) ListBanks(c *fiber.Ctx) error {
|
||||
// Parse query parameters
|
||||
countryID, _ := strconv.Atoi(c.Query("country_id"))
|
||||
var countryIDPtr *int
|
||||
if c.Query("country_id") != "" {
|
||||
countryIDPtr = &countryID
|
||||
}
|
||||
// func (h *Handler) ListBanks(c *fiber.Ctx) error {
|
||||
// // Parse query parameters
|
||||
// countryID, _ := strconv.Atoi(c.Query("country_id"))
|
||||
// var countryIDPtr *int
|
||||
// if c.Query("country_id") != "" {
|
||||
// countryIDPtr = &countryID
|
||||
// }
|
||||
|
||||
isActive, _ := strconv.ParseBool(c.Query("is_active"))
|
||||
var isActivePtr *bool
|
||||
if c.Query("is_active") != "" {
|
||||
isActivePtr = &isActive
|
||||
}
|
||||
// isActive, _ := strconv.ParseBool(c.Query("is_active"))
|
||||
// var isActivePtr *bool
|
||||
// if c.Query("is_active") != "" {
|
||||
// isActivePtr = &isActive
|
||||
// }
|
||||
|
||||
var searchTermPtr *string
|
||||
if searchTerm := c.Query("search"); searchTerm != "" {
|
||||
searchTermPtr = &searchTerm
|
||||
}
|
||||
// var searchTermPtr *string
|
||||
// if searchTerm := c.Query("search"); searchTerm != "" {
|
||||
// searchTermPtr = &searchTerm
|
||||
// }
|
||||
|
||||
page, _ := strconv.Atoi(c.Query("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.Query("page_size", "50"))
|
||||
// page, _ := strconv.Atoi(c.Query("page", "1"))
|
||||
// pageSize, _ := strconv.Atoi(c.Query("page_size", "50"))
|
||||
|
||||
banks, pagination, err := h.instSvc.List(
|
||||
c.Context(),
|
||||
countryIDPtr,
|
||||
isActivePtr,
|
||||
searchTermPtr,
|
||||
page,
|
||||
pageSize,
|
||||
)
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("failed to list banks",
|
||||
zap.Error(err),
|
||||
zap.Any("query_params", c.Queries()),
|
||||
)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||
Message: "Failed to retrieve banks",
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// banks, pagination, err := h.instSvc.List(
|
||||
// c.Context(),
|
||||
// countryIDPtr,
|
||||
// isActivePtr,
|
||||
// searchTermPtr,
|
||||
// page,
|
||||
// pageSize,
|
||||
// )
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("failed to list banks",
|
||||
// zap.Error(err),
|
||||
// zap.Any("query_params", c.Queries()),
|
||||
// )
|
||||
// return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||
// Message: "Failed to retrieve banks",
|
||||
// Error: err.Error(),
|
||||
// })
|
||||
// }
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(domain.InstResponse{
|
||||
Message: "Banks retrieved successfully",
|
||||
Status: "success",
|
||||
Data: banks,
|
||||
Pagination: pagination,
|
||||
})
|
||||
}
|
||||
// return c.Status(fiber.StatusOK).JSON(domain.InstResponse{
|
||||
// Message: "Banks retrieved successfully",
|
||||
// Status: "success",
|
||||
// Data: banks,
|
||||
// Pagination: pagination,
|
||||
// })
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -2,15 +2,12 @@ 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 CreateManagerReq struct {
|
||||
|
|
@ -34,75 +31,75 @@ type CreateManagerReq struct {
|
|||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @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
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("RegisterUser failed", "error", err)
|
||||
h.mongoLoggerSvc.Info("CreateManager failed to create manager",
|
||||
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 CreateManager",
|
||||
zap.Any("request", req),
|
||||
zap.Int("status_code", fiber.StatusBadRequest),
|
||||
zap.String("errMsg", errMsg),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
}
|
||||
// var req CreateManagerReq
|
||||
// if err := c.BodyParser(&req); err != nil {
|
||||
// h.logger.Error("RegisterUser failed", "error", err)
|
||||
// h.mongoLoggerSvc.Info("CreateManager failed to create manager",
|
||||
// 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 CreateManager",
|
||||
// zap.Any("request", req),
|
||||
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||
// zap.String("errMsg", errMsg),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
// }
|
||||
|
||||
var companyID domain.ValidInt64
|
||||
role := c.Locals("role").(domain.Role)
|
||||
if role == domain.RoleSuperAdmin {
|
||||
if req.CompanyID == nil {
|
||||
h.logger.Error("RegisterUser failed error: company id is required")
|
||||
h.mongoLoggerSvc.Info("RegisterUser failed error: company id is required",
|
||||
zap.Int("status_code", fiber.StatusBadRequest),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Company ID is required for super-admin")
|
||||
}
|
||||
companyID = domain.ValidInt64{
|
||||
Value: *req.CompanyID,
|
||||
Valid: true,
|
||||
}
|
||||
} else {
|
||||
companyID = c.Locals("company_id").(domain.ValidInt64)
|
||||
}
|
||||
// var companyID domain.ValidInt64
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
// if role == domain.RoleSuperAdmin {
|
||||
// if req.CompanyID == nil {
|
||||
// h.logger.Error("RegisterUser failed error: company id is required")
|
||||
// h.mongoLoggerSvc.Info("RegisterUser failed error: company id is required",
|
||||
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Company ID is required for super-admin")
|
||||
// }
|
||||
// companyID = domain.ValidInt64{
|
||||
// Value: *req.CompanyID,
|
||||
// Valid: true,
|
||||
// }
|
||||
// } else {
|
||||
// companyID = c.Locals("company_id").(domain.ValidInt64)
|
||||
// }
|
||||
|
||||
user := domain.CreateUserReq{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Role: string(domain.RoleBranchManager),
|
||||
CompanyID: companyID,
|
||||
}
|
||||
_, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("CreateManager failed to create manager",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create manager:"+err.Error())
|
||||
}
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Manager created successfully", nil, nil)
|
||||
// user := domain.CreateUserReq{
|
||||
// FirstName: req.FirstName,
|
||||
// LastName: req.LastName,
|
||||
// Email: req.Email,
|
||||
// PhoneNumber: req.PhoneNumber,
|
||||
// Password: req.Password,
|
||||
// Role: string(domain.RoleBranchManager),
|
||||
// OrganizationID: companyID,
|
||||
// }
|
||||
// _, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("CreateManager failed to create manager",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create manager:"+err.Error())
|
||||
// }
|
||||
// return response.WriteJSON(c, fiber.StatusOK, "Manager created successfully", nil, nil)
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
type ManagersRes struct {
|
||||
ID int64 `json:"id"`
|
||||
|
|
@ -133,141 +130,141 @@ type ManagersRes struct {
|
|||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/managers [get]
|
||||
func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
||||
role := c.Locals("role").(domain.Role)
|
||||
companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||
// func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
// companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||
|
||||
// Checking to make sure that admin user has a company id in the token
|
||||
if role != domain.RoleSuperAdmin && !companyId.Valid {
|
||||
h.mongoLoggerSvc.Error("Cannot get company ID from 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 from context")
|
||||
}
|
||||
// // Checking to make sure that admin user has a company id in the token
|
||||
// if role != domain.RoleSuperAdmin && !companyId.Valid {
|
||||
// h.mongoLoggerSvc.Error("Cannot get company ID from 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 from context")
|
||||
// }
|
||||
|
||||
searchQuery := c.Query("query")
|
||||
searchString := domain.ValidString{
|
||||
Value: searchQuery,
|
||||
Valid: searchQuery != "",
|
||||
}
|
||||
// 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("created_before", 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,
|
||||
}
|
||||
}
|
||||
// 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("created_before", 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,
|
||||
}
|
||||
}
|
||||
// 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.RoleBranchManager),
|
||||
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 get all filters",
|
||||
zap.Any("filter", filter),
|
||||
zap.Int("status_code", fiber.StatusBadRequest),
|
||||
zap.String("errMsg", errMsg),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
}
|
||||
managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||
if err != nil {
|
||||
h.logger.Error("GetAllManagers failed", "error", err)
|
||||
h.mongoLoggerSvc.Error("GetAllManagers failed to get all managers",
|
||||
zap.Any("filter", filter),
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Managers"+err.Error())
|
||||
}
|
||||
// filter := domain.UserFilter{
|
||||
// Role: string(domain.RoleBranchManager),
|
||||
// OrganizationID: 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 get all filters",
|
||||
// zap.Any("filter", filter),
|
||||
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||
// zap.String("errMsg", errMsg),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
// }
|
||||
// managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||
// if err != nil {
|
||||
// h.logger.Error("GetAllManagers failed", "error", err)
|
||||
// h.mongoLoggerSvc.Error("GetAllManagers failed to get all managers",
|
||||
// zap.Any("filter", filter),
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Managers"+err.Error())
|
||||
// }
|
||||
|
||||
var result []ManagersRes = make([]ManagersRes, len(managers))
|
||||
for index, manager := range managers {
|
||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), manager.ID)
|
||||
if err != nil {
|
||||
if err == authentication.ErrRefreshTokenNotFound {
|
||||
lastLogin = &manager.CreatedAt
|
||||
} else {
|
||||
h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||
zap.Int64("userID", manager.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[index] = ManagersRes{
|
||||
ID: manager.ID,
|
||||
FirstName: manager.FirstName,
|
||||
LastName: manager.LastName,
|
||||
Email: manager.Email,
|
||||
PhoneNumber: manager.PhoneNumber,
|
||||
Role: manager.Role,
|
||||
EmailVerified: manager.EmailVerified,
|
||||
PhoneVerified: manager.PhoneVerified,
|
||||
CreatedAt: manager.CreatedAt,
|
||||
UpdatedAt: manager.UpdatedAt,
|
||||
SuspendedAt: manager.SuspendedAt,
|
||||
Suspended: manager.Suspended,
|
||||
LastLogin: *lastLogin,
|
||||
}
|
||||
}
|
||||
// var result []ManagersRes = make([]ManagersRes, len(managers))
|
||||
// for index, manager := range managers {
|
||||
// lastLogin, err := h.authSvc.GetLastLogin(c.Context(), manager.ID)
|
||||
// if err != nil {
|
||||
// if err == authentication.ErrRefreshTokenNotFound {
|
||||
// lastLogin = &manager.CreatedAt
|
||||
// } else {
|
||||
// h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||
// zap.Int64("userID", manager.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[index] = ManagersRes{
|
||||
// ID: manager.ID,
|
||||
// FirstName: manager.FirstName,
|
||||
// LastName: manager.LastName,
|
||||
// Email: manager.Email,
|
||||
// PhoneNumber: manager.PhoneNumber,
|
||||
// Role: manager.Role,
|
||||
// EmailVerified: manager.EmailVerified,
|
||||
// PhoneVerified: manager.PhoneVerified,
|
||||
// CreatedAt: manager.CreatedAt,
|
||||
// UpdatedAt: manager.UpdatedAt,
|
||||
// SuspendedAt: manager.SuspendedAt,
|
||||
// Suspended: manager.Suspended,
|
||||
// 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
|
||||
// @Summary Get manager by id
|
||||
|
|
@ -281,103 +278,103 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
|||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/managers/{id} [get]
|
||||
func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
|
||||
role := c.Locals("role").(domain.Role)
|
||||
companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||
requestUserID := c.Locals("user_id").(int64)
|
||||
// func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
// companyId := c.Locals("company_id").(domain.ValidInt64)
|
||||
// requestUserID := c.Locals("user_id").(int64)
|
||||
|
||||
// Only Super Admin / Admin / Branch Manager can view this route
|
||||
if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager {
|
||||
h.mongoLoggerSvc.Warn("Attempt to access from unauthorized role",
|
||||
zap.Int64("userID", requestUserID),
|
||||
zap.String("role", string(role)),
|
||||
zap.Int("status_code", fiber.StatusForbidden),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusForbidden, "This role cannot view this route")
|
||||
}
|
||||
// // Only Super Admin / Admin / Branch Manager can view this route
|
||||
// if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager {
|
||||
// h.mongoLoggerSvc.Warn("Attempt to access from unauthorized role",
|
||||
// zap.Int64("userID", requestUserID),
|
||||
// zap.String("role", string(role)),
|
||||
// zap.Int("status_code", fiber.StatusForbidden),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusForbidden, "This role cannot view this route")
|
||||
// }
|
||||
|
||||
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")
|
||||
}
|
||||
// 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")
|
||||
// }
|
||||
|
||||
userIDstr := c.Params("id")
|
||||
userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid managers ID")
|
||||
}
|
||||
// userIDstr := c.Params("id")
|
||||
// userID, err := strconv.ParseInt(userIDstr, 10, 64)
|
||||
// if err != nil {
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid managers ID")
|
||||
// }
|
||||
|
||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to get manager by id",
|
||||
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 get managers:"+err.Error())
|
||||
}
|
||||
// user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to get manager by id",
|
||||
// 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 get managers:"+err.Error())
|
||||
// }
|
||||
|
||||
// A Branch Manager can only fetch his own branch info
|
||||
if role == domain.RoleBranchManager && user.ID != requestUserID {
|
||||
h.mongoLoggerSvc.Warn("Attempt to access another branch manager info",
|
||||
zap.String("userID", userIDstr),
|
||||
zap.Int("status_code", fiber.StatusForbidden),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusForbidden, "User Access Not Allowed")
|
||||
}
|
||||
// // A Branch Manager can only fetch his own branch info
|
||||
// if role == domain.RoleBranchManager && user.ID != requestUserID {
|
||||
// h.mongoLoggerSvc.Warn("Attempt to access another branch manager info",
|
||||
// zap.String("userID", userIDstr),
|
||||
// zap.Int("status_code", fiber.StatusForbidden),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusForbidden, "User Access Not Allowed")
|
||||
// }
|
||||
|
||||
// Check that only admin from company can view this route
|
||||
if role != domain.RoleSuperAdmin && user.CompanyID.Value != companyId.Value {
|
||||
h.mongoLoggerSvc.Warn("Attempt to access info from another company",
|
||||
zap.String("userID", userIDstr),
|
||||
zap.Int("status_code", fiber.StatusForbidden),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusForbidden, "Cannot access another company information")
|
||||
}
|
||||
// // Check that only admin from company can view this route
|
||||
// if role != domain.RoleSuperAdmin && user.OrganizationID.Value != companyId.Value {
|
||||
// h.mongoLoggerSvc.Warn("Attempt to access info from another company",
|
||||
// zap.String("userID", userIDstr),
|
||||
// zap.Int("status_code", fiber.StatusForbidden),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusForbidden, "Cannot access another company information")
|
||||
// }
|
||||
|
||||
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", userID),
|
||||
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, 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", userID),
|
||||
// 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
|
||||
}
|
||||
// lastLogin = &user.CreatedAt
|
||||
// }
|
||||
|
||||
res := ManagersRes{
|
||||
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,
|
||||
}
|
||||
// res := ManagersRes{
|
||||
// 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,
|
||||
// }
|
||||
|
||||
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 {
|
||||
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{
|
||||
UserId: ManagersId,
|
||||
UserID: ManagersId,
|
||||
FirstName: domain.ValidString{
|
||||
Value: req.FirstName,
|
||||
Valid: req.FirstName != "",
|
||||
|
|
@ -446,7 +443,7 @@ func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
|
|||
Value: req.Suspended,
|
||||
Valid: true,
|
||||
},
|
||||
CompanyID: companyID,
|
||||
OrganizationID: companyID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@ import (
|
|||
"Yimaru-Backend/internal/web_server/ws"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
|
@ -131,45 +129,45 @@ func (h *Handler) ConnectSocket(c *fiber.Ctx) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
||||
type Request struct {
|
||||
NotificationIDs []string `json:"notification_ids" validate:"required"`
|
||||
}
|
||||
// func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
||||
// type Request struct {
|
||||
// NotificationIDs []string `json:"notification_ids" validate:"required"`
|
||||
// }
|
||||
|
||||
var req Request
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.mongoLoggerSvc.Info("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")
|
||||
}
|
||||
// var req Request
|
||||
// if err := c.BodyParser(&req); err != nil {
|
||||
// h.mongoLoggerSvc.Info("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")
|
||||
// }
|
||||
|
||||
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 in context")
|
||||
}
|
||||
// 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 in context")
|
||||
// }
|
||||
|
||||
fmt.Printf("Notification IDs: %v \n", req.NotificationIDs)
|
||||
if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationIDs, userID); err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to mark notifications as read",
|
||||
zap.String("notificationID", strings.Join(req.NotificationIDs, ",")),
|
||||
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 update notification status:", err.Error())
|
||||
}
|
||||
// fmt.Printf("Notification IDs: %v \n", req.NotificationIDs)
|
||||
// if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationIDs, userID); err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to mark notifications as read",
|
||||
// zap.String("notificationID", strings.Join(req.NotificationIDs, ",")),
|
||||
// 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 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 {
|
||||
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) {
|
||||
return h.notificationSvc.ListRecipientIDs(ctx, receiver)
|
||||
}
|
||||
// func (h *Handler) GetAllRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||
// return h.notificationSvc.ListRecipientIDs(ctx, receiver)
|
||||
// }
|
||||
|
||||
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")
|
||||
}
|
||||
referralCode, err := h.referralSvc.CreateReferralCode(c.Context(), userID, companyID.Value)
|
||||
// referralCode, err := h.referralSvc.CreateReferralCode(c.Context(), userID, companyID.Value)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to create referral",
|
||||
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 create referral")
|
||||
}
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to create referral",
|
||||
// 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 create 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 {
|
||||
|
|
@ -72,7 +72,7 @@ func (h *Handler) GetReferralCode(c *fiber.Ctx) error {
|
|||
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",
|
||||
zap.Int64("userID", userID),
|
||||
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")
|
||||
}
|
||||
|
||||
referrals, err := h.referralSvc.GetReferralCodesByUser(c.Context(), user.ID)
|
||||
// referrals, err := h.referralSvc.GetReferralCodesByUser(c.Context(), user.ID)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to get user referrals",
|
||||
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 referral codes")
|
||||
}
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to get user referrals",
|
||||
// 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 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
|
||||
// // @Summary Update referral settings
|
||||
// // @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)
|
||||
}
|
||||
|
||||
func (h *Handler) SaveCompanySettingList(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")
|
||||
}
|
||||
// func (h *Handler) SaveCompanySettingList(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 domain.SaveSettingListReq
|
||||
// var req domain.SaveSettingListReq
|
||||
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.mongoLoggerSvc.Info("Failed to parse SaveSettingListReq",
|
||||
zap.Int("status_code", fiber.StatusBadRequest),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
||||
}
|
||||
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 SaveSettingListReq",
|
||||
zap.Int("status_code", fiber.StatusBadRequest),
|
||||
zap.String("errMsg", errMsg),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
}
|
||||
settingList := domain.ConvertSaveSettingListReq(req)
|
||||
err := h.settingSvc.InsertCompanySettingList(c.Context(), settingList, companyID.Value)
|
||||
// if err := c.BodyParser(&req); err != nil {
|
||||
// h.mongoLoggerSvc.Info("Failed to parse SaveSettingListReq",
|
||||
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
||||
// }
|
||||
// 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 SaveSettingListReq",
|
||||
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||
// zap.String("errMsg", errMsg),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
// }
|
||||
// // settingList := domain.ConvertSaveSettingListReq(req)
|
||||
// // err := h.settingSvc.InsertCompanySettingList(c.Context(), settingList, companyID.Value)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Info("failed to save setting",
|
||||
zap.Any("setting_list", settingList),
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to save setting")
|
||||
}
|
||||
// // if err != nil {
|
||||
// // h.mongoLoggerSvc.Info("failed to save setting",
|
||||
// // zap.Any("setting_list", settingList),
|
||||
// // zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// // zap.Time("timestamp", time.Now()),
|
||||
// // )
|
||||
// // 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 {
|
||||
h.mongoLoggerSvc.Error("Failed to fetch settings",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error())
|
||||
}
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to fetch settings",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// 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 {
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
if !companyID.Valid {
|
||||
h.BadRequestLogger().Error("invalid company id")
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
|
||||
}
|
||||
// func (h *Handler) GetCompanySettingList(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")
|
||||
// }
|
||||
|
||||
settingsList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
||||
// settingsList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to fetch settings",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error())
|
||||
}
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to fetch settings",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// 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}
|
||||
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")
|
||||
}
|
||||
|
||||
err := h.settingSvc.DeleteCompanySetting(c.Context(), companyID.Value, settingKey)
|
||||
// err := h.settingSvc.DeleteCompanySetting(c.Context(), companyID.Value, settingKey)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
||||
}
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
||||
// }
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
err := h.settingSvc.DeleteAllCompanySetting(c.Context(), companyID.Value)
|
||||
// err := h.settingSvc.DeleteAllCompanySetting(c.Context(), companyID.Value)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
||||
}
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("Failed to delete company override settings",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete company override settings:"+err.Error())
|
||||
// }
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "setting deleted", nil, nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,77 +33,77 @@ type CreateTransactionApproverReq struct {
|
|||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/admin [post]
|
||||
func (h *Handler) CreateTransactionApprover(c *fiber.Ctx) error {
|
||||
var companyID domain.ValidInt64
|
||||
var req CreateTransactionApproverReq
|
||||
// func (h *Handler) CreateTransactionApprover(c *fiber.Ctx) error {
|
||||
// var companyID domain.ValidInt64
|
||||
// var req CreateTransactionApproverReq
|
||||
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.mongoLoggerSvc.Info("failed to parse CreateAdmin request",
|
||||
zap.Int64("status_code", fiber.StatusBadRequest),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+err.Error())
|
||||
}
|
||||
// if err := c.BodyParser(&req); err != nil {
|
||||
// h.mongoLoggerSvc.Info("failed to parse CreateAdmin request",
|
||||
// zap.Int64("status_code", fiber.StatusBadRequest),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+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.Error("validation failed for CreateAdmin request",
|
||||
zap.Int64("status_code", fiber.StatusBadRequest),
|
||||
zap.Any("validation_errors", valErrs),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
}
|
||||
// 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.Error("validation failed for CreateAdmin request",
|
||||
// zap.Int64("status_code", fiber.StatusBadRequest),
|
||||
// zap.Any("validation_errors", valErrs),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
// }
|
||||
|
||||
// _, err := h.companySvc.GetCompanyByID(c.Context(), req.CompanyID)
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
||||
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Int64("company_id", req.CompanyID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
||||
// }
|
||||
companyID = domain.ValidInt64{
|
||||
Value: req.CompanyID,
|
||||
Valid: true,
|
||||
}
|
||||
// // _, err := h.companySvc.GetCompanyByID(c.Context(), req.CompanyID)
|
||||
// // if err != nil {
|
||||
// // h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin",
|
||||
// // zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||
// // zap.Int64("company_id", req.CompanyID),
|
||||
// // zap.Error(err),
|
||||
// // zap.Time("timestamp", time.Now()),
|
||||
// // )
|
||||
// // return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error())
|
||||
// // }
|
||||
// companyID = domain.ValidInt64{
|
||||
// Value: req.CompanyID,
|
||||
// Valid: true,
|
||||
// }
|
||||
|
||||
user := domain.CreateUserReq{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Role: string(domain.RoleTransactionApprover),
|
||||
CompanyID: companyID,
|
||||
}
|
||||
// user := domain.CreateUserReq{
|
||||
// FirstName: req.FirstName,
|
||||
// LastName: req.LastName,
|
||||
// Email: req.Email,
|
||||
// PhoneNumber: req.PhoneNumber,
|
||||
// Password: req.Password,
|
||||
// Role: string(domain.RoleTransactionApprover),
|
||||
// OrganizationID: companyID,
|
||||
// }
|
||||
|
||||
newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("failed to create admin user",
|
||||
zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||
zap.Any("request", req),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
||||
}
|
||||
// newUser, err := h.userSvc.CreateUser(c.Context(), user, true)
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("failed to create admin user",
|
||||
// zap.Int64("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Any("request", req),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
|
||||
// }
|
||||
|
||||
h.mongoLoggerSvc.Info("transaction_approver created successfully",
|
||||
zap.Int64("transaction_approver_id", newUser.ID),
|
||||
zap.String("email", newUser.Email),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
// h.mongoLoggerSvc.Info("transaction_approver created successfully",
|
||||
// zap.Int64("transaction_approver_id", newUser.ID),
|
||||
// zap.String("email", newUser.Email),
|
||||
// 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 {
|
||||
ID int64 `json:"id"`
|
||||
|
|
@ -134,144 +134,144 @@ type TransactionApproverRes struct {
|
|||
// @Failure 401 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/t-approver [get]
|
||||
func (h *Handler) GetAllTransactionApprovers(c *fiber.Ctx) error {
|
||||
role := c.Locals("role").(domain.Role)
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
// func (h *Handler) GetAllTransactionApprovers(c *fiber.Ctx) error {
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
// companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
|
||||
searchQuery := c.Query("query")
|
||||
searchString := domain.ValidString{
|
||||
Value: searchQuery,
|
||||
Valid: searchQuery != "",
|
||||
}
|
||||
// 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.logger.Info("invalid start_time format", "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||
}
|
||||
createdBefore = domain.ValidTime{
|
||||
Value: createdBeforeParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
// createdBeforeQuery := c.Query("created_before")
|
||||
// var createdBefore domain.ValidTime
|
||||
// if createdBeforeQuery != "" {
|
||||
// createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||
// if err != nil {
|
||||
// h.logger.Info("invalid start_time format", "error", err)
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time 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.logger.Info("invalid start_time format", "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||
}
|
||||
createdAfter = domain.ValidTime{
|
||||
Value: createdAfterParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
// createdAfterQuery := c.Query("created_after")
|
||||
// var createdAfter domain.ValidTime
|
||||
// if createdAfterQuery != "" {
|
||||
// createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||
// if err != nil {
|
||||
// h.logger.Info("invalid start_time format", "error", err)
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
|
||||
// }
|
||||
// createdAfter = domain.ValidTime{
|
||||
// Value: createdAfterParsed,
|
||||
// Valid: true,
|
||||
// }
|
||||
// }
|
||||
|
||||
var companyIDFilter domain.ValidInt64
|
||||
if role == domain.RoleSuperAdmin {
|
||||
companyIDQuery := int64(c.QueryInt("company_id"))
|
||||
companyIDFilter = domain.ValidInt64{
|
||||
Value: companyIDQuery,
|
||||
Valid: companyIDQuery != 0,
|
||||
}
|
||||
} else {
|
||||
if !companyID.Valid {
|
||||
h.logger.Info("invalid companyID")
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Unable to get company ID")
|
||||
}
|
||||
// var companyIDFilter domain.ValidInt64
|
||||
// if role == domain.RoleSuperAdmin {
|
||||
// companyIDQuery := int64(c.QueryInt("company_id"))
|
||||
// companyIDFilter = domain.ValidInt64{
|
||||
// Value: companyIDQuery,
|
||||
// Valid: companyIDQuery != 0,
|
||||
// }
|
||||
// } else {
|
||||
// if !companyID.Valid {
|
||||
// h.logger.Info("invalid companyID")
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Unable to get company ID")
|
||||
// }
|
||||
|
||||
companyIDFilter = companyID
|
||||
}
|
||||
// companyIDFilter = companyID
|
||||
// }
|
||||
|
||||
filter := domain.UserFilter{
|
||||
Role: string(domain.RoleTransactionApprover),
|
||||
CompanyID: companyIDFilter,
|
||||
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,
|
||||
}
|
||||
// filter := domain.UserFilter{
|
||||
// Role: string(domain.RoleTransactionApprover),
|
||||
// OrganizationID: companyIDFilter,
|
||||
// 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("invalid filter values in GetAllAdmins request",
|
||||
zap.Int("status_code", fiber.StatusBadRequest),
|
||||
zap.Any("validation_errors", valErrs),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
}
|
||||
// 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("invalid filter values in GetAllAdmins request",
|
||||
// zap.Int("status_code", fiber.StatusBadRequest),
|
||||
// zap.Any("validation_errors", valErrs),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusBadRequest, errMsg)
|
||||
// }
|
||||
|
||||
users, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("failed to get users from user service",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Any("filter", filter),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users"+err.Error())
|
||||
}
|
||||
// users, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
|
||||
// if err != nil {
|
||||
// h.mongoLoggerSvc.Error("failed to get users from user service",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Any("filter", filter),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users"+err.Error())
|
||||
// }
|
||||
|
||||
result := make([]TransactionApproverRes, len(users))
|
||||
for index, admin := range users {
|
||||
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID)
|
||||
if err != nil {
|
||||
if err == authentication.ErrRefreshTokenNotFound {
|
||||
lastLogin = &admin.CreatedAt
|
||||
} else {
|
||||
h.mongoLoggerSvc.Error("failed to get last login for admin",
|
||||
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
zap.Int64("admin_id", admin.ID),
|
||||
zap.Error(err),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
||||
}
|
||||
}
|
||||
// result := make([]TransactionApproverRes, len(users))
|
||||
// for index, admin := range users {
|
||||
// lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID)
|
||||
// if err != nil {
|
||||
// if err == authentication.ErrRefreshTokenNotFound {
|
||||
// lastLogin = &admin.CreatedAt
|
||||
// } else {
|
||||
// h.mongoLoggerSvc.Error("failed to get last login for admin",
|
||||
// zap.Int("status_code", fiber.StatusInternalServerError),
|
||||
// zap.Int64("admin_id", admin.ID),
|
||||
// zap.Error(err),
|
||||
// zap.Time("timestamp", time.Now()),
|
||||
// )
|
||||
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error())
|
||||
// }
|
||||
// }
|
||||
|
||||
result[index] = TransactionApproverRes{
|
||||
ID: admin.ID,
|
||||
FirstName: admin.FirstName,
|
||||
LastName: admin.LastName,
|
||||
Email: admin.Email,
|
||||
PhoneNumber: admin.PhoneNumber,
|
||||
Role: admin.Role,
|
||||
EmailVerified: admin.EmailVerified,
|
||||
PhoneVerified: admin.PhoneVerified,
|
||||
CreatedAt: admin.CreatedAt,
|
||||
UpdatedAt: admin.UpdatedAt,
|
||||
SuspendedAt: admin.SuspendedAt,
|
||||
Suspended: admin.Suspended,
|
||||
LastLogin: *lastLogin,
|
||||
}
|
||||
}
|
||||
// result[index] = TransactionApproverRes{
|
||||
// ID: admin.ID,
|
||||
// FirstName: admin.FirstName,
|
||||
// LastName: admin.LastName,
|
||||
// Email: admin.Email,
|
||||
// PhoneNumber: admin.PhoneNumber,
|
||||
// Role: admin.Role,
|
||||
// EmailVerified: admin.EmailVerified,
|
||||
// PhoneVerified: admin.PhoneVerified,
|
||||
// CreatedAt: admin.CreatedAt,
|
||||
// UpdatedAt: admin.UpdatedAt,
|
||||
// SuspendedAt: admin.SuspendedAt,
|
||||
// Suspended: admin.Suspended,
|
||||
// LastLogin: *lastLogin,
|
||||
// }
|
||||
// }
|
||||
|
||||
h.mongoLoggerSvc.Info("approvers retrieved successfully",
|
||||
zap.Int("status_code", fiber.StatusOK),
|
||||
zap.Int("count", len(result)),
|
||||
zap.Int("page", filter.Page.Value+1),
|
||||
zap.Time("timestamp", time.Now()),
|
||||
)
|
||||
// h.mongoLoggerSvc.Info("approvers retrieved successfully",
|
||||
// zap.Int("status_code", fiber.StatusOK),
|
||||
// zap.Int("count", len(result)),
|
||||
// zap.Int("page", filter.Page.Value+1),
|
||||
// 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
|
||||
// @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{
|
||||
UserId: ApproverID,
|
||||
UserID: ApproverID,
|
||||
FirstName: domain.ValidString{
|
||||
Value: 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())
|
||||
}
|
||||
|
||||
if !user.CompanyID.Valid {
|
||||
if !user.OrganizationID.Valid {
|
||||
if user.Role == domain.RoleSuperAdmin {
|
||||
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{
|
||||
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)
|
||||
|
|
@ -102,11 +102,11 @@ type CheckPhoneEmailExistRes struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/user/checkPhoneEmailExist [post]
|
||||
func (h *Handler) CheckPhoneEmailExist(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")
|
||||
}
|
||||
// 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 CheckPhoneEmailExistReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
h.mongoLoggerSvc.Error("Failed to check phone/email existence",
|
||||
zap.Any("request", req),
|
||||
|
|
@ -160,11 +160,11 @@ type RegisterCodeReq struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/user/sendRegisterCode [post]
|
||||
func (h *Handler) SendRegisterCode(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")
|
||||
}
|
||||
// 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 RegisterCodeReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
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")
|
||||
}
|
||||
|
||||
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",
|
||||
zap.String("Medium", string(medium)),
|
||||
zap.String("Send To", string(sentTo)),
|
||||
|
|
@ -231,11 +231,6 @@ type RegisterUserReq struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/user/register [post]
|
||||
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
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
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)
|
||||
}
|
||||
user := domain.RegisterUserReq{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Otp: req.Otp,
|
||||
ReferralCode: req.ReferralCode,
|
||||
OtpMedium: domain.OtpMediumEmail,
|
||||
CompanyID: companyID,
|
||||
Role: string(domain.RoleCustomer),
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Otp: req.Otp,
|
||||
ReferralCode: req.ReferralCode,
|
||||
OtpMedium: domain.OtpMediumEmail,
|
||||
OrganizationID: domain.ValidInt64{},
|
||||
Role: string(domain.RoleStudent),
|
||||
}
|
||||
medium, err := getMedium(req.Email, req.PhoneNumber)
|
||||
if err != nil {
|
||||
|
|
@ -279,7 +274,7 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
|||
|
||||
user.OtpMedium = medium
|
||||
|
||||
newUser, err := h.userSvc.RegisterUser(c.Context(), user)
|
||||
_, err = h.userSvc.RegisterUser(c.Context(), user)
|
||||
if err != nil {
|
||||
if errors.Is(err, domain.ErrOtpAlreadyUsed) {
|
||||
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())
|
||||
}
|
||||
|
||||
// _, 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)
|
||||
}
|
||||
|
||||
|
|
@ -424,11 +381,11 @@ func (h *Handler) SendResetCode(c *fiber.Ctx) error {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/user/sendResetCode [post]
|
||||
func (h *Handler) SendTenantResetCode(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")
|
||||
}
|
||||
// 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 ResetCodeReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
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")
|
||||
}
|
||||
|
||||
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",
|
||||
zap.String("medium", string(medium)),
|
||||
zap.String("sentTo", string(sentTo)),
|
||||
|
|
@ -562,11 +519,11 @@ func (h *Handler) ResetPassword(c *fiber.Ctx) error {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/user/resetPassword [post]
|
||||
func (h *Handler) ResetTenantPassword(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")
|
||||
}
|
||||
// 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 ResetPasswordReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
|
|
@ -599,12 +556,12 @@ func (h *Handler) ResetTenantPassword(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
resetReq := domain.ResetPasswordReq{
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Otp: req.Otp,
|
||||
OtpMedium: medium,
|
||||
CompanyID: companyID.Value,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
Otp: req.Otp,
|
||||
OtpMedium: medium,
|
||||
OrganizationID: 1,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
h.mongoLoggerSvc.Error("Failed to get user by name or phone",
|
||||
zap.Any("request", req),
|
||||
|
|
@ -912,11 +874,11 @@ func (h *Handler) SearchUserByNameOrPhone(c *fiber.Ctx) error {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /api/v1/{tenant_slug}/user/search [post]
|
||||
func (h *Handler) SearchCompanyUserByNameOrPhone(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")
|
||||
}
|
||||
// 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 SearchUserByNameOrPhoneReq
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
h.mongoLoggerSvc.Error("Failed to get user by name or phone",
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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 {
|
||||
JwtAccessKey string
|
||||
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) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim{
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: "fortune-bet",
|
||||
Issuer: "yimaru.com",
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
Audience: jwt.ClaimStrings{"api.fortunebets.net"},
|
||||
Audience: jwt.ClaimStrings{"api.yimaru.com"},
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
token, err := jwt.ParseWithClaims(jwtToken, &UserClaim{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(key), nil
|
||||
|
|
@ -101,22 +67,3 @@ func ParseJwt(jwtToken string, key string) (*UserClaim, error) {
|
|||
}
|
||||
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
|
||||
// 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, "fortune.com", claims.Audience[0], "Audience should match")
|
||||
// assert.True(t, claims.ExpiresAt.Time.After(time.Now()), "Token should not be expired yet")
|
||||
|
||||
// // 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 {
|
||||
userID := c.Locals("user_id").(int64)
|
||||
userRole := c.Locals("role").(domain.Role)
|
||||
if userRole == domain.RoleCustomer {
|
||||
if userRole == domain.RoleStudent {
|
||||
a.mongoLoggerSvc.Warn("Attempt to access restricted CompanyOnly route",
|
||||
zap.Int64("userID", userID),
|
||||
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 {
|
||||
userID := c.Locals("user_id").(int64)
|
||||
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",
|
||||
zap.Int64("userID", userID),
|
||||
zap.String("role", string(userRole)),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ func (a *App) initAppRoutes() {
|
|||
a.settingSvc,
|
||||
a.NotidicationStore,
|
||||
a.validator,
|
||||
a.referralSvc,
|
||||
a.recommendationSvc,
|
||||
a.userSvc,
|
||||
a.transactionSvc,
|
||||
|
|
@ -70,20 +69,12 @@ func (a *App) initAppRoutes() {
|
|||
// Get S
|
||||
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
|
||||
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
||||
|
||||
groupV1.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{
|
||||
"message": "FortuneBet API V1",
|
||||
"message": "Welcome to Yimaru Backend API v1",
|
||||
"version": "1.0.1",
|
||||
})
|
||||
})
|
||||
|
|
@ -128,23 +119,7 @@ func (a *App) initAppRoutes() {
|
|||
// groupV1.Post("/arifpay/b2c/transfer", a.authMiddleware, h.ExecuteArifpayB2CTransfer)
|
||||
// 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/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)
|
||||
// groupV1.Get("/arifpay/payment-methods", a.authMiddleware, h.GetArifpayPaymentMethodsHandler
|
||||
|
||||
// User Routes
|
||||
groupV1.Post("/user/resetPassword", h.ResetPassword)
|
||||
|
|
@ -159,272 +134,26 @@ func (a *App) initAppRoutes() {
|
|||
groupV1.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
||||
|
||||
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.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
||||
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
||||
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/:id", a.authMiddleware, a.SuperAdminOnly, h.GetAdminByID)
|
||||
groupV1.Post("/admin", a.authMiddleware, a.SuperAdminOnly, h.CreateAdmin)
|
||||
groupV1.Put("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAdmin)
|
||||
|
||||
groupV1.Get("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllTransactionApprovers)
|
||||
groupV1.Get("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetTransactionApproverByID)
|
||||
groupV1.Post("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateTransactionApprover)
|
||||
groupV1.Put("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateTransactionApprover)
|
||||
// groupV1.Get("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllTransactionApprovers)
|
||||
// groupV1.Get("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetTransactionApproverByID)
|
||||
// groupV1.Post("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateTransactionApprover)
|
||||
// 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
|
||||
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/:id", a.authMiddleware, a.CompanyOnly, h.GetTransactionByID)
|
||||
// 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("/notifications", a.authMiddleware, h.GetUserNotification)
|
||||
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.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
|
||||
// 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)
|
||||
|
|
@ -473,12 +179,4 @@ func (a *App) initAppRoutes() {
|
|||
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
|
||||
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
|
||||
@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=fortunebet-test-1"):/app/coverage ./ || true
|
||||
@docker cp $(shell docker ps -q -f "name=yimaru-test-1"):/app/coverage ./ || true
|
||||
@docker compose stop test
|
||||
|
||||
.PHONY: build
|
||||
|
|
@ -46,45 +46,45 @@ postgres:
|
|||
.PHONY: backup
|
||||
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:
|
||||
@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 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:
|
||||
@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
|
||||
seed_data:
|
||||
|
||||
@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..."; \
|
||||
sleep 1; \
|
||||
done
|
||||
@for file in db/data/*.sql; do \
|
||||
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
|
||||
.PHONY: seed_dev_data
|
||||
seed_dev_data:
|
||||
@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..."; \
|
||||
sleep 1; \
|
||||
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 \
|
||||
if [ -f "$$file" ]; then \
|
||||
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 \
|
||||
done
|
||||
postgres_log:
|
||||
docker logs fortunebet-backend-postgres-1
|
||||
docker logs yimaru-backend-postgres-1
|
||||
.PHONY: swagger
|
||||
swagger:
|
||||
@swag init -g cmd/main.go
|
||||
|
|
@ -94,15 +94,15 @@ logs:
|
|||
db-up: | logs
|
||||
@mkdir -p logs
|
||||
@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
|
||||
db-down:
|
||||
@docker compose down -v
|
||||
# @docker volume rm fortunebet-backend_postgres_data
|
||||
# @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 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