Spaces:
Runtime error
Runtime error
Commit ·
dc4d7ab
1
Parent(s): 6b99a55
Deploy files from GitHub repository
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- repositories/account_repository.go +1 -1
- repositories/repository.go +10 -14
- services/authentication_service.go +3 -4
- space/repositories/account_repository.go +1 -1
- space/space/config/turnstile_client_config.go +5 -5
- space/space/controller/authentication_controller.go +2 -2
- space/space/go.mod +1 -0
- space/space/go.sum +2 -0
- space/space/models/entities_model.go +1 -1
- space/space/repositories/account_repository.go +2 -2
- space/space/repositories/repository.go +37 -5
- space/space/services/authentication_service.go +11 -9
- space/space/space/space/Dockerfile +2 -2
- space/space/space/space/controller/authentication_controller.go +1 -1
- space/space/space/space/space/config/config.go +1 -0
- space/space/space/space/space/config/env_config.go +4 -1
- space/space/space/space/space/config/turnstile_client_config.go +11 -0
- space/space/space/space/space/controller/authentication_controller.go +40 -0
- space/space/space/space/space/factory/authentication_factory.go +16 -0
- space/space/space/space/space/go.mod +3 -0
- space/space/space/space/space/go.sum +6 -0
- space/space/space/space/space/middleware/authentication_middleware.go +31 -47
- space/space/space/space/space/models/authentication_dto.go +3 -2
- space/space/space/space/space/models/authentication_payload_model.go +11 -3
- space/space/space/space/space/models/entities_model.go +4 -4
- space/space/space/space/space/models/exception_model.go +1 -1
- space/space/space/space/space/models/http_response_dto_model.go +1 -1
- space/space/space/space/space/repositories/account_repository.go +16 -6
- space/space/space/space/space/router/authentication_route.go +20 -0
- space/space/space/space/space/router/router.go +1 -0
- space/space/space/space/space/services/authentication_service.go +68 -3
- space/space/space/space/space/services/jwt_service.go +68 -0
- space/space/space/space/space/space/services/openai_service.go +0 -1
- space/space/space/space/space/space/space/controller/prediction_controller.go +7 -1
- space/space/space/space/space/space/space/services/openai_service.go +1 -0
- space/space/space/space/space/space/space/space/.github/workflows/deploy.yml +4 -3
- space/space/space/space/space/space/space/space/.github/workflows/go.yml +22 -7
- space/space/space/space/space/space/space/space/Dockerfile +3 -3
- space/space/space/space/space/space/space/space/config/config.go +5 -24
- space/space/space/space/space/space/space/space/config/database_connection_config.go +1 -1
- space/space/space/space/space/space/space/space/config/env_config.go +26 -0
- space/space/space/space/space/space/space/space/config/openai_client_config.go +1 -1
- space/space/space/space/space/space/space/space/config/replicate_client_config.go +1 -1
- space/space/space/space/space/space/space/space/factory/prediction_factory.go +15 -5
- space/space/space/space/space/space/space/space/images/foto-pacarku.jpg +0 -0
- space/space/space/space/space/space/space/space/images/foto_pacarku.jpg +0 -0
- space/space/space/space/space/space/space/space/logs/error_log.txt +8 -0
- space/space/space/space/space/space/space/space/main.go +1 -0
- space/space/space/space/space/space/space/space/models/authentication_dto.go +2 -1
- space/space/space/space/space/space/space/space/repositories/chat_history_repository.go +6 -5
repositories/account_repository.go
CHANGED
|
@@ -21,7 +21,7 @@ func NewAccountRepository(db *gorm.DB) AccountRepository {
|
|
| 21 |
return &accountRepository{
|
| 22 |
repository: &repository[models.Account]{
|
| 23 |
entity: models.Account{},
|
| 24 |
-
transaction: db,
|
| 25 |
},
|
| 26 |
}
|
| 27 |
}
|
|
|
|
| 21 |
return &accountRepository{
|
| 22 |
repository: &repository[models.Account]{
|
| 23 |
entity: models.Account{},
|
| 24 |
+
transaction: db.Begin(),
|
| 25 |
},
|
| 26 |
}
|
| 27 |
}
|
repositories/repository.go
CHANGED
|
@@ -55,36 +55,32 @@ func (repo *repository[T1]) Transactions(ctx context.Context, act func(ctx conte
|
|
| 55 |
|
| 56 |
}
|
| 57 |
func (repo *repository[T1]) Where(ctx context.Context) {
|
| 58 |
-
tx := repo.transaction
|
| 59 |
-
tx.WithContext(ctx).Model(&repo.entity)
|
| 60 |
if tx.Error != nil {
|
| 61 |
repo.rowsCount = int(tx.RowsAffected)
|
| 62 |
-
repo.noRecord = repo.rowsCount == 0
|
| 63 |
repo.rowsError = tx.Error
|
| 64 |
repo.rowsError = repo.transaction.Error
|
| 65 |
tx.Rollback()
|
| 66 |
return
|
| 67 |
}
|
| 68 |
-
repo.rowsCount = int(tx.RowsAffected)
|
| 69 |
-
repo.noRecord = repo.rowsCount == 0
|
| 70 |
repo.rowsError = tx.Error
|
|
|
|
| 71 |
|
| 72 |
}
|
| 73 |
func (repo *repository[T1]) Find(ctx context.Context, res any) {
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
if tx.Error != nil {
|
| 78 |
-
repo.rowsCount = int(tx.RowsAffected)
|
| 79 |
repo.noRecord = repo.rowsCount == 0
|
| 80 |
-
repo.rowsError = tx.Error
|
| 81 |
repo.rowsError = repo.transaction.Error
|
| 82 |
-
|
|
|
|
| 83 |
return
|
| 84 |
}
|
| 85 |
-
repo.rowsCount = int(
|
| 86 |
repo.noRecord = repo.rowsCount == 0
|
| 87 |
-
repo.rowsError =
|
| 88 |
|
| 89 |
}
|
| 90 |
|
|
|
|
| 55 |
|
| 56 |
}
|
| 57 |
func (repo *repository[T1]) Where(ctx context.Context) {
|
| 58 |
+
tx := repo.transaction.WithContext(ctx).Model(&repo.entity)
|
|
|
|
| 59 |
if tx.Error != nil {
|
| 60 |
repo.rowsCount = int(tx.RowsAffected)
|
| 61 |
+
repo.noRecord = (repo.rowsCount == 0)
|
| 62 |
repo.rowsError = tx.Error
|
| 63 |
repo.rowsError = repo.transaction.Error
|
| 64 |
tx.Rollback()
|
| 65 |
return
|
| 66 |
}
|
|
|
|
|
|
|
| 67 |
repo.rowsError = tx.Error
|
| 68 |
+
return
|
| 69 |
|
| 70 |
}
|
| 71 |
func (repo *repository[T1]) Find(ctx context.Context, res any) {
|
| 72 |
+
repo.transaction = repo.transaction.WithContext(ctx).First(&res)
|
| 73 |
+
if repo.transaction.Error != nil {
|
| 74 |
+
repo.rowsCount = int(repo.transaction.RowsAffected)
|
|
|
|
|
|
|
| 75 |
repo.noRecord = repo.rowsCount == 0
|
|
|
|
| 76 |
repo.rowsError = repo.transaction.Error
|
| 77 |
+
repo.rowsError = repo.transaction.Error
|
| 78 |
+
repo.transaction.Rollback()
|
| 79 |
return
|
| 80 |
}
|
| 81 |
+
repo.rowsCount = int(repo.transaction.RowsAffected)
|
| 82 |
repo.noRecord = repo.rowsCount == 0
|
| 83 |
+
repo.rowsError = repo.transaction.Error
|
| 84 |
|
| 85 |
}
|
| 86 |
|
services/authentication_service.go
CHANGED
|
@@ -59,15 +59,14 @@ func (s *authenticationService) Register(ctx context.Context, passPhrase string,
|
|
| 59 |
|
| 60 |
func (s *authenticationService) Login(ctx context.Context, passPhrase string) string {
|
| 61 |
account := s.repository.GetAccountByPassPhrase(ctx, passPhrase)
|
| 62 |
-
if s.ThrowsRepoException() {
|
| 63 |
-
return ""
|
| 64 |
-
}
|
| 65 |
|
| 66 |
if s.repository.IsNoRecord() {
|
| 67 |
s.ThrowsException(&s.exception.Unauthorized, "Account not found!")
|
| 68 |
return " "
|
| 69 |
}
|
| 70 |
-
|
|
|
|
|
|
|
| 71 |
token := s.jwtService.GenerateToken(ctx, models.JWTCustomClaims{IdUser: account.ID})
|
| 72 |
if s.jwtService.Error() != nil {
|
| 73 |
s.ThrowsException(&s.exception.Unauthorized, "JWTService Error")
|
|
|
|
| 59 |
|
| 60 |
func (s *authenticationService) Login(ctx context.Context, passPhrase string) string {
|
| 61 |
account := s.repository.GetAccountByPassPhrase(ctx, passPhrase)
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
if s.repository.IsNoRecord() {
|
| 64 |
s.ThrowsException(&s.exception.Unauthorized, "Account not found!")
|
| 65 |
return " "
|
| 66 |
}
|
| 67 |
+
if s.ThrowsRepoException() {
|
| 68 |
+
return ""
|
| 69 |
+
}
|
| 70 |
token := s.jwtService.GenerateToken(ctx, models.JWTCustomClaims{IdUser: account.ID})
|
| 71 |
if s.jwtService.Error() != nil {
|
| 72 |
s.ThrowsException(&s.exception.Unauthorized, "JWTService Error")
|
space/repositories/account_repository.go
CHANGED
|
@@ -35,6 +35,6 @@ func (r *accountRepository) CreateAccount(ctx context.Context, passPhrase string
|
|
| 35 |
func (r *accountRepository) GetAccountByPassPhrase(ctx context.Context, passPhrase string) (res models.Account) {
|
| 36 |
r.entity.PassPhrase = passPhrase
|
| 37 |
r.Where(ctx)
|
| 38 |
-
r.Find(ctx, res)
|
| 39 |
return res
|
| 40 |
}
|
|
|
|
| 35 |
func (r *accountRepository) GetAccountByPassPhrase(ctx context.Context, passPhrase string) (res models.Account) {
|
| 36 |
r.entity.PassPhrase = passPhrase
|
| 37 |
r.Where(ctx)
|
| 38 |
+
r.Find(ctx, &res)
|
| 39 |
return res
|
| 40 |
}
|
space/space/config/turnstile_client_config.go
CHANGED
|
@@ -1,11 +1,11 @@
|
|
| 1 |
package config
|
| 2 |
|
| 3 |
-
import
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
var TurnstileClient turnstile.
|
| 6 |
|
| 7 |
func InitTurnStileClient() {
|
| 8 |
-
TurnstileClient = turnstile.New(
|
| 9 |
-
Secret: TURNSTILE_SECRET_KEY,
|
| 10 |
-
})
|
| 11 |
}
|
|
|
|
| 1 |
package config
|
| 2 |
|
| 3 |
+
import (
|
| 4 |
+
"github.com/meyskens/go-turnstile"
|
| 5 |
+
)
|
| 6 |
|
| 7 |
+
var TurnstileClient *turnstile.Turnstile
|
| 8 |
|
| 9 |
func InitTurnStileClient() {
|
| 10 |
+
TurnstileClient = turnstile.New(TURNSTILE_SECRET_KEY)
|
|
|
|
|
|
|
| 11 |
}
|
space/space/controller/authentication_controller.go
CHANGED
|
@@ -22,7 +22,7 @@ func NewAuthenticationController(authenticationService services.AuthenticationSe
|
|
| 22 |
}
|
| 23 |
func (c *authenticationController) Register(ctx *gin.Context) {
|
| 24 |
var loginRequest models.LoginRequest
|
| 25 |
-
c.RequestJSON(ctx, loginRequest)
|
| 26 |
if loginRequest.IPAddress == "" {
|
| 27 |
loginRequest.IPAddress = ctx.ClientIP()
|
| 28 |
}
|
|
@@ -32,7 +32,7 @@ func (c *authenticationController) Register(ctx *gin.Context) {
|
|
| 32 |
}
|
| 33 |
func (c *authenticationController) Login(ctx *gin.Context) {
|
| 34 |
var loginRequest models.LoginRequest
|
| 35 |
-
c.RequestJSON(ctx, loginRequest)
|
| 36 |
|
| 37 |
token := c.service.Login(ctx.Request.Context(), loginRequest.PassPhrase)
|
| 38 |
|
|
|
|
| 22 |
}
|
| 23 |
func (c *authenticationController) Register(ctx *gin.Context) {
|
| 24 |
var loginRequest models.LoginRequest
|
| 25 |
+
c.RequestJSON(ctx, &loginRequest)
|
| 26 |
if loginRequest.IPAddress == "" {
|
| 27 |
loginRequest.IPAddress = ctx.ClientIP()
|
| 28 |
}
|
|
|
|
| 32 |
}
|
| 33 |
func (c *authenticationController) Login(ctx *gin.Context) {
|
| 34 |
var loginRequest models.LoginRequest
|
| 35 |
+
c.RequestJSON(ctx, &loginRequest)
|
| 36 |
|
| 37 |
token := c.service.Login(ctx.Request.Context(), loginRequest.PassPhrase)
|
| 38 |
|
space/space/go.mod
CHANGED
|
@@ -37,6 +37,7 @@ require (
|
|
| 37 |
github.com/kr/text v0.2.0 // indirect
|
| 38 |
github.com/leodido/go-urn v1.4.0 // indirect
|
| 39 |
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
|
|
| 40 |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
| 41 |
github.com/modern-go/reflect2 v1.0.2 // indirect
|
| 42 |
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
|
|
|
| 37 |
github.com/kr/text v0.2.0 // indirect
|
| 38 |
github.com/leodido/go-urn v1.4.0 // indirect
|
| 39 |
github.com/mattn/go-isatty v0.0.20 // indirect
|
| 40 |
+
github.com/meyskens/go-turnstile v0.0.0-20230622160222-89160e594ca1 // indirect
|
| 41 |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
| 42 |
github.com/modern-go/reflect2 v1.0.2 // indirect
|
| 43 |
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
space/space/go.sum
CHANGED
|
@@ -67,6 +67,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
|
| 67 |
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
| 68 |
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
| 69 |
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
|
|
|
|
|
| 70 |
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
| 71 |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
| 72 |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
|
|
| 67 |
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
| 68 |
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
| 69 |
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
| 70 |
+
github.com/meyskens/go-turnstile v0.0.0-20230622160222-89160e594ca1 h1:lGjDY7OC1VfMpuVUN+b59vPPepbPx/eJQXGqpM2pCdw=
|
| 71 |
+
github.com/meyskens/go-turnstile v0.0.0-20230622160222-89160e594ca1/go.mod h1:YbEb1gFAr7w2NcabqA2aPAeyW4Mhf85fmt+vVrrLo4s=
|
| 72 |
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
| 73 |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
| 74 |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
space/space/models/entities_model.go
CHANGED
|
@@ -8,7 +8,7 @@ import (
|
|
| 8 |
|
| 9 |
type Account struct {
|
| 10 |
ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
|
| 11 |
-
PassPhrase string `gorm:"not null;"`
|
| 12 |
CreatedAt time.Time
|
| 13 |
DeletedAt *time.Time `gorm:"column:deleted_at"` // perhatikan penamaan kolom
|
| 14 |
}
|
|
|
|
| 8 |
|
| 9 |
type Account struct {
|
| 10 |
ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
|
| 11 |
+
PassPhrase string `gorm:"not null;uniqueIndex"`
|
| 12 |
CreatedAt time.Time
|
| 13 |
DeletedAt *time.Time `gorm:"column:deleted_at"` // perhatikan penamaan kolom
|
| 14 |
}
|
space/space/repositories/account_repository.go
CHANGED
|
@@ -9,8 +9,8 @@ import (
|
|
| 9 |
|
| 10 |
type AccountRepository interface {
|
| 11 |
Repository
|
| 12 |
-
CreateAccount(ctx context.Context,
|
| 13 |
-
GetAccountByPassPhrase(ctx context.Context,
|
| 14 |
}
|
| 15 |
|
| 16 |
type accountRepository struct {
|
|
|
|
| 9 |
|
| 10 |
type AccountRepository interface {
|
| 11 |
Repository
|
| 12 |
+
CreateAccount(ctx context.Context, passPhrase string) (res models.Account)
|
| 13 |
+
GetAccountByPassPhrase(ctx context.Context, passPhrase string) (res models.Account)
|
| 14 |
}
|
| 15 |
|
| 16 |
type accountRepository struct {
|
space/space/repositories/repository.go
CHANGED
|
@@ -56,8 +56,15 @@ func (repo *repository[T1]) Transactions(ctx context.Context, act func(ctx conte
|
|
| 56 |
}
|
| 57 |
func (repo *repository[T1]) Where(ctx context.Context) {
|
| 58 |
tx := repo.transaction
|
| 59 |
-
tx.WithContext(ctx).
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
repo.rowsCount = int(tx.RowsAffected)
|
| 62 |
repo.noRecord = repo.rowsCount == 0
|
| 63 |
repo.rowsError = tx.Error
|
|
@@ -66,11 +73,15 @@ func (repo *repository[T1]) Where(ctx context.Context) {
|
|
| 66 |
func (repo *repository[T1]) Find(ctx context.Context, res any) {
|
| 67 |
|
| 68 |
tx := repo.transaction
|
| 69 |
-
tx.WithContext(ctx).
|
| 70 |
if tx.Error != nil {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
tx.Rollback()
|
|
|
|
| 72 |
}
|
| 73 |
-
|
| 74 |
repo.rowsCount = int(tx.RowsAffected)
|
| 75 |
repo.noRecord = repo.rowsCount == 0
|
| 76 |
repo.rowsError = tx.Error
|
|
@@ -82,9 +93,13 @@ func (repo *repository[T1]) FindAllPaginate(ctx context.Context, res any) {
|
|
| 82 |
tx := repo.transaction
|
| 83 |
tx.WithContext(ctx).Limit(repo.pagination.limit).Offset(repo.pagination.offset).Find(&res)
|
| 84 |
if tx.Error != nil {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
tx.Rollback()
|
|
|
|
| 86 |
}
|
| 87 |
-
|
| 88 |
repo.rowsCount = int(tx.RowsAffected)
|
| 89 |
repo.noRecord = repo.rowsCount == 0
|
| 90 |
repo.rowsError = tx.Error
|
|
@@ -116,7 +131,12 @@ func (repo *repository[T1]) Update(ctx context.Context) {
|
|
| 116 |
tx := repo.transaction
|
| 117 |
tx.WithContext(ctx).Save(&repo.entity).Find(&repo.entity)
|
| 118 |
if tx.Error != nil {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
tx.Rollback()
|
|
|
|
| 120 |
}
|
| 121 |
|
| 122 |
repo.rowsCount = int(tx.RowsAffected)
|
|
@@ -129,8 +149,14 @@ func (repo *repository[T1]) Delete(ctx context.Context) {
|
|
| 129 |
|
| 130 |
tx := repo.transaction
|
| 131 |
tx.WithContext(ctx).Delete(&repo.entity)
|
|
|
|
| 132 |
if tx.Error != nil {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
tx.Rollback()
|
|
|
|
| 134 |
}
|
| 135 |
|
| 136 |
repo.rowsCount = int(tx.RowsAffected)
|
|
@@ -143,8 +169,14 @@ func (repo *repository[T1]) Query(ctx context.Context, res any) {
|
|
| 143 |
|
| 144 |
tx := repo.transaction
|
| 145 |
tx.WithContext(ctx).Model(&repo.entity).Raw(repo.customQuery.sql, repo.customQuery.values).Scan(&res)
|
|
|
|
| 146 |
if tx.Error != nil {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
tx.Rollback()
|
|
|
|
| 148 |
}
|
| 149 |
|
| 150 |
repo.rowsCount = int(tx.RowsAffected)
|
|
|
|
| 56 |
}
|
| 57 |
func (repo *repository[T1]) Where(ctx context.Context) {
|
| 58 |
tx := repo.transaction
|
| 59 |
+
tx.WithContext(ctx).Model(&repo.entity)
|
| 60 |
+
if tx.Error != nil {
|
| 61 |
+
repo.rowsCount = int(tx.RowsAffected)
|
| 62 |
+
repo.noRecord = repo.rowsCount == 0
|
| 63 |
+
repo.rowsError = tx.Error
|
| 64 |
+
repo.rowsError = repo.transaction.Error
|
| 65 |
+
tx.Rollback()
|
| 66 |
+
return
|
| 67 |
+
}
|
| 68 |
repo.rowsCount = int(tx.RowsAffected)
|
| 69 |
repo.noRecord = repo.rowsCount == 0
|
| 70 |
repo.rowsError = tx.Error
|
|
|
|
| 73 |
func (repo *repository[T1]) Find(ctx context.Context, res any) {
|
| 74 |
|
| 75 |
tx := repo.transaction
|
| 76 |
+
tx.WithContext(ctx).First(&res)
|
| 77 |
if tx.Error != nil {
|
| 78 |
+
repo.rowsCount = int(tx.RowsAffected)
|
| 79 |
+
repo.noRecord = repo.rowsCount == 0
|
| 80 |
+
repo.rowsError = tx.Error
|
| 81 |
+
repo.rowsError = repo.transaction.Error
|
| 82 |
tx.Rollback()
|
| 83 |
+
return
|
| 84 |
}
|
|
|
|
| 85 |
repo.rowsCount = int(tx.RowsAffected)
|
| 86 |
repo.noRecord = repo.rowsCount == 0
|
| 87 |
repo.rowsError = tx.Error
|
|
|
|
| 93 |
tx := repo.transaction
|
| 94 |
tx.WithContext(ctx).Limit(repo.pagination.limit).Offset(repo.pagination.offset).Find(&res)
|
| 95 |
if tx.Error != nil {
|
| 96 |
+
repo.rowsCount = int(tx.RowsAffected)
|
| 97 |
+
repo.noRecord = repo.rowsCount == 0
|
| 98 |
+
repo.rowsError = tx.Error
|
| 99 |
+
repo.rowsError = repo.transaction.Error
|
| 100 |
tx.Rollback()
|
| 101 |
+
return
|
| 102 |
}
|
|
|
|
| 103 |
repo.rowsCount = int(tx.RowsAffected)
|
| 104 |
repo.noRecord = repo.rowsCount == 0
|
| 105 |
repo.rowsError = tx.Error
|
|
|
|
| 131 |
tx := repo.transaction
|
| 132 |
tx.WithContext(ctx).Save(&repo.entity).Find(&repo.entity)
|
| 133 |
if tx.Error != nil {
|
| 134 |
+
repo.rowsCount = int(tx.RowsAffected)
|
| 135 |
+
repo.noRecord = repo.rowsCount == 0
|
| 136 |
+
repo.rowsError = tx.Error
|
| 137 |
+
repo.rowsError = repo.transaction.Error
|
| 138 |
tx.Rollback()
|
| 139 |
+
return
|
| 140 |
}
|
| 141 |
|
| 142 |
repo.rowsCount = int(tx.RowsAffected)
|
|
|
|
| 149 |
|
| 150 |
tx := repo.transaction
|
| 151 |
tx.WithContext(ctx).Delete(&repo.entity)
|
| 152 |
+
|
| 153 |
if tx.Error != nil {
|
| 154 |
+
repo.rowsCount = int(tx.RowsAffected)
|
| 155 |
+
repo.noRecord = repo.rowsCount == 0
|
| 156 |
+
repo.rowsError = tx.Error
|
| 157 |
+
repo.rowsError = repo.transaction.Error
|
| 158 |
tx.Rollback()
|
| 159 |
+
return
|
| 160 |
}
|
| 161 |
|
| 162 |
repo.rowsCount = int(tx.RowsAffected)
|
|
|
|
| 169 |
|
| 170 |
tx := repo.transaction
|
| 171 |
tx.WithContext(ctx).Model(&repo.entity).Raw(repo.customQuery.sql, repo.customQuery.values).Scan(&res)
|
| 172 |
+
|
| 173 |
if tx.Error != nil {
|
| 174 |
+
repo.rowsCount = int(tx.RowsAffected)
|
| 175 |
+
repo.noRecord = repo.rowsCount == 0
|
| 176 |
+
repo.rowsError = tx.Error
|
| 177 |
+
repo.rowsError = repo.transaction.Error
|
| 178 |
tx.Rollback()
|
| 179 |
+
return
|
| 180 |
}
|
| 181 |
|
| 182 |
repo.rowsCount = int(tx.RowsAffected)
|
space/space/services/authentication_service.go
CHANGED
|
@@ -2,10 +2,11 @@ package services
|
|
| 2 |
|
| 3 |
import (
|
| 4 |
"context"
|
|
|
|
| 5 |
|
| 6 |
-
"github.com/9ssi7/turnstile"
|
| 7 |
models "github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 8 |
"github.com/abdanhafidz/ai-visual-multi-modal-backend/repositories"
|
|
|
|
| 9 |
)
|
| 10 |
|
| 11 |
type AuthenticationService interface {
|
|
@@ -16,11 +17,11 @@ type AuthenticationService interface {
|
|
| 16 |
|
| 17 |
type authenticationService struct {
|
| 18 |
*service[repositories.AccountRepository]
|
| 19 |
-
turnStileClient turnstile.
|
| 20 |
jwtService JWTService
|
| 21 |
}
|
| 22 |
|
| 23 |
-
func NewAuthenticationService(accountRepository repositories.AccountRepository, turnStileClient turnstile.
|
| 24 |
return &authenticationService{
|
| 25 |
service: &service[repositories.AccountRepository]{repository: accountRepository},
|
| 26 |
turnStileClient: turnStileClient,
|
|
@@ -28,14 +29,16 @@ func NewAuthenticationService(accountRepository repositories.AccountRepository,
|
|
| 28 |
}
|
| 29 |
}
|
| 30 |
func (s *authenticationService) Register(ctx context.Context, passPhrase string, turnstile string, ip string) string {
|
| 31 |
-
|
| 32 |
-
|
|
|
|
| 33 |
if err != nil {
|
| 34 |
-
s.ThrowsException(&s.exception.Unauthorized, "Turnstile error!")
|
|
|
|
| 35 |
return ""
|
| 36 |
}
|
| 37 |
|
| 38 |
-
if
|
| 39 |
account := s.repository.CreateAccount(ctx, passPhrase)
|
| 40 |
if s.ThrowsRepoException() {
|
| 41 |
return ""
|
|
@@ -50,9 +53,8 @@ func (s *authenticationService) Register(ctx context.Context, passPhrase string,
|
|
| 50 |
return token
|
| 51 |
} else {
|
| 52 |
s.ThrowsException(&s.exception.Unauthorized, "Invalid turnstile payload!")
|
|
|
|
| 53 |
}
|
| 54 |
-
|
| 55 |
-
return ""
|
| 56 |
}
|
| 57 |
|
| 58 |
func (s *authenticationService) Login(ctx context.Context, passPhrase string) string {
|
|
|
|
| 2 |
|
| 3 |
import (
|
| 4 |
"context"
|
| 5 |
+
"fmt"
|
| 6 |
|
|
|
|
| 7 |
models "github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 8 |
"github.com/abdanhafidz/ai-visual-multi-modal-backend/repositories"
|
| 9 |
+
"github.com/meyskens/go-turnstile"
|
| 10 |
)
|
| 11 |
|
| 12 |
type AuthenticationService interface {
|
|
|
|
| 17 |
|
| 18 |
type authenticationService struct {
|
| 19 |
*service[repositories.AccountRepository]
|
| 20 |
+
turnStileClient *turnstile.Turnstile
|
| 21 |
jwtService JWTService
|
| 22 |
}
|
| 23 |
|
| 24 |
+
func NewAuthenticationService(accountRepository repositories.AccountRepository, turnStileClient *turnstile.Turnstile, jwtService JWTService) AuthenticationService {
|
| 25 |
return &authenticationService{
|
| 26 |
service: &service[repositories.AccountRepository]{repository: accountRepository},
|
| 27 |
turnStileClient: turnStileClient,
|
|
|
|
| 29 |
}
|
| 30 |
}
|
| 31 |
func (s *authenticationService) Register(ctx context.Context, passPhrase string, turnstile string, ip string) string {
|
| 32 |
+
turnStileResponse, err := s.turnStileClient.Verify(turnstile, ip)
|
| 33 |
+
fmt.Println(turnstile)
|
| 34 |
+
fmt.Println(turnStileResponse)
|
| 35 |
if err != nil {
|
| 36 |
+
s.ThrowsException(&s.exception.Unauthorized, "Turnstile error!, Turnstile Respose :")
|
| 37 |
+
s.ThrowsError(err)
|
| 38 |
return ""
|
| 39 |
}
|
| 40 |
|
| 41 |
+
if turnStileResponse.Success {
|
| 42 |
account := s.repository.CreateAccount(ctx, passPhrase)
|
| 43 |
if s.ThrowsRepoException() {
|
| 44 |
return ""
|
|
|
|
| 53 |
return token
|
| 54 |
} else {
|
| 55 |
s.ThrowsException(&s.exception.Unauthorized, "Invalid turnstile payload!")
|
| 56 |
+
return ""
|
| 57 |
}
|
|
|
|
|
|
|
| 58 |
}
|
| 59 |
|
| 60 |
func (s *authenticationService) Login(ctx context.Context, passPhrase string) string {
|
space/space/space/space/Dockerfile
CHANGED
|
@@ -31,8 +31,8 @@ RUN --mount=type=secret,id=DB_PASSWORD,mode=0444,required=false \
|
|
| 31 |
echo "LOG_PATH=logs" >> .env && \
|
| 32 |
echo "EMAIL_VERIFICATION_DURATION=2" >> .env && \
|
| 33 |
echo "OPEN_AI_API_KEY=$(cat /run/secrets/OPENAI_API_KEY 2>/dev/null)" >> .env && \
|
| 34 |
-
echo "REPLICATE_API_TOKEN=$(cat /run/secrets/REPLICATE_API_TOKEN 2>/dev/null)" >> .env
|
| 35 |
-
|
| 36 |
# Buat direktori audio dan logs, beri izin dan kepemilikan ke appuser
|
| 37 |
RUN mkdir -p /app/images /app/logs /app/audio && \
|
| 38 |
chmod -R 777 /app/images /app/logs /app/audio && \
|
|
|
|
| 31 |
echo "LOG_PATH=logs" >> .env && \
|
| 32 |
echo "EMAIL_VERIFICATION_DURATION=2" >> .env && \
|
| 33 |
echo "OPEN_AI_API_KEY=$(cat /run/secrets/OPENAI_API_KEY 2>/dev/null)" >> .env && \
|
| 34 |
+
echo "REPLICATE_API_TOKEN=$(cat /run/secrets/REPLICATE_API_TOKEN 2>/dev/null)" >> .env && \
|
| 35 |
+
echo "TURNSTILE_SECRET_KEY =$(cat /run/secrets/TURNSTILE_SECRET_KEY>/dev/null)" >> .env
|
| 36 |
# Buat direktori audio dan logs, beri izin dan kepemilikan ke appuser
|
| 37 |
RUN mkdir -p /app/images /app/logs /app/audio && \
|
| 38 |
chmod -R 777 /app/images /app/logs /app/audio && \
|
space/space/space/space/controller/authentication_controller.go
CHANGED
|
@@ -23,7 +23,7 @@ func NewAuthenticationController(authenticationService services.AuthenticationSe
|
|
| 23 |
func (c *authenticationController) Register(ctx *gin.Context) {
|
| 24 |
var loginRequest models.LoginRequest
|
| 25 |
c.RequestJSON(ctx, loginRequest)
|
| 26 |
-
if
|
| 27 |
loginRequest.IPAddress = ctx.ClientIP()
|
| 28 |
}
|
| 29 |
token := c.service.Register(ctx.Request.Context(), loginRequest.PassPhrase, loginRequest.TurnStile, loginRequest.IPAddress)
|
|
|
|
| 23 |
func (c *authenticationController) Register(ctx *gin.Context) {
|
| 24 |
var loginRequest models.LoginRequest
|
| 25 |
c.RequestJSON(ctx, loginRequest)
|
| 26 |
+
if loginRequest.IPAddress == "" {
|
| 27 |
loginRequest.IPAddress = ctx.ClientIP()
|
| 28 |
}
|
| 29 |
token := c.service.Register(ctx.Request.Context(), loginRequest.PassPhrase, loginRequest.TurnStile, loginRequest.IPAddress)
|
space/space/space/space/space/config/config.go
CHANGED
|
@@ -5,4 +5,5 @@ func RunConfig() {
|
|
| 5 |
InitializeDatabase()
|
| 6 |
InitializeOpenAIClient()
|
| 7 |
InitializeReplicateClient()
|
|
|
|
| 8 |
}
|
|
|
|
| 5 |
InitializeDatabase()
|
| 6 |
InitializeOpenAIClient()
|
| 7 |
InitializeReplicateClient()
|
| 8 |
+
InitTurnStileClient()
|
| 9 |
}
|
space/space/space/space/space/config/env_config.go
CHANGED
|
@@ -6,6 +6,7 @@ import (
|
|
| 6 |
|
| 7 |
"github.com/joho/godotenv"
|
| 8 |
)
|
|
|
|
| 9 |
var TCP_ADDRESS string
|
| 10 |
var LOG_PATH string
|
| 11 |
var HOST_ADDRESS string
|
|
@@ -13,6 +14,7 @@ var HOST_PORT string
|
|
| 13 |
var EMAIL_VERIFICATION_DURATION int
|
| 14 |
var OPEN_AI_API_KEY string
|
| 15 |
var REPLICATE_API_KEY string
|
|
|
|
| 16 |
|
| 17 |
func InitializeEnv() {
|
| 18 |
godotenv.Load()
|
|
@@ -23,4 +25,5 @@ func InitializeEnv() {
|
|
| 23 |
EMAIL_VERIFICATION_DURATION, _ = strconv.Atoi(os.Getenv("EMAIL_VERIFICATION_DURATION"))
|
| 24 |
OPEN_AI_API_KEY = os.Getenv("OPEN_AI_API_KEY")
|
| 25 |
REPLICATE_API_KEY = os.Getenv("REPLICATE_API_KEY")
|
| 26 |
-
|
|
|
|
|
|
| 6 |
|
| 7 |
"github.com/joho/godotenv"
|
| 8 |
)
|
| 9 |
+
|
| 10 |
var TCP_ADDRESS string
|
| 11 |
var LOG_PATH string
|
| 12 |
var HOST_ADDRESS string
|
|
|
|
| 14 |
var EMAIL_VERIFICATION_DURATION int
|
| 15 |
var OPEN_AI_API_KEY string
|
| 16 |
var REPLICATE_API_KEY string
|
| 17 |
+
var TURNSTILE_SECRET_KEY string
|
| 18 |
|
| 19 |
func InitializeEnv() {
|
| 20 |
godotenv.Load()
|
|
|
|
| 25 |
EMAIL_VERIFICATION_DURATION, _ = strconv.Atoi(os.Getenv("EMAIL_VERIFICATION_DURATION"))
|
| 26 |
OPEN_AI_API_KEY = os.Getenv("OPEN_AI_API_KEY")
|
| 27 |
REPLICATE_API_KEY = os.Getenv("REPLICATE_API_KEY")
|
| 28 |
+
TURNSTILE_SECRET_KEY = os.Getenv("TURNSTILE_SECRET_KEY")
|
| 29 |
+
}
|
space/space/space/space/space/config/turnstile_client_config.go
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package config
|
| 2 |
+
|
| 3 |
+
import "github.com/9ssi7/turnstile"
|
| 4 |
+
|
| 5 |
+
var TurnstileClient turnstile.Service
|
| 6 |
+
|
| 7 |
+
func InitTurnStileClient() {
|
| 8 |
+
TurnstileClient = turnstile.New(turnstile.Config{
|
| 9 |
+
Secret: TURNSTILE_SECRET_KEY,
|
| 10 |
+
})
|
| 11 |
+
}
|
space/space/space/space/space/controller/authentication_controller.go
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package controller
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 5 |
+
services "github.com/abdanhafidz/ai-visual-multi-modal-backend/services"
|
| 6 |
+
"github.com/gin-gonic/gin"
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
type AuhenticationController interface {
|
| 10 |
+
Controller
|
| 11 |
+
Login(ctx *gin.Context)
|
| 12 |
+
Register(ctx *gin.Context)
|
| 13 |
+
}
|
| 14 |
+
type authenticationController struct {
|
| 15 |
+
*controller[services.AuthenticationService]
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
func NewAuthenticationController(authenticationService services.AuthenticationService) AuhenticationController {
|
| 19 |
+
return &authenticationController{
|
| 20 |
+
controller: &controller[services.AuthenticationService]{service: authenticationService},
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
func (c *authenticationController) Register(ctx *gin.Context) {
|
| 24 |
+
var loginRequest models.LoginRequest
|
| 25 |
+
c.RequestJSON(ctx, loginRequest)
|
| 26 |
+
if (loginRequest.IPAddress == ""){
|
| 27 |
+
loginRequest.IPAddress = ctx.ClientIP()
|
| 28 |
+
}
|
| 29 |
+
token := c.service.Register(ctx.Request.Context(), loginRequest.PassPhrase, loginRequest.TurnStile, loginRequest.IPAddress)
|
| 30 |
+
|
| 31 |
+
c.Response(ctx, token)
|
| 32 |
+
}
|
| 33 |
+
func (c *authenticationController) Login(ctx *gin.Context) {
|
| 34 |
+
var loginRequest models.LoginRequest
|
| 35 |
+
c.RequestJSON(ctx, loginRequest)
|
| 36 |
+
|
| 37 |
+
token := c.service.Login(ctx.Request.Context(), loginRequest.PassPhrase)
|
| 38 |
+
|
| 39 |
+
c.Response(ctx, token)
|
| 40 |
+
}
|
space/space/space/space/space/factory/authentication_factory.go
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package factory
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/config"
|
| 5 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/controller"
|
| 6 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/repositories"
|
| 7 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/services"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func NewAuthenticationModule() controller.AuhenticationController {
|
| 11 |
+
accountRepository := repositories.NewAccountRepository(config.DB)
|
| 12 |
+
jwtService := services.NewJWTService(accountRepository, config.Salt)
|
| 13 |
+
authenticationService := services.NewAuthenticationService(accountRepository, config.TurnstileClient, jwtService)
|
| 14 |
+
authenticationController := controller.NewAuthenticationController(authenticationService)
|
| 15 |
+
return authenticationController
|
| 16 |
+
}
|
space/space/space/space/space/go.mod
CHANGED
|
@@ -14,6 +14,7 @@ require (
|
|
| 14 |
)
|
| 15 |
|
| 16 |
require (
|
|
|
|
| 17 |
github.com/bytedance/sonic v1.13.1 // indirect
|
| 18 |
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
| 19 |
github.com/cloudwego/base64x v0.1.5 // indirect
|
|
@@ -23,6 +24,8 @@ require (
|
|
| 23 |
github.com/go-playground/universal-translator v0.18.1 // indirect
|
| 24 |
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
| 25 |
github.com/goccy/go-json v0.10.5 // indirect
|
|
|
|
|
|
|
| 26 |
github.com/jackc/pgpassfile v1.0.0 // indirect
|
| 27 |
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
| 28 |
github.com/jackc/pgx/v5 v5.7.2 // indirect
|
|
|
|
| 14 |
)
|
| 15 |
|
| 16 |
require (
|
| 17 |
+
github.com/9ssi7/turnstile v1.0.0 // indirect
|
| 18 |
github.com/bytedance/sonic v1.13.1 // indirect
|
| 19 |
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
| 20 |
github.com/cloudwego/base64x v0.1.5 // indirect
|
|
|
|
| 24 |
github.com/go-playground/universal-translator v0.18.1 // indirect
|
| 25 |
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
| 26 |
github.com/goccy/go-json v0.10.5 // indirect
|
| 27 |
+
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
| 28 |
+
github.com/google/uuid v1.6.0 // indirect
|
| 29 |
github.com/jackc/pgpassfile v1.0.0 // indirect
|
| 30 |
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
| 31 |
github.com/jackc/pgx/v5 v5.7.2 // indirect
|
space/space/space/space/space/go.sum
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g=
|
| 2 |
github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
| 3 |
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
|
@@ -28,11 +30,15 @@ github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0
|
|
| 28 |
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
| 29 |
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
| 30 |
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
|
|
|
|
|
|
| 31 |
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
| 32 |
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
| 33 |
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
| 34 |
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
| 35 |
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
|
|
|
|
|
| 36 |
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
| 37 |
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
| 38 |
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
|
|
|
| 1 |
+
github.com/9ssi7/turnstile v1.0.0 h1:MDH8pXAbStCeH9Yul1MOIp0e4YKctpUXvcPEqKEUyZs=
|
| 2 |
+
github.com/9ssi7/turnstile v1.0.0/go.mod h1:R37Sy9c6VdYzQc0jr/hUojAdn3bYpeKaAoo9nUSqVSI=
|
| 3 |
github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g=
|
| 4 |
github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
| 5 |
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
|
|
|
| 30 |
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
| 31 |
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
| 32 |
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
| 33 |
+
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
| 34 |
+
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
| 35 |
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
| 36 |
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
| 37 |
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
| 38 |
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
| 39 |
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
| 40 |
+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
| 41 |
+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
| 42 |
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
| 43 |
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
| 44 |
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
space/space/space/space/space/middleware/authentication_middleware.go
CHANGED
|
@@ -3,13 +3,12 @@
|
|
| 3 |
package middleware
|
| 4 |
|
| 5 |
import (
|
| 6 |
-
"time"
|
| 7 |
-
|
| 8 |
config "github.com/abdanhafidz/ai-visual-multi-modal-backend/config"
|
| 9 |
models "github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
|
|
|
| 10 |
utils "github.com/abdanhafidz/ai-visual-multi-modal-backend/utils"
|
| 11 |
"github.com/gin-gonic/gin"
|
| 12 |
-
"github.com/golang-jwt/jwt/
|
| 13 |
)
|
| 14 |
|
| 15 |
var salt = config.Salt
|
|
@@ -17,54 +16,39 @@ var secretKey = []byte(salt)
|
|
| 17 |
|
| 18 |
// VerifyPassword verifies if the provided password matches the hashed password
|
| 19 |
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
return secretKey, nil
|
| 29 |
-
})
|
| 30 |
-
if err != nil {
|
| 31 |
-
return 0, "invalid-token", err
|
| 32 |
-
}
|
| 33 |
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
-
return claims.UserID, "valid", err
|
| 44 |
-
}
|
| 45 |
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
if currAccData.VerifyStatus == "invalid-token" || currAccData.VerifyStatus == "expired" {
|
| 53 |
-
currAccData.UserID = 0
|
| 54 |
-
utils.ResponseFAIL(c, 401, models.Exception{Unauthorized: true, Message: "Your session is expired, Please re-Login!"})
|
| 55 |
-
c.Abort()
|
| 56 |
return
|
| 57 |
-
} else {
|
| 58 |
-
c.Set("accountData", currAccData)
|
| 59 |
-
c.Next()
|
| 60 |
}
|
| 61 |
-
} else {
|
| 62 |
-
currAccData.UserID = 0
|
| 63 |
-
currAccData.VerifyStatus = "no-token"
|
| 64 |
-
currAccData.ErrVerif = nil
|
| 65 |
-
utils.ResponseFAIL(c, 401, models.Exception{Unauthorized: true, Message: "You have to login first!"})
|
| 66 |
-
c.Abort()
|
| 67 |
-
return
|
| 68 |
-
}
|
| 69 |
|
|
|
|
|
|
|
|
|
|
| 70 |
}
|
|
|
|
| 3 |
package middleware
|
| 4 |
|
| 5 |
import (
|
|
|
|
|
|
|
| 6 |
config "github.com/abdanhafidz/ai-visual-multi-modal-backend/config"
|
| 7 |
models "github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 8 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/services"
|
| 9 |
utils "github.com/abdanhafidz/ai-visual-multi-modal-backend/utils"
|
| 10 |
"github.com/gin-gonic/gin"
|
| 11 |
+
"github.com/golang-jwt/jwt/v4"
|
| 12 |
)
|
| 13 |
|
| 14 |
var salt = config.Salt
|
|
|
|
| 16 |
|
| 17 |
// VerifyPassword verifies if the provided password matches the hashed password
|
| 18 |
|
| 19 |
+
func AuthenticationMiddleware(jwtService services.JWTService) gin.HandlerFunc {
|
| 20 |
+
return func(c *gin.Context) {
|
| 21 |
+
tokenString := c.GetHeader("Authorization")
|
| 22 |
+
if tokenString == "" {
|
| 23 |
+
utils.ResponseFAIL(c, 401, models.Exception{
|
| 24 |
+
Unauthorized: true,
|
| 25 |
+
Message: "You Have To Login First!",
|
| 26 |
+
})
|
| 27 |
+
return
|
| 28 |
+
}
|
| 29 |
|
| 30 |
+
token, err := jwt.ParseWithClaims(tokenString, &models.JWTCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
| 31 |
+
return secretKey, nil
|
| 32 |
+
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
+
if err != nil || !token.Valid {
|
| 35 |
+
utils.ResponseFAIL(c, 401, models.Exception{
|
| 36 |
+
Unauthorized: true,
|
| 37 |
+
Message: "Invalid Authorization Token!",
|
| 38 |
+
})
|
| 39 |
+
return
|
| 40 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
+
claims, ok := token.Claims.(*models.JWTCustomClaims)
|
| 43 |
+
if !ok {
|
| 44 |
+
utils.ResponseFAIL(c, 401, models.Exception{
|
| 45 |
+
Unauthorized: true,
|
| 46 |
+
Message: "Invalid Authorization Token!",
|
| 47 |
+
})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
return
|
|
|
|
|
|
|
|
|
|
| 49 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
+
c.Set("user_id", claims.IdUser)
|
| 52 |
+
c.Next()
|
| 53 |
+
}
|
| 54 |
}
|
space/space/space/space/space/models/authentication_dto.go
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
package models
|
| 2 |
|
| 3 |
type LoginRequest struct {
|
| 4 |
-
PassPhrase string `json:"pass_phrase binding:"required"`
|
| 5 |
-
TurnStile string `json:"turnstile_payload binding:"required"`
|
|
|
|
| 6 |
}
|
|
|
|
| 1 |
package models
|
| 2 |
|
| 3 |
type LoginRequest struct {
|
| 4 |
+
PassPhrase string `json:"pass_phrase" binding:"required"`
|
| 5 |
+
TurnStile string `json:"turnstile_payload" binding:"required"`
|
| 6 |
+
IPAddress string `json:"ip_address"`
|
| 7 |
}
|
space/space/space/space/space/models/authentication_payload_model.go
CHANGED
|
@@ -1,7 +1,15 @@
|
|
| 1 |
package models
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
type AccountData struct {
|
| 4 |
-
|
| 5 |
-
VerifyStatus string
|
| 6 |
-
ErrVerif error
|
| 7 |
}
|
|
|
|
| 1 |
package models
|
| 2 |
|
| 3 |
+
import (
|
| 4 |
+
"github.com/golang-jwt/jwt/v4"
|
| 5 |
+
uuid "github.com/satori/go.uuid"
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
type JWTCustomClaims struct {
|
| 9 |
+
IdUser uuid.UUID `json:"user_id" binding:"required"`
|
| 10 |
+
jwt.RegisteredClaims
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
type AccountData struct {
|
| 14 |
+
IdUser uuid.UUID `json:"user_id" binding:"required"`
|
|
|
|
|
|
|
| 15 |
}
|
space/space/space/space/space/models/entities_model.go
CHANGED
|
@@ -7,10 +7,10 @@ import (
|
|
| 7 |
)
|
| 8 |
|
| 9 |
type Account struct {
|
| 10 |
-
ID
|
| 11 |
-
|
| 12 |
-
CreatedAt
|
| 13 |
-
DeletedAt
|
| 14 |
}
|
| 15 |
|
| 16 |
type ChatHistory struct {
|
|
|
|
| 7 |
)
|
| 8 |
|
| 9 |
type Account struct {
|
| 10 |
+
ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
|
| 11 |
+
PassPhrase string `gorm:"not null;"`
|
| 12 |
+
CreatedAt time.Time
|
| 13 |
+
DeletedAt *time.Time `gorm:"column:deleted_at"` // perhatikan penamaan kolom
|
| 14 |
}
|
| 15 |
|
| 16 |
type ChatHistory struct {
|
space/space/space/space/space/models/exception_model.go
CHANGED
|
@@ -12,5 +12,5 @@ type Exception struct {
|
|
| 12 |
ReplicateConnectionRefused bool `json:"replicated_connection_refused,omitempty"`
|
| 13 |
AudioFileError bool `json:"audio_file_error,omitempty"`
|
| 14 |
FailedGenerateAudio bool `json:"audio_generation_failed,omitempty"`
|
| 15 |
-
Message string `json:"message"`
|
| 16 |
}
|
|
|
|
| 12 |
ReplicateConnectionRefused bool `json:"replicated_connection_refused,omitempty"`
|
| 13 |
AudioFileError bool `json:"audio_file_error,omitempty"`
|
| 14 |
FailedGenerateAudio bool `json:"audio_generation_failed,omitempty"`
|
| 15 |
+
Message string `json:"message,omitempty"`
|
| 16 |
}
|
space/space/space/space/space/models/http_response_dto_model.go
CHANGED
|
@@ -2,7 +2,7 @@ package models
|
|
| 2 |
|
| 3 |
type SuccessResponse struct {
|
| 4 |
Status string `json:"status"`
|
| 5 |
-
Message string `json:"message"`
|
| 6 |
Data any `json:"data"`
|
| 7 |
MetaData any `json:"meta_data"`
|
| 8 |
}
|
|
|
|
| 2 |
|
| 3 |
type SuccessResponse struct {
|
| 4 |
Status string `json:"status"`
|
| 5 |
+
Message string `json:"message,omitempty"`
|
| 6 |
Data any `json:"data"`
|
| 7 |
MetaData any `json:"meta_data"`
|
| 8 |
}
|
space/space/space/space/space/repositories/account_repository.go
CHANGED
|
@@ -4,26 +4,36 @@ import (
|
|
| 4 |
"context"
|
| 5 |
|
| 6 |
"github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
|
|
|
| 7 |
)
|
| 8 |
|
| 9 |
type AccountRepository interface {
|
| 10 |
Repository
|
| 11 |
CreateAccount(ctx context.Context, fingerPrint string) (res models.Account)
|
| 12 |
-
|
| 13 |
}
|
| 14 |
|
| 15 |
type accountRepository struct {
|
| 16 |
-
repository[models.Account]
|
| 17 |
}
|
| 18 |
|
| 19 |
-
func (
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
r.Create(ctx)
|
| 22 |
return r.entity
|
| 23 |
}
|
| 24 |
|
| 25 |
-
func (r *accountRepository)
|
| 26 |
-
r.entity.
|
| 27 |
r.Where(ctx)
|
| 28 |
r.Find(ctx, res)
|
| 29 |
return res
|
|
|
|
| 4 |
"context"
|
| 5 |
|
| 6 |
"github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 7 |
+
"gorm.io/gorm"
|
| 8 |
)
|
| 9 |
|
| 10 |
type AccountRepository interface {
|
| 11 |
Repository
|
| 12 |
CreateAccount(ctx context.Context, fingerPrint string) (res models.Account)
|
| 13 |
+
GetAccountByPassPhrase(ctx context.Context, fingePrint string) (res models.Account)
|
| 14 |
}
|
| 15 |
|
| 16 |
type accountRepository struct {
|
| 17 |
+
*repository[models.Account]
|
| 18 |
}
|
| 19 |
|
| 20 |
+
func NewAccountRepository(db *gorm.DB) AccountRepository {
|
| 21 |
+
return &accountRepository{
|
| 22 |
+
repository: &repository[models.Account]{
|
| 23 |
+
entity: models.Account{},
|
| 24 |
+
transaction: db,
|
| 25 |
+
},
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
func (r *accountRepository) CreateAccount(ctx context.Context, passPhrase string) (res models.Account) {
|
| 30 |
+
r.entity.PassPhrase = passPhrase
|
| 31 |
r.Create(ctx)
|
| 32 |
return r.entity
|
| 33 |
}
|
| 34 |
|
| 35 |
+
func (r *accountRepository) GetAccountByPassPhrase(ctx context.Context, passPhrase string) (res models.Account) {
|
| 36 |
+
r.entity.PassPhrase = passPhrase
|
| 37 |
r.Where(ctx)
|
| 38 |
r.Find(ctx, res)
|
| 39 |
return res
|
space/space/space/space/space/router/authentication_route.go
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package router
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
factory "github.com/abdanhafidz/ai-visual-multi-modal-backend/factory"
|
| 5 |
+
"github.com/gin-gonic/gin"
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
func AuthenticationRoute(router *gin.Engine) {
|
| 9 |
+
routerGroup := router.Group("/api/v1")
|
| 10 |
+
{
|
| 11 |
+
routerGroup.POST("/register", func(c *gin.Context) {
|
| 12 |
+
authenticationModule := factory.NewAuthenticationModule()
|
| 13 |
+
authenticationModule.Register(c)
|
| 14 |
+
})
|
| 15 |
+
routerGroup.POST("/login", func(c *gin.Context) {
|
| 16 |
+
authenticationModule := factory.NewAuthenticationModule()
|
| 17 |
+
authenticationModule.Login(c)
|
| 18 |
+
})
|
| 19 |
+
}
|
| 20 |
+
}
|
space/space/space/space/space/router/router.go
CHANGED
|
@@ -10,5 +10,6 @@ func StartService() {
|
|
| 10 |
router := gin.Default()
|
| 11 |
router.GET("/", controller.HomeController)
|
| 12 |
PredictionRoute(router)
|
|
|
|
| 13 |
router.Run(config.TCP_ADDRESS)
|
| 14 |
}
|
|
|
|
| 10 |
router := gin.Default()
|
| 11 |
router.GET("/", controller.HomeController)
|
| 12 |
PredictionRoute(router)
|
| 13 |
+
AuthenticationRoute(router)
|
| 14 |
router.Run(config.TCP_ADDRESS)
|
| 15 |
}
|
space/space/space/space/space/services/authentication_service.go
CHANGED
|
@@ -1,11 +1,76 @@
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
type AuthenticationService interface {
|
| 6 |
-
|
| 7 |
-
|
|
|
|
| 8 |
}
|
| 9 |
|
| 10 |
type authenticationService struct {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
}
|
|
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
+
import (
|
| 4 |
+
"context"
|
| 5 |
+
|
| 6 |
+
"github.com/9ssi7/turnstile"
|
| 7 |
+
models "github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 8 |
+
"github.com/abdanhafidz/ai-visual-multi-modal-backend/repositories"
|
| 9 |
+
)
|
| 10 |
|
| 11 |
type AuthenticationService interface {
|
| 12 |
+
Service
|
| 13 |
+
Register(ctx context.Context, passPhrase string, turnstile string, ip string) string
|
| 14 |
+
Login(ctx context.Context, passPhrase string) string
|
| 15 |
}
|
| 16 |
|
| 17 |
type authenticationService struct {
|
| 18 |
+
*service[repositories.AccountRepository]
|
| 19 |
+
turnStileClient turnstile.Service
|
| 20 |
+
jwtService JWTService
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
func NewAuthenticationService(accountRepository repositories.AccountRepository, turnStileClient turnstile.Service, jwtService JWTService) AuthenticationService {
|
| 24 |
+
return &authenticationService{
|
| 25 |
+
service: &service[repositories.AccountRepository]{repository: accountRepository},
|
| 26 |
+
turnStileClient: turnStileClient,
|
| 27 |
+
jwtService: jwtService,
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
func (s *authenticationService) Register(ctx context.Context, passPhrase string, turnstile string, ip string) string {
|
| 31 |
+
verifiedTurnStile, err := s.turnStileClient.Verify(ctx, turnstile, ip)
|
| 32 |
+
|
| 33 |
+
if err != nil {
|
| 34 |
+
s.ThrowsException(&s.exception.Unauthorized, "Turnstile error!")
|
| 35 |
+
return ""
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
if verifiedTurnStile {
|
| 39 |
+
account := s.repository.CreateAccount(ctx, passPhrase)
|
| 40 |
+
if s.ThrowsRepoException() {
|
| 41 |
+
return ""
|
| 42 |
+
}
|
| 43 |
+
token := s.jwtService.GenerateToken(ctx, models.JWTCustomClaims{IdUser: account.ID})
|
| 44 |
+
if s.jwtService.Error() != nil {
|
| 45 |
+
s.ThrowsException(&s.exception.Unauthorized, "JWTService Error")
|
| 46 |
+
s.ThrowsError(s.jwtService.Error())
|
| 47 |
+
return ""
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
return token
|
| 51 |
+
} else {
|
| 52 |
+
s.ThrowsException(&s.exception.Unauthorized, "Invalid turnstile payload!")
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
return ""
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
func (s *authenticationService) Login(ctx context.Context, passPhrase string) string {
|
| 59 |
+
account := s.repository.GetAccountByPassPhrase(ctx, passPhrase)
|
| 60 |
+
if s.ThrowsRepoException() {
|
| 61 |
+
return ""
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
if s.repository.IsNoRecord() {
|
| 65 |
+
s.ThrowsException(&s.exception.Unauthorized, "Account not found!")
|
| 66 |
+
return " "
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
token := s.jwtService.GenerateToken(ctx, models.JWTCustomClaims{IdUser: account.ID})
|
| 70 |
+
if s.jwtService.Error() != nil {
|
| 71 |
+
s.ThrowsException(&s.exception.Unauthorized, "JWTService Error")
|
| 72 |
+
s.ThrowsError(s.jwtService.Error())
|
| 73 |
+
return ""
|
| 74 |
+
}
|
| 75 |
+
return token
|
| 76 |
}
|
space/space/space/space/space/services/jwt_service.go
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package services
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"context"
|
| 5 |
+
|
| 6 |
+
models "github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 7 |
+
repositories "github.com/abdanhafidz/ai-visual-multi-modal-backend/repositories"
|
| 8 |
+
"github.com/golang-jwt/jwt/v4"
|
| 9 |
+
uuid "github.com/satori/go.uuid"
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
type JWTService interface {
|
| 13 |
+
Service
|
| 14 |
+
GenerateToken(ctx context.Context, payload models.JWTCustomClaims) string
|
| 15 |
+
ValidateToken(ctx context.Context, tokenStr string) *models.JWTCustomClaims
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
type jwtService struct {
|
| 19 |
+
*service[repositories.AccountRepository]
|
| 20 |
+
secretKey string
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
func NewJWTService(repo repositories.AccountRepository, secretKey string) JWTService {
|
| 24 |
+
return &jwtService{
|
| 25 |
+
service: &service[repositories.AccountRepository]{repository: repo},
|
| 26 |
+
secretKey: secretKey,
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
func (s *jwtService) GenerateToken(ctx context.Context, payload models.JWTCustomClaims) string {
|
| 30 |
+
claims := jwt.MapClaims{
|
| 31 |
+
"user_id": payload.IdUser,
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
| 35 |
+
tokenStr, err := token.SignedString([]byte(s.secretKey))
|
| 36 |
+
if err != nil {
|
| 37 |
+
s.ThrowsException(&s.exception.Unauthorized, "Failed to generate JWT token!")
|
| 38 |
+
s.ThrowsError(err)
|
| 39 |
+
return ""
|
| 40 |
+
}
|
| 41 |
+
return tokenStr
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
func (s *jwtService) ValidateToken(ctx context.Context, tokenStr string) *models.JWTCustomClaims {
|
| 45 |
+
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
|
| 46 |
+
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
| 47 |
+
s.ThrowsException(&s.exception.Unauthorized, "Unexpected signing method")
|
| 48 |
+
return nil, jwt.ErrSignatureInvalid
|
| 49 |
+
}
|
| 50 |
+
return []byte(s.secretKey), nil
|
| 51 |
+
})
|
| 52 |
+
|
| 53 |
+
if err != nil || !token.Valid {
|
| 54 |
+
s.ThrowsException(&s.exception.Unauthorized, "Invalid token!")
|
| 55 |
+
s.ThrowsError(err)
|
| 56 |
+
return nil
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
claims, ok := token.Claims.(jwt.MapClaims)
|
| 60 |
+
if !ok {
|
| 61 |
+
s.ThrowsException(&s.exception.Unauthorized, "Invalid token claims")
|
| 62 |
+
return nil
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
return &models.JWTCustomClaims{
|
| 66 |
+
IdUser: claims["user_id"].(uuid.UUID),
|
| 67 |
+
}
|
| 68 |
+
}
|
space/space/space/space/space/space/services/openai_service.go
CHANGED
|
@@ -61,7 +61,6 @@ func (s *openAIService) SpeechToText(ctx context.Context, audioFile multipart.Fi
|
|
| 61 |
|
| 62 |
req := openai.AudioRequest{
|
| 63 |
Model: openai.Whisper1,
|
| 64 |
-
Prompt: "please give it on summarized information",
|
| 65 |
FilePath: savedPath,
|
| 66 |
}
|
| 67 |
|
|
|
|
| 61 |
|
| 62 |
req := openai.AudioRequest{
|
| 63 |
Model: openai.Whisper1,
|
|
|
|
| 64 |
FilePath: savedPath,
|
| 65 |
}
|
| 66 |
|
space/space/space/space/space/space/space/controller/prediction_controller.go
CHANGED
|
@@ -76,7 +76,13 @@ func NewPredictionController(predictionService services.PredictionService) Predi
|
|
| 76 |
func (c *predictionController) Predict(ctx *gin.Context) {
|
| 77 |
|
| 78 |
var predictionRequest models.PredictionRequest
|
| 79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
requestImage(ctx, &predictionRequest.ImageFile, &predictionRequest.ImageFileName)
|
| 81 |
requestAudio(ctx, &predictionRequest.AudioQuestionFile, &predictionRequest.AudioQuestionFilename)
|
| 82 |
|
|
|
|
| 76 |
func (c *predictionController) Predict(ctx *gin.Context) {
|
| 77 |
|
| 78 |
var predictionRequest models.PredictionRequest
|
| 79 |
+
if err := ctx.ShouldBind(&predictionRequest); err != nil {
|
| 80 |
+
utils.ResponseFAIL(ctx, 400, models.Exception{
|
| 81 |
+
BadRequest: true,
|
| 82 |
+
Message: "Invalid request format",
|
| 83 |
+
})
|
| 84 |
+
return
|
| 85 |
+
}
|
| 86 |
requestImage(ctx, &predictionRequest.ImageFile, &predictionRequest.ImageFileName)
|
| 87 |
requestAudio(ctx, &predictionRequest.AudioQuestionFile, &predictionRequest.AudioQuestionFilename)
|
| 88 |
|
space/space/space/space/space/space/space/services/openai_service.go
CHANGED
|
@@ -61,6 +61,7 @@ func (s *openAIService) SpeechToText(ctx context.Context, audioFile multipart.Fi
|
|
| 61 |
|
| 62 |
req := openai.AudioRequest{
|
| 63 |
Model: openai.Whisper1,
|
|
|
|
| 64 |
FilePath: savedPath,
|
| 65 |
}
|
| 66 |
|
|
|
|
| 61 |
|
| 62 |
req := openai.AudioRequest{
|
| 63 |
Model: openai.Whisper1,
|
| 64 |
+
Prompt: "please give it on summarized information",
|
| 65 |
FilePath: savedPath,
|
| 66 |
}
|
| 67 |
|
space/space/space/space/space/space/space/space/.github/workflows/deploy.yml
CHANGED
|
@@ -1,9 +1,10 @@
|
|
| 1 |
name: Deploy to Huggingface
|
| 2 |
|
| 3 |
on:
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
|
|
|
| 7 |
|
| 8 |
jobs:
|
| 9 |
deploy-to-huggingface:
|
|
|
|
| 1 |
name: Deploy to Huggingface
|
| 2 |
|
| 3 |
on:
|
| 4 |
+
workflow_run:
|
| 5 |
+
workflows: ["Go Regression Testing"]
|
| 6 |
+
types:
|
| 7 |
+
- completed
|
| 8 |
|
| 9 |
jobs:
|
| 10 |
deploy-to-huggingface:
|
space/space/space/space/space/space/space/space/.github/workflows/go.yml
CHANGED
|
@@ -1,7 +1,4 @@
|
|
| 1 |
-
|
| 2 |
-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
| 3 |
-
|
| 4 |
-
name: Go
|
| 5 |
|
| 6 |
on:
|
| 7 |
push:
|
|
@@ -10,19 +7,37 @@ on:
|
|
| 10 |
branches: [ "main" ]
|
| 11 |
|
| 12 |
jobs:
|
| 13 |
-
|
| 14 |
build:
|
| 15 |
runs-on: ubuntu-latest
|
|
|
|
| 16 |
steps:
|
| 17 |
- uses: actions/checkout@v4
|
| 18 |
|
| 19 |
- name: Set up Go
|
| 20 |
uses: actions/setup-go@v4
|
| 21 |
with:
|
| 22 |
-
go-version: '1.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
- name: Build
|
| 25 |
run: go build -v ./...
|
| 26 |
|
| 27 |
- name: Test
|
| 28 |
-
run: go test -v ./
|
|
|
|
| 1 |
+
name: Go Regression Testing
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
on:
|
| 4 |
push:
|
|
|
|
| 7 |
branches: [ "main" ]
|
| 8 |
|
| 9 |
jobs:
|
|
|
|
| 10 |
build:
|
| 11 |
runs-on: ubuntu-latest
|
| 12 |
+
|
| 13 |
steps:
|
| 14 |
- uses: actions/checkout@v4
|
| 15 |
|
| 16 |
- name: Set up Go
|
| 17 |
uses: actions/setup-go@v4
|
| 18 |
with:
|
| 19 |
+
go-version: '1.24.0'
|
| 20 |
+
|
| 21 |
+
- name: Create .env files from secrets
|
| 22 |
+
run: |
|
| 23 |
+
ENV_CONTENT="DB_HOST=${{ secrets.DB_HOST }}
|
| 24 |
+
DB_USER=${{ secrets.DB_USER }}
|
| 25 |
+
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
|
| 26 |
+
DB_PORT=${{ secrets.DB_PORT }}
|
| 27 |
+
DB_NAME=${{ secrets.DB_NAME }}
|
| 28 |
+
SALT=akunakpacarCHINDOFineshyt
|
| 29 |
+
HOST_ADDRESS=localhost
|
| 30 |
+
HOST_PORT=8080
|
| 31 |
+
LOG_PATH=logs
|
| 32 |
+
EMAIL_VERIFICATION_DURATION=2
|
| 33 |
+
OPEN_AI_API_KEY=${{ secrets.OPEN_AI_API_KEY }}
|
| 34 |
+
REPLICATE_API_TOKEN=${{ secrets.REPLICATE_API_TOKEN }}"
|
| 35 |
+
|
| 36 |
+
echo "$ENV_CONTENT" > .env
|
| 37 |
+
echo "$ENV_CONTENT" > tests/.env
|
| 38 |
|
| 39 |
- name: Build
|
| 40 |
run: go build -v ./...
|
| 41 |
|
| 42 |
- name: Test
|
| 43 |
+
run: go test -v -timeout 300s ./tests
|
space/space/space/space/space/space/space/space/Dockerfile
CHANGED
|
@@ -34,9 +34,9 @@ RUN --mount=type=secret,id=DB_PASSWORD,mode=0444,required=false \
|
|
| 34 |
echo "REPLICATE_API_TOKEN=$(cat /run/secrets/REPLICATE_API_TOKEN 2>/dev/null)" >> .env
|
| 35 |
|
| 36 |
# Buat direktori audio dan logs, beri izin dan kepemilikan ke appuser
|
| 37 |
-
RUN mkdir -p /app/
|
| 38 |
-
chmod -R 777 /app/
|
| 39 |
-
chown -R appuser:appuser /app/
|
| 40 |
|
| 41 |
# Build aplikasi
|
| 42 |
RUN go build -o main .
|
|
|
|
| 34 |
echo "REPLICATE_API_TOKEN=$(cat /run/secrets/REPLICATE_API_TOKEN 2>/dev/null)" >> .env
|
| 35 |
|
| 36 |
# Buat direktori audio dan logs, beri izin dan kepemilikan ke appuser
|
| 37 |
+
RUN mkdir -p /app/images /app/logs /app/audio && \
|
| 38 |
+
chmod -R 777 /app/images /app/logs /app/audio && \
|
| 39 |
+
chown -R appuser:appuser /app/images /app/logs /app/audio
|
| 40 |
|
| 41 |
# Build aplikasi
|
| 42 |
RUN go build -o main .
|
space/space/space/space/space/space/space/space/config/config.go
CHANGED
|
@@ -1,27 +1,8 @@
|
|
| 1 |
package config
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
)
|
| 9 |
-
|
| 10 |
-
var TCP_ADDRESS string
|
| 11 |
-
var LOG_PATH string
|
| 12 |
-
var HOST_ADDRESS string
|
| 13 |
-
var HOST_PORT string
|
| 14 |
-
var EMAIL_VERIFICATION_DURATION int
|
| 15 |
-
var OPEN_AI_API_KEY string
|
| 16 |
-
var REPLICATE_API_KEY string
|
| 17 |
-
|
| 18 |
-
func init() {
|
| 19 |
-
godotenv.Load()
|
| 20 |
-
HOST_ADDRESS = os.Getenv("HOST_ADDRESS")
|
| 21 |
-
HOST_PORT = os.Getenv("HOST_PORT")
|
| 22 |
-
TCP_ADDRESS = HOST_ADDRESS + ":" + HOST_PORT
|
| 23 |
-
LOG_PATH = os.Getenv("LOG_PATH")
|
| 24 |
-
EMAIL_VERIFICATION_DURATION, _ = strconv.Atoi(os.Getenv("EMAIL_VERIFICATION_DURATION"))
|
| 25 |
-
OPEN_AI_API_KEY = os.Getenv("OPEN_AI_API_KEY")
|
| 26 |
-
REPLICATE_API_KEY = os.Getenv("REPLICATE_API_KEY")
|
| 27 |
}
|
|
|
|
| 1 |
package config
|
| 2 |
|
| 3 |
+
func RunConfig() {
|
| 4 |
+
InitializeEnv()
|
| 5 |
+
InitializeDatabase()
|
| 6 |
+
InitializeOpenAIClient()
|
| 7 |
+
InitializeReplicateClient()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
}
|
space/space/space/space/space/space/space/space/config/database_connection_config.go
CHANGED
|
@@ -17,7 +17,7 @@ var DB *gorm.DB
|
|
| 17 |
var err error
|
| 18 |
var Salt string
|
| 19 |
|
| 20 |
-
func
|
| 21 |
godotenv.Load()
|
| 22 |
if err != nil {
|
| 23 |
fmt.Println("Gagal membaca file .env")
|
|
|
|
| 17 |
var err error
|
| 18 |
var Salt string
|
| 19 |
|
| 20 |
+
func InitializeDatabase() {
|
| 21 |
godotenv.Load()
|
| 22 |
if err != nil {
|
| 23 |
fmt.Println("Gagal membaca file .env")
|
space/space/space/space/space/space/space/space/config/env_config.go
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package config
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"os"
|
| 5 |
+
"strconv"
|
| 6 |
+
|
| 7 |
+
"github.com/joho/godotenv"
|
| 8 |
+
)
|
| 9 |
+
var TCP_ADDRESS string
|
| 10 |
+
var LOG_PATH string
|
| 11 |
+
var HOST_ADDRESS string
|
| 12 |
+
var HOST_PORT string
|
| 13 |
+
var EMAIL_VERIFICATION_DURATION int
|
| 14 |
+
var OPEN_AI_API_KEY string
|
| 15 |
+
var REPLICATE_API_KEY string
|
| 16 |
+
|
| 17 |
+
func InitializeEnv() {
|
| 18 |
+
godotenv.Load()
|
| 19 |
+
HOST_ADDRESS = os.Getenv("HOST_ADDRESS")
|
| 20 |
+
HOST_PORT = os.Getenv("HOST_PORT")
|
| 21 |
+
TCP_ADDRESS = HOST_ADDRESS + ":" + HOST_PORT
|
| 22 |
+
LOG_PATH = os.Getenv("LOG_PATH")
|
| 23 |
+
EMAIL_VERIFICATION_DURATION, _ = strconv.Atoi(os.Getenv("EMAIL_VERIFICATION_DURATION"))
|
| 24 |
+
OPEN_AI_API_KEY = os.Getenv("OPEN_AI_API_KEY")
|
| 25 |
+
REPLICATE_API_KEY = os.Getenv("REPLICATE_API_KEY")
|
| 26 |
+
}
|
space/space/space/space/space/space/space/space/config/openai_client_config.go
CHANGED
|
@@ -6,6 +6,6 @@ import (
|
|
| 6 |
|
| 7 |
var OpenAIClient *openai.Client
|
| 8 |
|
| 9 |
-
func
|
| 10 |
OpenAIClient = openai.NewClient(OPEN_AI_API_KEY)
|
| 11 |
}
|
|
|
|
| 6 |
|
| 7 |
var OpenAIClient *openai.Client
|
| 8 |
|
| 9 |
+
func InitializeOpenAIClient() {
|
| 10 |
OpenAIClient = openai.NewClient(OPEN_AI_API_KEY)
|
| 11 |
}
|
space/space/space/space/space/space/space/space/config/replicate_client_config.go
CHANGED
|
@@ -6,7 +6,7 @@ import (
|
|
| 6 |
|
| 7 |
var ReplicateClient *replicate.Client
|
| 8 |
|
| 9 |
-
func
|
| 10 |
ReplicateClient, err = replicate.NewClient(replicate.WithTokenFromEnv())
|
| 11 |
if err != nil {
|
| 12 |
panic(err)
|
|
|
|
| 6 |
|
| 7 |
var ReplicateClient *replicate.Client
|
| 8 |
|
| 9 |
+
func InitializeReplicateClient() {
|
| 10 |
ReplicateClient, err = replicate.NewClient(replicate.WithTokenFromEnv())
|
| 11 |
if err != nil {
|
| 12 |
panic(err)
|
space/space/space/space/space/space/space/space/factory/prediction_factory.go
CHANGED
|
@@ -8,11 +8,21 @@ import (
|
|
| 8 |
)
|
| 9 |
|
| 10 |
func NewPredictionModule() controller.PredictionController {
|
| 11 |
-
chatHistoryRepository := repositories.NewChatHistoryRepository()
|
| 12 |
-
openAIService := services.NewOpenAIService(
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
predictionController := controller.NewPredictionController(predictionService)
|
| 16 |
-
|
| 17 |
return predictionController
|
| 18 |
}
|
|
|
|
| 8 |
)
|
| 9 |
|
| 10 |
func NewPredictionModule() controller.PredictionController {
|
| 11 |
+
chatHistoryRepository := repositories.NewChatHistoryRepository(config.DB)
|
| 12 |
+
openAIService := services.NewOpenAIService(
|
| 13 |
+
chatHistoryRepository,
|
| 14 |
+
config.OpenAIClient,
|
| 15 |
+
)
|
| 16 |
+
replicateService := services.NewReplicateService(
|
| 17 |
+
chatHistoryRepository,
|
| 18 |
+
config.ReplicateClient,
|
| 19 |
+
"spuuntries/urna-kp3l:9338a4573a17178b70515c0ef2e613d3b4213e2dc860ef23b3ad6149dacadc1e",
|
| 20 |
+
)
|
| 21 |
+
predictionService := services.NewPredictionService(
|
| 22 |
+
chatHistoryRepository,
|
| 23 |
+
replicateService,
|
| 24 |
+
openAIService,
|
| 25 |
+
)
|
| 26 |
predictionController := controller.NewPredictionController(predictionService)
|
|
|
|
| 27 |
return predictionController
|
| 28 |
}
|
space/space/space/space/space/space/space/space/images/foto-pacarku.jpg
ADDED
|
space/space/space/space/space/space/space/space/images/foto_pacarku.jpg
ADDED
|
space/space/space/space/space/space/space/space/logs/error_log.txt
CHANGED
|
@@ -24,3 +24,11 @@ duplicated key not allowed; invalid transaction; invalid transaction; invalid tr
|
|
| 24 |
2025/06/21 21:27:10 Error Log : duplicated key not allowed; invalid transaction
|
| 25 |
2025/06/21 21:48:34 Error Log : duplicated key not allowed; invalid transaction
|
| 26 |
duplicated key not allowed; invalid transaction; invalid transaction; invalid transaction
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
2025/06/21 21:27:10 Error Log : duplicated key not allowed; invalid transaction
|
| 25 |
2025/06/21 21:48:34 Error Log : duplicated key not allowed; invalid transaction
|
| 26 |
duplicated key not allowed; invalid transaction; invalid transaction; invalid transaction
|
| 27 |
+
2025/06/22 18:15:55 Error Log : remove audio\20250616_235223.mp3: The process cannot access the file because it is being used by another process.
|
| 28 |
+
2025/06/22 18:16:19 Error Log : remove audio\20250616_235223.mp3: The process cannot access the file because it is being used by another process.
|
| 29 |
+
2025/06/22 18:19:01 Error Log : open ./images/foto-pacarku.jpg: The system cannot find the path specified.
|
| 30 |
+
2025/06/22 21:51:05 Error Log : error, status code: 400, status: 400 Bad Request, message: Invalid file format. Supported formats: ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm']
|
| 31 |
+
2025/06/22 22:06:00 Error Log : error, status code: 400, status: 400 Bad Request, message: Invalid file format. Supported formats: ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm']
|
| 32 |
+
2025/06/22 22:06:37 Error Log : error, status code: 400, status: 400 Bad Request, message: Invalid file format. Supported formats: ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm']
|
| 33 |
+
2025/06/23 15:09:33 Error Log : error, status code: 400, status: 400 Bad Request, message: Invalid file format. Supported formats: ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm']
|
| 34 |
+
2025/06/23 21:55:35 Error Log : error, status code: 400, status: 400 Bad Request, message: Invalid file format. Supported formats: ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm']
|
space/space/space/space/space/space/space/space/main.go
CHANGED
|
@@ -8,6 +8,7 @@ import (
|
|
| 8 |
)
|
| 9 |
|
| 10 |
func main() {
|
|
|
|
| 11 |
fmt.Println("Server started on ", config.TCP_ADDRESS, ", port :", config.HOST_PORT)
|
| 12 |
router.StartService()
|
| 13 |
|
|
|
|
| 8 |
)
|
| 9 |
|
| 10 |
func main() {
|
| 11 |
+
config.RunConfig()
|
| 12 |
fmt.Println("Server started on ", config.TCP_ADDRESS, ", port :", config.HOST_PORT)
|
| 13 |
router.StartService()
|
| 14 |
|
space/space/space/space/space/space/space/space/models/authentication_dto.go
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
package models
|
| 2 |
|
| 3 |
type LoginRequest struct {
|
| 4 |
-
|
|
|
|
| 5 |
}
|
|
|
|
| 1 |
package models
|
| 2 |
|
| 3 |
type LoginRequest struct {
|
| 4 |
+
PassPhrase string `json:"pass_phrase binding:"required"`
|
| 5 |
+
TurnStile string `json:"turnstile_payload binding:"required"`
|
| 6 |
}
|
space/space/space/space/space/space/space/space/repositories/chat_history_repository.go
CHANGED
|
@@ -3,8 +3,8 @@ package repositories
|
|
| 3 |
import (
|
| 4 |
"context"
|
| 5 |
|
| 6 |
-
"github.com/abdanhafidz/ai-visual-multi-modal-backend/config"
|
| 7 |
"github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
|
|
|
| 8 |
)
|
| 9 |
|
| 10 |
type ChatHistoryRepository interface {
|
|
@@ -13,13 +13,14 @@ type ChatHistoryRepository interface {
|
|
| 13 |
}
|
| 14 |
|
| 15 |
type chatHistoryRepository struct {
|
| 16 |
-
repository[models.ChatHistory]
|
| 17 |
}
|
| 18 |
|
| 19 |
-
func NewChatHistoryRepository() ChatHistoryRepository {
|
| 20 |
return &chatHistoryRepository{
|
| 21 |
-
repository: repository[models.ChatHistory]{
|
| 22 |
-
|
|
|
|
| 23 |
},
|
| 24 |
}
|
| 25 |
}
|
|
|
|
| 3 |
import (
|
| 4 |
"context"
|
| 5 |
|
|
|
|
| 6 |
"github.com/abdanhafidz/ai-visual-multi-modal-backend/models"
|
| 7 |
+
"gorm.io/gorm"
|
| 8 |
)
|
| 9 |
|
| 10 |
type ChatHistoryRepository interface {
|
|
|
|
| 13 |
}
|
| 14 |
|
| 15 |
type chatHistoryRepository struct {
|
| 16 |
+
*repository[models.ChatHistory]
|
| 17 |
}
|
| 18 |
|
| 19 |
+
func NewChatHistoryRepository(db *gorm.DB) ChatHistoryRepository {
|
| 20 |
return &chatHistoryRepository{
|
| 21 |
+
repository: &repository[models.ChatHistory]{
|
| 22 |
+
entity: models.ChatHistory{},
|
| 23 |
+
transaction: db,
|
| 24 |
},
|
| 25 |
}
|
| 26 |
}
|