lifedebugger commited on
Commit
dc4d7ab
·
1 Parent(s): 6b99a55

Deploy files from GitHub repository

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. repositories/account_repository.go +1 -1
  2. repositories/repository.go +10 -14
  3. services/authentication_service.go +3 -4
  4. space/repositories/account_repository.go +1 -1
  5. space/space/config/turnstile_client_config.go +5 -5
  6. space/space/controller/authentication_controller.go +2 -2
  7. space/space/go.mod +1 -0
  8. space/space/go.sum +2 -0
  9. space/space/models/entities_model.go +1 -1
  10. space/space/repositories/account_repository.go +2 -2
  11. space/space/repositories/repository.go +37 -5
  12. space/space/services/authentication_service.go +11 -9
  13. space/space/space/space/Dockerfile +2 -2
  14. space/space/space/space/controller/authentication_controller.go +1 -1
  15. space/space/space/space/space/config/config.go +1 -0
  16. space/space/space/space/space/config/env_config.go +4 -1
  17. space/space/space/space/space/config/turnstile_client_config.go +11 -0
  18. space/space/space/space/space/controller/authentication_controller.go +40 -0
  19. space/space/space/space/space/factory/authentication_factory.go +16 -0
  20. space/space/space/space/space/go.mod +3 -0
  21. space/space/space/space/space/go.sum +6 -0
  22. space/space/space/space/space/middleware/authentication_middleware.go +31 -47
  23. space/space/space/space/space/models/authentication_dto.go +3 -2
  24. space/space/space/space/space/models/authentication_payload_model.go +11 -3
  25. space/space/space/space/space/models/entities_model.go +4 -4
  26. space/space/space/space/space/models/exception_model.go +1 -1
  27. space/space/space/space/space/models/http_response_dto_model.go +1 -1
  28. space/space/space/space/space/repositories/account_repository.go +16 -6
  29. space/space/space/space/space/router/authentication_route.go +20 -0
  30. space/space/space/space/space/router/router.go +1 -0
  31. space/space/space/space/space/services/authentication_service.go +68 -3
  32. space/space/space/space/space/services/jwt_service.go +68 -0
  33. space/space/space/space/space/space/services/openai_service.go +0 -1
  34. space/space/space/space/space/space/space/controller/prediction_controller.go +7 -1
  35. space/space/space/space/space/space/space/services/openai_service.go +1 -0
  36. space/space/space/space/space/space/space/space/.github/workflows/deploy.yml +4 -3
  37. space/space/space/space/space/space/space/space/.github/workflows/go.yml +22 -7
  38. space/space/space/space/space/space/space/space/Dockerfile +3 -3
  39. space/space/space/space/space/space/space/space/config/config.go +5 -24
  40. space/space/space/space/space/space/space/space/config/database_connection_config.go +1 -1
  41. space/space/space/space/space/space/space/space/config/env_config.go +26 -0
  42. space/space/space/space/space/space/space/space/config/openai_client_config.go +1 -1
  43. space/space/space/space/space/space/space/space/config/replicate_client_config.go +1 -1
  44. space/space/space/space/space/space/space/space/factory/prediction_factory.go +15 -5
  45. space/space/space/space/space/space/space/space/images/foto-pacarku.jpg +0 -0
  46. space/space/space/space/space/space/space/space/images/foto_pacarku.jpg +0 -0
  47. space/space/space/space/space/space/space/space/logs/error_log.txt +8 -0
  48. space/space/space/space/space/space/space/space/main.go +1 -0
  49. space/space/space/space/space/space/space/space/models/authentication_dto.go +2 -1
  50. 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
- 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
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 "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
  }
 
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, fingerPrint string) (res models.Account)
13
- GetAccountByPassPhrase(ctx context.Context, fingePrint string) (res models.Account)
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).Where(&repo.entity)
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).Find(&res)
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.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,
@@ -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
- 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 ""
@@ -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 (loginRequest.IPAddress == ""){
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/v5"
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
- type CustomClaims struct {
21
- jwt.RegisteredClaims
22
- UserID int `json:"id"`
23
- }
 
 
 
 
 
 
24
 
25
- func VerifyToken(bearer_token string) (int, string, error) {
26
- // fmt.Println(bearer_token)
27
- token, err := jwt.ParseWithClaims(bearer_token, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
28
- return secretKey, nil
29
- })
30
- if err != nil {
31
- return 0, "invalid-token", err
32
- }
33
 
34
- // Extract the claims
35
- claims, ok := token.Claims.(*CustomClaims)
36
- if !ok || !token.Valid {
37
- return 0, "invalid-token", err
38
- }
39
- if claims.ExpiresAt != nil && claims.ExpiresAt.Time.Before(time.Now()) {
40
- return 0, "expired", err
41
- }
42
-
43
- return claims.UserID, "valid", err
44
- }
45
 
46
- func AuthUser(c *gin.Context) {
47
- var currAccData models.AccountData
48
- if c.Request.Header["Auth-Bearer-Token"] != nil {
49
- token := c.Request.Header["Auth-Bearer-Token"]
50
- currAccData.UserID, currAccData.VerifyStatus, currAccData.ErrVerif = VerifyToken(token[0])
51
- // fmt.Println("Verify Status :", currAccData.verifyStatus)
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
- UserID int
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 uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
11
- Fingerprint 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 {
 
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
- GetAccountByFingerPrint(ctx context.Context, fingePrint string) (res models.Account)
13
  }
14
 
15
  type accountRepository struct {
16
- repository[models.Account]
17
  }
18
 
19
- func (r *accountRepository) CreateAccount(ctx context.Context, fingerPrint string) (res models.Account) {
20
- r.entity.Fingerprint = fingerPrint
 
 
 
 
 
 
 
 
 
21
  r.Create(ctx)
22
  return r.entity
23
  }
24
 
25
- func (r *accountRepository) GetAccountByFingerPrint(ctx context.Context, fingerPrint string) (res models.Account) {
26
- r.entity.Fingerprint = fingerPrint
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 "context"
 
 
 
 
 
 
4
 
5
  type AuthenticationService interface {
6
- Register(ctx context.Context, fingerPrint string)
7
- Login(ctx context.Context, fingerPrint string)
 
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
- push:
5
- branches:
6
- - main
 
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
- # This workflow will build a golang project
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.20'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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/audio /app/logs && \
38
- chmod -R 777 /app/audio /app/logs && \
39
- chown -R appuser:appuser /app/audio /app/logs
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
- import (
4
- "os"
5
- "strconv"
6
-
7
- "github.com/joho/godotenv"
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 init() {
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 init() {
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 init() {
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(chatHistoryRepository, config.OpenAIClient)
13
- replicateService := services.NewReplicateService(chatHistoryRepository, config.ReplicateClient, "spuuntries/urna-kp3l:9338a4573a17178b70515c0ef2e613d3b4213e2dc860ef23b3ad6149dacadc1e")
14
- predictionService := services.NewPredictionService(chatHistoryRepository, replicateService, openAIService)
 
 
 
 
 
 
 
 
 
 
 
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
- FingerPrintToken string `json:"email" binding:"required"`
 
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
- transaction: config.DB.Begin(),
 
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
  }