47 Commits
Author SHA1 Message Date
Ardeman 211f0154be fix: update default environment mode to local and adjust database configurations 2025-04-24 11:25:36 +08:00
Ardeman 136c4634c8 fix: enable SSL for Redis configuration in debug environment 2025-04-23 19:10:31 +08:00
Ardeman 987ac2fe4a fix: update Redis configuration to use SSL and adjust related settings 2025-04-23 19:09:24 +08:00
Ardeman 02d8a509ff fix: update Redis credentials in staging configuration 2025-04-23 18:45:49 +08:00
Ardeman e29bd7986f fix: update default environment mode to staging and add local configuration file 2025-04-23 18:18:44 +08:00
Ardeman 4bf318a9c2 fix: update PostgreSQL configuration for staging environment 2025-04-23 18:01:55 +08:00
Ardeman 52085a5be0 feat: add staging configuration file with server, database, and OSS settings 2025-04-23 17:52:58 +08:00
Ardeman 21c4c1efba fix: update MinIO endpoint and URLs to use news-cdn.legalgo.id in debug.yaml and production.yaml 2025-04-23 14:50:59 +08:00
Ardeman c17540cc20 fix: update MinIO endpoint and URLs to use crm-cdn.legalgo.id in production.yaml 2025-04-23 14:27:26 +08:00
Ardeman 714b1ff4eb fix: correct public URL formatting in GetPublicURL function 2025-04-23 13:50:41 +08:00
Ardeman abc3ce8d2b fix: update bucket name to 'uploads' in debug.yaml and production.yaml 2025-04-23 13:48:28 +08:00
Ardeman cd1097d3d0 fix: update MinIO endpoint to include the full domain in debug.yaml and production.yaml 2025-04-23 13:39:43 +08:00
Ardeman 52991059c6 fix: update bucket name to legalgonews-production in debug.yaml and production.yaml 2025-04-23 13:17:32 +08:00
Ardeman a7ef3f8ca2 fix: update SSL mode configuration in debug.yaml and NewDB function 2025-04-23 13:11:57 +08:00
Ardeman 6f1ac37915 fix: update redis host configuration in production.yaml 2025-04-23 12:57:06 +08:00
Ardeman e20c63e694 feat: add debug configuration file for server, jwt, postgresql, oss, and redis 2025-04-23 12:50:28 +08:00
Ardeman abcbc014a2 feat: add production configuration files for server, jwt, postgresql, oss, and redis 2025-04-23 12:39:50 +08:00
ericprd 98b871a5ed feat: get all staff 2025-03-25 18:01:14 +08:00
ericprd 3311b80943 Merge branch 'main' of github.com:ardeman/project-legalgo-go 2025-03-24 22:16:17 +08:00
ericprd 16fef8706a fix: register staff return message only 2025-03-24 22:15:41 +08:00
Ardeman 4fbfa9c2c9 Merge branch 'main' of https://github.com/ardeman/project-legalgo-go
* 'main' of https://github.com/ardeman/project-legalgo-go:
  fix: search news title by query
2025-03-24 18:18:53 +08:00
ericprd a68780f09e fix: search news title by query 2025-03-24 18:11:08 +08:00
Ardeman 49dc0e4a7b refactor: update GetAll method to return NewsResponse and rename clicked to views 2025-03-24 15:24:52 +08:00
ericprd 09d9c4efb8 fix: error clicked when create new news 2025-03-24 14:02:20 +08:00
ericprd 990026cece fix: error clicked when create new news 2025-03-24 13:35:46 +08:00
ericprd 11051ae89c feat: staff get news by id 2025-03-24 13:32:05 +08:00
ericprd 24f0fe6efa fix: filter active in news 2025-03-20 13:13:28 +08:00
ericprd 8d7500610e fix: get userAgent and IP from custom header 2025-03-20 11:52:12 +08:00
ericprd 0c8133c802 fix: don't record log if staff 2025-03-20 11:19:41 +08:00
ericprd d8f6968f64 fix: improvement logs and record news access 2025-03-20 11:11:08 +08:00
ericprd 290d7f6701 fix: improvement log record ads tih ip, useragent, and uer_id 2025-03-19 22:43:31 +08:00
ericprd b0099dac1e fix: remove auth in ads log 2025-03-19 12:47:41 +08:00
ericprd d7fa8496b0 fix: add created_at field on user profile 2025-03-17 22:50:37 +08:00
ericprd efab193793 fix: add seeding spotlight category 2025-03-17 22:42:25 +08:00
ericprd 7b529ba46e fix: add clicked count on ads 2025-03-17 22:35:22 +08:00
ericprd c0dcdb77fa feat: ads log 2025-03-17 22:19:17 +08:00
ericprd ee8e8e140d fix: improvement access data 2025-03-14 13:00:12 +08:00
ericprd 11bc19360c feat: update staff data 2025-03-14 12:41:11 +08:00
ericprd 1297c71200 feat: update route ads 2025-03-13 12:00:26 +08:00
ericprd 47085ca0ae fix: add start date and end date of ads 2025-03-13 11:45:39 +08:00
ericprd ce17e9dc73 fix: update seeder 2025-03-10 12:28:56 +08:00
ericprd ce341dbc13 fix: add new fields on subscribe plan, and change status type to number in subscribe 2025-03-10 11:48:20 +08:00
ericprd 52dfb7e0f2 feat: delete ads 2025-03-10 10:50:27 +08:00
ericprd ef6b17a363 fix: image must be url in create ads 2025-03-10 10:28:23 +08:00
ericprd 1ae192ccef feat: get all ads 2025-03-09 00:55:40 +08:00
ericprd 213d370332 feat: create ads 2025-03-09 00:47:24 +08:00
ericprd 13c976dcbf fix: update user plan and rearrange structur project 2025-03-08 22:46:05 +08:00
137 changed files with 1991 additions and 482 deletions
+2
View File
@@ -2,3 +2,5 @@ bin
.env .env
.DS_Store .DS_Store
/cmd/legalgo/env /cmd/legalgo/env
__debug*
+21 -5
View File
@@ -6,6 +6,7 @@ import (
"legalgo-BE-go/config" "legalgo-BE-go/config"
"legalgo-BE-go/database" "legalgo-BE-go/database"
categorydomain "legalgo-BE-go/internal/domain/category"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"github.com/google/uuid" "github.com/google/uuid"
@@ -36,14 +37,29 @@ func main() {
log.Fatal("Migration failed: ", err) log.Fatal("Migration failed: ", err)
} }
var temp subscribeplandomain.SubscribePlan var tempSP subscribeplandomain.SubscribePlan
var tempCtg categorydomain.Category
if err := db.Where("code = ?", "basic").First(&temp).Error; err != nil { if err := db.Where("code = ?", "basic").First(&tempSP).Error; err != nil {
log.Print("seeding basic subscribe plan") log.Print("seeding basic subscribe plan")
db.Create(&subscribeplandomain.SubscribePlan{ db.Create(&subscribeplandomain.SubscribePlan{
ID: uuid.NewString(), ID: uuid.NewString(),
Code: "basic", Code: "basic",
Name: "Basic", Name: "Basic",
Length: 0,
Price: 0,
Status: 1,
})
}
if err := db.Where("code = ?", "spotlight").First(&tempCtg).Error; err != nil {
log.Print("seeding basic subscribe plan")
seq := 0
db.Create(&categorydomain.Category{
ID: uuid.NewString(),
Code: "spotlight",
Name: "Spotlight",
Sequence: &seq,
}) })
} }
+5 -4
View File
@@ -12,14 +12,15 @@ import (
const ( const (
YAML_PATH = "env/%s" YAML_PATH = "env/%s"
ENV_MODE = "ENV_MODE" ENV_MODE = "ENV_MODE"
DEFAULT_ENV_MODE = "development" DEFAULT_ENV_MODE = "local"
) )
var ( var (
validEnvMode = map[string]struct{}{ validEnvMode = map[string]struct{}{
"local": {}, "local": {},
"development": {}, "staging": {},
"production": {}, "production": {},
"debug": {},
} }
) )
+1 -1
View File
@@ -6,7 +6,7 @@ type Redis struct {
DB int `mapstructure:"db"` DB int `mapstructure:"db"`
Username string `mapstructure:"username"` Username string `mapstructure:"username"`
Password string `mapstructure:"password"` Password string `mapstructure:"password"`
SslMode string `mapstructure:"ssl-mode"` SSL bool `mapstructure:"ssl"`
Debug bool `mapstructure:"debug"` Debug bool `mapstructure:"debug"`
MaxIdleConnectionsInSecond int `mapstructure:"max-idle-connections-in-second"` MaxIdleConnectionsInSecond int `mapstructure:"max-idle-connections-in-second"`
MaxOpenConnectionsInSecond int `mapstructure:"max-open-connections-in-second"` MaxOpenConnectionsInSecond int `mapstructure:"max-open-connections-in-second"`
+13
View File
@@ -0,0 +1,13 @@
package database
import "time"
type Ads struct {
ID string `gorm:"primaryKey;not null" json:"id"`
ImageUrl string `gorm:"not null" json:"image_url"`
Url string `gorm:"not null" json:"url"`
StartDate *time.Time `gorm:"default:null" json:"start_date"`
EndDate *time.Time `gorm:"default:null" json:"end_date"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
+14
View File
@@ -0,0 +1,14 @@
package database
import "time"
type ContentLog struct {
ID string `gorm:"primaryKey;not null" json:"id"`
ContentID string `gorm:"not null" json:"content_id"`
UserID string `gorm:"default:null" json:"user_id"`
IP string `gorm:"default:null" json:"ip"`
UserAgent string `gorm:"default:null" json:"user_agent"`
Category string `gorm:"not null" json:"category"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}
+4 -1
View File
@@ -15,12 +15,13 @@ type DB struct {
func NewDB(cfg *config.Config) (*DB, error) { func NewDB(cfg *config.Config) (*DB, error) {
dsn := fmt.Sprintf( dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%v sslmode=disable", "host=%s user=%s password=%s dbname=%s port=%v sslmode=%s",
cfg.Database.Host, cfg.Database.Host,
cfg.Database.Username, cfg.Database.Username,
cfg.Database.Password, cfg.Database.Password,
cfg.Database.DB, cfg.Database.DB,
cfg.Database.Port, cfg.Database.Port,
cfg.Database.SslMode,
) )
if dsn == "" { if dsn == "" {
@@ -54,5 +55,7 @@ func (db *DB) Migrate() error {
&News{}, &News{},
&Tag{}, &Tag{},
&Category{}, &Category{},
&Ads{},
&ContentLog{},
) )
} }
+4 -1
View File
@@ -9,7 +9,7 @@ type Subscribe struct {
SubscribePlanID string `gorm:"not null" json:"subscribe_plan_id"` SubscribePlanID string `gorm:"not null" json:"subscribe_plan_id"`
StartDate time.Time `gorm:"default:CURRENT_TIMESTAMP"` StartDate time.Time `gorm:"default:CURRENT_TIMESTAMP"`
EndDate time.Time `gorm:"default:null"` EndDate time.Time `gorm:"default:null"`
Status string `gorm:"default:'inactive'"` Status int8 `gorm:"default:0"`
AutoRenew bool `gorm:"default:true"` AutoRenew bool `gorm:"default:true"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
@@ -22,6 +22,9 @@ type SubscribePlan struct {
ID string `gorm:"primaryKey" json:"id"` ID string `gorm:"primaryKey" json:"id"`
Code string `gorm:"not null;unique" json:"code"` Code string `gorm:"not null;unique" json:"code"`
Name string `gorm:"not null" json:"name"` Name string `gorm:"not null" json:"name"`
Length int `gorm:"default:0" json:"length"`
Price float32 `gorm:"default:0" json:"price"`
Status int8 `gorm:"default:1" json:"status"`
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
} }
+43
View File
@@ -0,0 +1,43 @@
server:
base-url: https://api.legalgo.id/core
local-url: http://localhost:3300
port: 3300
jwt:
token:
expires-ttl: 1440
secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
postgresql:
host: dpg-d046h549c44c739arfv0-a.singapore-postgres.render.com
port: 5432
driver: postgres
db: legalgonews_prod
username: legalgo_admin
password: "656ogwc0JlLEVQyHnT5RrrYa7762iBQQ"
ssl-mode: require
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
oss:
access_key_id: GTK7i3SVy9llQeGH0Htv
access_key_secret: 2psmKXZFpevA9n5ntSDRMqFBpZuSz32dvtXjYclf
endpoint: news-cdn.legalgo.id
bucket_name: uploads
log_level: Error
host_url: https://news-cdn.legalgo.id
public_url: https://news-cdn.legalgo.id
redis:
host: singapore-keyvalue.render.com
port: 6379
username: red-d046l42dbo4c73ea9iag
password: 7cZvu08JKuO9MPNxBb97tZCVNj0ZGNp2
db: 5
ssl: true
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
+43
View File
@@ -0,0 +1,43 @@
server:
base-url: https://api.legalgo.id/core
local-url: http://localhost:3300
port: 3300
jwt:
token:
expires-ttl: 1440
secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
postgresql:
host: dpg-d04bi9juibrs73augcc0-a.singapore-postgres.render.com
port: 5432
driver: postgres
db: legalgonews_dev
username: legalgo_admin
password: "5h7DCBR1T8pug6AlbrHXqIDAr9o2vnky"
ssl-mode: require
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
oss:
access_key_id: GTK7i3SVy9llQeGH0Htv
access_key_secret: 2psmKXZFpevA9n5ntSDRMqFBpZuSz32dvtXjYclf
endpoint: news-cdn.legalgo.id
bucket_name: uploads-staging
log_level: Error
host_url: https://news-cdn.legalgo.id
public_url: https://news-cdn.legalgo.id
redis:
host: singapore-keyvalue.render.com
port: 6379
username: red-d04c8k49c44c739ga8dg
password: ItPzniHv94yr8vY4HTrhCfKoibqBh61T
db: 5
ssl: true
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
+13 -13
View File
@@ -9,12 +9,12 @@ jwt:
secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs" secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
postgresql: postgresql:
host: 62.72.45.250 host: dpg-d046h549c44c739arfv0-a
port: 20826 port: 5432
driver: postgres driver: postgres
db: legalgonews-dev db: legalgonews_prod
username: legalgo_admin username: legalgo_admin
password: "K4K!2Kg7c@KW6H&4A2aBy2dFCRY3Sh" password: "656ogwc0JlLEVQyHnT5RrrYa7762iBQQ"
ssl-mode: disable ssl-mode: disable
max-idle-connections-in-second: 600 max-idle-connections-in-second: 600
max-open-connections-in-second: 600 max-open-connections-in-second: 600
@@ -22,18 +22,18 @@ postgresql:
debug: false debug: false
oss: oss:
access_key_id: cf9a475e18bc7626cbdbf09709d82a64 access_key_id: GTK7i3SVy9llQeGH0Htv
access_key_secret: 91f3321294d3e23035427a0ecb893ada access_key_secret: 2psmKXZFpevA9n5ntSDRMqFBpZuSz32dvtXjYclf
endpoint: sin1.contabostorage.com endpoint: news-cdn.legalgo.id
bucket_name: legalgonews-dev bucket_name: uploads
log_level: Error log_level: Error
host_url: https://sin1.contabostorage.com host_url: https://news-cdn.legalgo.id
public_url: https://sin1.contabostorage.com/fda98c2228f246f29a7e466b86b3b9e7 public_url: https://news-cdn.legalgo.id
redis: redis:
host: 62.72.45.250 host: red-d046l42dbo4c73ea9iag
port: 26379 port: 6379
password: mDtpsyEW8W26vwLhglpO password: 7cZvu08JKuO9MPNxBb97tZCVNj0ZGNp2
db: 5 db: 5
ssl: false ssl: false
max-idle-connections-in-second: 600 max-idle-connections-in-second: 600
+42
View File
@@ -0,0 +1,42 @@
server:
base-url: https://api.legalgo.id/core
local-url: http://localhost:3300
port: 3300
jwt:
token:
expires-ttl: 1440
secret: "5Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
postgresql:
host: dpg-d04bi9juibrs73augcc0-a
port: 5432
driver: postgres
db: legalgonews_dev
username: legalgo_admin
password: "5h7DCBR1T8pug6AlbrHXqIDAr9o2vnky"
ssl-mode: disable
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
oss:
access_key_id: GTK7i3SVy9llQeGH0Htv
access_key_secret: 2psmKXZFpevA9n5ntSDRMqFBpZuSz32dvtXjYclf
endpoint: news-cdn.legalgo.id
bucket_name: uploads-staging
log_level: Error
host_url: https://news-cdn.legalgo.id
public_url: https://news-cdn.legalgo.id
redis:
host: red-d04c8k49c44c739ga8dg
port: 6379
password: ItPzniHv94yr8vY4HTrhCfKoibqBh61T
db: 5
ssl: false
max-idle-connections-in-second: 600
max-open-connections-in-second: 600
connection-max-life-time-in-second: 600
debug: false
+14
View File
@@ -0,0 +1,14 @@
package adsrepository
import (
"fmt"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
func (a *accessor) Create(spec adsdomain.Ads) error {
if err := a.db.Create(&spec).Error; err != nil {
return fmt.Errorf("failed to create ads: %v", err)
}
return nil
}
+26
View File
@@ -0,0 +1,26 @@
package adsrepository
import (
"errors"
"fmt"
adsdomain "legalgo-BE-go/internal/domain/ads"
"gorm.io/gorm"
)
func (a *accessor) Delete(id string) error {
var ads adsdomain.Ads
if err := a.db.First(&ads, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("ads with id %s is not found", id)
}
return fmt.Errorf("failed to g ads %s : %v", id, err)
}
if err := a.db.Delete(&ads).Error; err != nil {
return fmt.Errorf("failed to delete ads %s : %v", id, err)
}
return nil
}
+20
View File
@@ -0,0 +1,20 @@
package adsrepository
import (
"fmt"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
func (a *accessor) GetAll() ([]adsdomain.AdsResponse, error) {
var ads []adsdomain.AdsResponse
if err := a.db.Table("ads").
Select("ads.*, COUNT(content_logs.content_id) as clicked").
Joins("LEFT JOIN content_logs ON content_logs.content_id = ads.id").
Group("ads.id").
Scan(&ads).Error; err != nil {
return ads, fmt.Errorf("failed to get all ads: %v", err)
}
return ads, nil
}
+23
View File
@@ -0,0 +1,23 @@
package adsrepository
import (
"legalgo-BE-go/database"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
type accessor struct {
db *database.DB
}
type Ads interface {
Create(adsdomain.Ads) error
GetAll() ([]adsdomain.AdsResponse, error)
Update(adsdomain.Ads) error
Delete(string) error
}
func New(
db *database.DB,
) Ads {
return &accessor{db}
}
+31
View File
@@ -0,0 +1,31 @@
package adsrepository
import (
"fmt"
adsdomain "legalgo-BE-go/internal/domain/ads"
"gorm.io/gorm/clause"
)
func (a *accessor) Update(spec adsdomain.Ads) error {
if err := a.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{
"image_url",
"url",
"updated_at",
"start_date",
"end_date",
}),
}).Select(
"image_url",
"url",
"updated_at",
"start_date",
"end_date",
).Save(&spec).Error; err != nil {
return fmt.Errorf("failed to update tag: %v", err)
}
return nil
}
+33
View File
@@ -0,0 +1,33 @@
package logrepository
import (
"legalgo-BE-go/database"
logsdomain "legalgo-BE-go/internal/domain/logs"
"github.com/google/uuid"
)
func (a *accessor) CreateLog(spec logsdomain.LogsSpec) error {
newSpec := database.ContentLog{
ID: uuid.NewString(),
ContentID: spec.ContentID,
Category: spec.Category,
}
if spec.UserID != nil {
newSpec.UserID = *spec.UserID
}
if spec.IP != nil {
newSpec.IP = *spec.IP
}
if spec.UserAgent != nil {
newSpec.UserAgent = *spec.UserAgent
}
if err := a.db.Create(&newSpec).Error; err != nil {
return err
}
return nil
}
+21
View File
@@ -0,0 +1,21 @@
package logrepository
import (
adsdomain "legalgo-BE-go/internal/domain/ads"
)
func (a *accessor) GetAllLogAds(userID string) ([]adsdomain.Ads, error) {
var ads []adsdomain.Ads
// if err := a.db.Find(&ads, "user_id = ?", userID).Error; err != nil {
// return ads, err
// }
if err := a.db.
Joins("JOIN log_ads ON ads.id = log_ads.ads_id").
Find(&ads, "log_ads.user_id = ?", userID).Error; err != nil {
return ads, err
}
return ads, nil
}
+20
View File
@@ -0,0 +1,20 @@
package logrepository
import (
"legalgo-BE-go/database"
adsdomain "legalgo-BE-go/internal/domain/ads"
logsdomain "legalgo-BE-go/internal/domain/logs"
)
type accessor struct {
db *database.DB
}
type Log interface {
CreateLog(logsdomain.LogsSpec) error
GetAllLogAds(string) ([]adsdomain.Ads, error)
}
func New(db *database.DB) Log {
return &accessor{db}
}
+5 -1
View File
@@ -1,13 +1,15 @@
package repository package repository
import ( import (
adsrepository "legalgo-BE-go/internal/accessor/ads"
categoryrepository "legalgo-BE-go/internal/accessor/category" categoryrepository "legalgo-BE-go/internal/accessor/category"
logrepository "legalgo-BE-go/internal/accessor/log"
newsrepository "legalgo-BE-go/internal/accessor/news" newsrepository "legalgo-BE-go/internal/accessor/news"
"legalgo-BE-go/internal/accessor/oss" "legalgo-BE-go/internal/accessor/oss"
redisaccessor "legalgo-BE-go/internal/accessor/redis" redisaccessor "legalgo-BE-go/internal/accessor/redis"
staffrepository "legalgo-BE-go/internal/accessor/staff" staffrepository "legalgo-BE-go/internal/accessor/staff"
subscriberepository "legalgo-BE-go/internal/accessor/subscribe" subscriberepository "legalgo-BE-go/internal/accessor/subscribe"
subscribeplanrepository "legalgo-BE-go/internal/accessor/subscribeplan" subscribeplanrepository "legalgo-BE-go/internal/accessor/subscribe_plan"
tagrepository "legalgo-BE-go/internal/accessor/tag" tagrepository "legalgo-BE-go/internal/accessor/tag"
userrepository "legalgo-BE-go/internal/accessor/user" userrepository "legalgo-BE-go/internal/accessor/user"
@@ -24,4 +26,6 @@ var Module = fx.Module("repository", fx.Provide(
categoryrepository.New, categoryrepository.New,
newsrepository.New, newsrepository.New,
oss.New, oss.New,
adsrepository.New,
logrepository.New,
)) ))
+29 -5
View File
@@ -1,13 +1,24 @@
package newsrepository package newsrepository
import newsdomain "legalgo-BE-go/internal/domain/news" import (
newsdomain "legalgo-BE-go/internal/domain/news"
timeutils "legalgo-BE-go/internal/utilities/time_utils"
)
func (a *accessor) GetAll(filter newsdomain.NewsFilter) ([]newsdomain.News, error) { type is_active string
var news []newsdomain.News
query := a.db. const (
active is_active = "true"
notActive is_active = "false"
)
func (a *accessor) GetAll(filter newsdomain.NewsFilter) ([]newsdomain.NewsResponse, error) {
var news []newsdomain.NewsResponse
query := a.db.Table("news").
Preload("Tags"). Preload("Tags").
Preload("Categories"). Preload("Categories").
Preload("Author") Preload("Author").
Joins("LEFT JOIN content_logs ON content_logs.content_id = news.id")
if len(filter.Category) > 0 { if len(filter.Category) > 0 {
query = query.Joins("JOIN news_categories nc ON nc.news_id = news.id"). query = query.Joins("JOIN news_categories nc ON nc.news_id = news.id").
@@ -19,6 +30,19 @@ func (a *accessor) GetAll(filter newsdomain.NewsFilter) ([]newsdomain.News, erro
Where("nt.tag_id IN (?)", filter.Tags) Where("nt.tag_id IN (?)", filter.Tags)
} }
if filter.Active == string(active) {
query = query.Where("news.live_at <= ?", timeutils.Now())
}
if filter.Search != "" {
query = query.Where("news.title ILIKE ?", "%"+filter.Search+"%")
}
query.
Select("news.*, COUNT(content_logs.content_id) as views").
Group("news.id").
Order("news.created_at DESC")
if err := query. if err := query.
Find(&news).Error; err != nil { Find(&news).Error; err != nil {
return nil, err return nil, err
+17
View File
@@ -0,0 +1,17 @@
package newsrepository
import newsdomain "legalgo-BE-go/internal/domain/news"
func (a *accessor) GetByID(id string) (*newsdomain.News, error) {
var news newsdomain.News
if err := a.db.
Preload("Tags").
Preload("Categories").
Preload("Author").
First(&news, "id = ?", id).Error; err != nil {
return nil, err
}
return &news, nil
}
+2 -1
View File
@@ -10,8 +10,9 @@ type accessor struct {
} }
type News interface { type News interface {
GetAll(filter newsdomain.NewsFilter) ([]newsdomain.News, error) GetAll(filter newsdomain.NewsFilter) ([]newsdomain.NewsResponse, error)
GetBySlug(string) (*newsdomain.News, error) GetBySlug(string) (*newsdomain.News, error)
GetByID(string) (*newsdomain.News, error)
Create(newsdomain.News) error Create(newsdomain.News) error
Update(newsdomain.News) error Update(newsdomain.News) error
Delete(string) error Delete(string) error
+17 -1
View File
@@ -66,5 +66,21 @@ func (r *OssRepositoryImpl) GetPublicURL(fileName string) string {
if fileName == "" { if fileName == "" {
return "" return ""
} }
return fmt.Sprintf("%s:%s%s", r.cfg.GetPublicURL(), r.cfg.GetBucketName(), fileName) return fmt.Sprintf("%s/%s%s", r.cfg.GetPublicURL(), r.cfg.GetBucketName(), fileName)
}
func (r *OssRepositoryImpl) DeleteObject(ctx context.Context, fileName string) error {
if fileName == "" {
return fmt.Errorf("file name is not provided")
}
_, err := r.s3.DeleteObject(&s3.DeleteObjectInput{
Key: aws.String(fileName),
})
if err != nil {
return fmt.Errorf("failed to delete object %s from bucket: %v", fileName, err)
}
return nil
} }
+1
View File
@@ -7,4 +7,5 @@ import (
type OSSRepository interface { type OSSRepository interface {
UploadFile(ctx context.Context, fileName string, fileContent []byte) (fileUrl string, err error) UploadFile(ctx context.Context, fileName string, fileContent []byte) (fileUrl string, err error)
GetPublicURL(fileName string) string GetPublicURL(fileName string) string
DeleteObject(ctx context.Context, fileName string) error
} }
+11 -2
View File
@@ -1,6 +1,7 @@
package redisaccessor package redisaccessor
import ( import (
"crypto/tls"
"fmt" "fmt"
"legalgo-BE-go/config" "legalgo-BE-go/config"
@@ -16,11 +17,19 @@ func Get() *redis.Client {
func New(cfg *config.Config) *redis.Client { func New(cfg *config.Config) *redis.Client {
addr := fmt.Sprintf("%s:%s", cfg.Redis.Host, cfg.Redis.Port) addr := fmt.Sprintf("%s:%s", cfg.Redis.Host, cfg.Redis.Port)
redisClient = redis.NewClient(&redis.Options{ options := &redis.Options{
Addr: addr, Addr: addr,
Password: cfg.Redis.Password, Password: cfg.Redis.Password,
DB: cfg.Redis.DB, DB: cfg.Redis.DB,
}) }
if cfg.Redis.Username != "" {
options.Username = cfg.Redis.Username
}
if cfg.Redis.SSL {
options.TLSConfig = &tls.Config{}
}
redisClient = redis.NewClient(options)
return redisClient return redisClient
} }
+3 -2
View File
@@ -2,6 +2,7 @@ package staffrepository
import ( import (
"errors" "errors"
"fmt"
staffdomain "legalgo-BE-go/internal/domain/staff" staffdomain "legalgo-BE-go/internal/domain/staff"
@@ -12,12 +13,12 @@ func (sr *accessor) GetStaffByEmail(email string) (*staffdomain.Staff, error) {
var staff staffdomain.Staff var staff staffdomain.Staff
if email == "" { if email == "" {
return nil, errors.New("email is required") return nil, fmt.Errorf("email is required")
} }
if err := sr.db.First(&staff, "email = ?", email).Error; err != nil { if err := sr.db.First(&staff, "email = ?", email).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("staff not found") return nil, fmt.Errorf("staff not found")
} }
return nil, err return nil, err
} }
+3 -2
View File
@@ -2,6 +2,7 @@ package staffrepository
import ( import (
"errors" "errors"
"fmt"
staffdomain "legalgo-BE-go/internal/domain/staff" staffdomain "legalgo-BE-go/internal/domain/staff"
"gorm.io/gorm" "gorm.io/gorm"
@@ -11,12 +12,12 @@ func (sr *accessor) GetStaffByID(ID string) (*staffdomain.Staff, error) {
var staff staffdomain.Staff var staff staffdomain.Staff
if ID == "" { if ID == "" {
return nil, errors.New("id is required") return nil, fmt.Errorf("id is required")
} }
if err := sr.db.First(&staff, "id = ? ", ID).Error; err != nil { if err := sr.db.First(&staff, "id = ? ", ID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("staff not found") return nil, fmt.Errorf("staff not found")
} }
return nil, err return nil, err
} }
+13
View File
@@ -0,0 +1,13 @@
package staffrepository
import staffdomain "legalgo-BE-go/internal/domain/staff"
func (a *accessor) GetStaffs() ([]staffdomain.StaffProfile, error) {
var staffs []staffdomain.StaffProfile
if err := a.db.Table("staffs").Find(&staffs).Error; err != nil {
return staffs, err
}
return staffs, nil
}
+1
View File
@@ -20,6 +20,7 @@ func (a *accessor) GetUsers() ([]userdomain.UserProfile, error) {
Email: user.Email, Email: user.Email,
Phone: user.Phone, Phone: user.Phone,
Subscribe: user.Subscribe, Subscribe: user.Subscribe,
CreatedAt: user.CreatedAt,
}) })
} }
+1
View File
@@ -14,6 +14,7 @@ type Staff interface {
GetStaffByEmail(string) (*staffdomain.Staff, error) GetStaffByEmail(string) (*staffdomain.Staff, error)
GetStaffByID(string) (*staffdomain.Staff, error) GetStaffByID(string) (*staffdomain.Staff, error)
GetUsers() ([]userdomain.UserProfile, error) GetUsers() ([]userdomain.UserProfile, error)
GetStaffs() ([]staffdomain.StaffProfile, error)
Create(staffdomain.Staff) error Create(staffdomain.Staff) error
Update(staffdomain.Staff) error Update(staffdomain.Staff) error
} }
+5 -6
View File
@@ -2,16 +2,15 @@ package staffrepository
import ( import (
staffdomain "legalgo-BE-go/internal/domain/staff" staffdomain "legalgo-BE-go/internal/domain/staff"
"legalgo-BE-go/internal/utilities/utils"
) )
func (ur *accessor) Update(spec staffdomain.Staff) error { func (ur *accessor) Update(spec staffdomain.Staff) error {
val, err := utils.StructToMap(spec) // val, err := utils.StructToMap(spec)
if err != nil { // if err != nil {
return err // return err
} // }
if err := ur.db.Model(&staffdomain.Staff{}).Where("id = ?", spec.ID).Updates(val).Error; err != nil { if err := ur.db.Model(&staffdomain.Staff{}).Where("id = ?", spec.ID).Updates(spec).Error; err != nil {
return err return err
} }
+2 -2
View File
@@ -6,13 +6,13 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
func (s *SubsAccs) Create(subsPlanId string) (string, error) { func (s *accessor) Create(subsPlanId string) (string, error) {
spec := &subscribedomain.Subscribe{ spec := &subscribedomain.Subscribe{
ID: uuid.NewString(), ID: uuid.NewString(),
SubscribePlanID: subsPlanId, SubscribePlanID: subsPlanId,
} }
if err := s.DB.Create(&spec).Error; err != nil { if err := s.db.Create(&spec).Error; err != nil {
return "", err return "", err
} }
+4 -4
View File
@@ -3,15 +3,15 @@ package subscriberepository
import ( import (
"errors" "errors"
"fmt" "fmt"
"legalgo-BE-go/database" subscribedomain "legalgo-BE-go/internal/domain/subscribe"
"gorm.io/gorm" "gorm.io/gorm"
) )
func (s *SubsAccs) GetByID(id string) (database.Subscribe, error) { func (s *accessor) GetByID(id string) (subscribedomain.Subscribe, error) {
var subscribe database.Subscribe var subscribe subscribedomain.Subscribe
if err := s.DB.First(&subscribe, "id = ?", id).Error; err != nil { if err := s.db.First(&subscribe, "id = ?", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return subscribe, fmt.Errorf("subscribe data not found: %v", err) return subscribe, fmt.Errorf("subscribe data not found: %v", err)
} }
+11 -8
View File
@@ -1,17 +1,20 @@
package subscriberepository package subscriberepository
import "legalgo-BE-go/database" import (
"legalgo-BE-go/database"
subscribedomain "legalgo-BE-go/internal/domain/subscribe"
)
type SubsAccs struct { type accessor struct {
DB *database.DB db *database.DB
} }
type SubsIntf interface { type Subscribe interface {
Create(string) (string, error) Create(string) (string, error)
GetByID(string) (database.Subscribe, error) GetByID(string) (subscribedomain.Subscribe, error)
UpdateSubscribeStatus(database.Subscribe) error Update(subscribedomain.Subscribe) error
} }
func New(db *database.DB) SubsIntf { func New(db *database.DB) Subscribe {
return &SubsAccs{db} return &accessor{db}
} }
+19
View File
@@ -0,0 +1,19 @@
package subscriberepository
import (
"fmt"
subscribedomain "legalgo-BE-go/internal/domain/subscribe"
"gorm.io/gorm/clause"
)
func (a *accessor) Update(spec subscribedomain.Subscribe) error {
if err := a.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{"status", "subscribe_plan_id", "start_date"}),
}).Create(&spec).Error; err != nil {
return fmt.Errorf("failed to update status: %v", err)
}
return nil
}
@@ -1,19 +0,0 @@
package subscriberepository
import (
"fmt"
"legalgo-BE-go/database"
"gorm.io/gorm/clause"
)
func (a *SubsAccs) UpdateSubscribeStatus(spec database.Subscribe) error {
if err := a.DB.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{"status"}),
}).Create(&spec).Error; err != nil {
return fmt.Errorf("failed to update status: %v", err)
}
return nil
}
@@ -0,0 +1,13 @@
package subscribeplanrepository
import (
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
)
func (s *accessor) Create(spec subscribeplandomain.SubscribePlan) error {
if err := s.db.Create(&spec).Error; err != nil {
return err
}
return nil
}
@@ -0,0 +1,30 @@
package subscribeplanrepository
import (
"fmt"
"legalgo-BE-go/database"
subscribedomain "legalgo-BE-go/internal/domain/subscribe"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
)
func (a *accessor) Delete(id string) error {
var subsPlan database.SubscribePlan
var basicPlan subscribeplandomain.SubscribePlan
if err := a.db.First(&basicPlan, "code = ?", "basic").Error; err != nil {
return fmt.Errorf("failed to find basic plan: %v", err)
}
if err := a.db.
Model(&subscribedomain.Subscribe{}).
Where("subscribe_plan_id = ?", id).
Update("subscribe_plan_id", basicPlan.ID).Error; err != nil {
return fmt.Errorf("failed to change subscribe plan: %v", err)
}
if err := a.db.Delete(&subsPlan, "id = ?", id).Error; err != nil {
return fmt.Errorf("failed to delete subscribe plan %s : %v", id, err)
}
return nil
}
@@ -4,10 +4,10 @@ import (
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
) )
func (s *SubsPlan) GetAll() ([]subscribeplandomain.SubscribePlan, error) { func (s *accessor) GetAll() ([]subscribeplandomain.SubscribePlan, error) {
var subscribePlans []subscribeplandomain.SubscribePlan var subscribePlans []subscribeplandomain.SubscribePlan
if err := s.DB.Find(&subscribePlans).Error; err != nil { if err := s.db.Find(&subscribePlans).Error; err != nil {
return nil, err return nil, err
} }
@@ -0,0 +1,22 @@
package subscribeplanrepository
import (
"errors"
"fmt"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"gorm.io/gorm"
)
func (s *accessor) GetByID(id string) (*subscribeplandomain.SubscribePlan, error) {
var subscribePlan *subscribeplandomain.SubscribePlan
if err := s.db.First(&subscribePlan, "id = ? ", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return subscribePlan, fmt.Errorf("subscribe plan not found")
}
return subscribePlan, err
}
return subscribePlan, nil
}
@@ -0,0 +1,22 @@
package subscribeplanrepository
import (
"legalgo-BE-go/database"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"github.com/google/uuid"
)
func (s *accessor) GetDefault() (*subscribeplandomain.SubscribePlan, error) {
var subscribePlan *subscribeplandomain.SubscribePlan
if err := s.db.First(&subscribePlan, "code = ?", "basic").Error; err != nil {
s.db.Create(&database.SubscribePlan{
ID: uuid.NewString(),
Code: "basic",
Name: "Basic",
})
}
return subscribePlan, nil
}
+25
View File
@@ -0,0 +1,25 @@
package subscribeplanrepository
import (
"legalgo-BE-go/database"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
)
type accessor struct {
db *database.DB
}
type SubscribePlan interface {
Create(subscribeplandomain.SubscribePlan) error
GetAll() ([]subscribeplandomain.SubscribePlan, error)
GetByID(string) (*subscribeplandomain.SubscribePlan, error)
GetDefault() (*subscribeplandomain.SubscribePlan, error)
Update(subscribeplandomain.SubscribePlan) error
Delete(string) error
}
func New(
db *database.DB,
) SubscribePlan {
return &accessor{db}
}
@@ -0,0 +1,33 @@
package subscribeplanrepository
import (
"fmt"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"gorm.io/gorm/clause"
)
func (a *accessor) Update(spec subscribeplandomain.SubscribePlan) error {
if err := a.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{
"name",
"code",
"length",
"price",
"status",
"updated_at",
}),
}).Select(
"name",
"code",
"length",
"price",
"status",
"updated_at",
).Save(&spec).Error; err != nil {
return fmt.Errorf("failed to update tag: %v", err)
}
return nil
}
-21
View File
@@ -1,21 +0,0 @@
package subscribeplanrepository
import (
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"github.com/google/uuid"
)
func (s *SubsPlan) Create(spec subscribeplandomain.SubscribePlanReq) error {
data := &subscribeplandomain.SubscribePlan{
ID: uuid.NewString(),
Code: spec.Code,
Name: spec.Name,
}
if err := s.DB.Create(&data).Error; err != nil {
return err
}
return nil
}
@@ -1,21 +0,0 @@
package subscribeplanrepository
import (
"errors"
"legalgo-BE-go/database"
"gorm.io/gorm"
)
func (s *SubsPlan) GetByID(id string) (*database.SubscribePlan, error) {
var subscribePlan *database.SubscribePlan
if err := s.DB.First(&subscribePlan, "id = ? ", id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return subscribePlan, errors.New("subscribe plan not found")
}
return subscribePlan, err
}
return subscribePlan, nil
}
@@ -1,21 +0,0 @@
package subscribeplanrepository
import (
"legalgo-BE-go/database"
"github.com/google/uuid"
)
func (s *SubsPlan) GetDefault() (*database.SubscribePlan, error) {
var subscribePlan *database.SubscribePlan
if err := s.DB.First(&subscribePlan, "code = ?", "basic").Error; err != nil {
s.DB.Create(&database.SubscribePlan{
ID: uuid.NewString(),
Code: "basic",
Name: "Basic",
})
}
return subscribePlan, nil
}
-23
View File
@@ -1,23 +0,0 @@
package subscribeplanrepository
import (
"legalgo-BE-go/database"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
)
type SubsPlan struct {
DB *database.DB
}
type SubsPlanIntf interface {
Create(subscribeplandomain.SubscribePlanReq) error
GetAll() ([]subscribeplandomain.SubscribePlan, error)
GetByID(string) (*database.SubscribePlan, error)
GetDefault() (*database.SubscribePlan, error)
}
func New(
db *database.DB,
) SubsPlanIntf {
return &SubsPlan{db}
}
+3 -2
View File
@@ -2,6 +2,7 @@ package userrepository
import ( import (
"errors" "errors"
"fmt"
userdomain "legalgo-BE-go/internal/domain/user" userdomain "legalgo-BE-go/internal/domain/user"
"gorm.io/gorm" "gorm.io/gorm"
@@ -11,12 +12,12 @@ func (ur *accessor) GetUserByEmail(email string) (*userdomain.User, error) {
var user *userdomain.User var user *userdomain.User
if email == "" { if email == "" {
return nil, errors.New("email is empty") return nil, fmt.Errorf("email is empty")
} }
if err := ur.db.First(&user, "email = ?", email).Error; err != nil { if err := ur.db.First(&user, "email = ?", email).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found") return nil, fmt.Errorf("user not found")
} }
return nil, err return nil, err
} }
+2 -3
View File
@@ -1,8 +1,7 @@
package userrepository package userrepository
import ( import (
"errors" "fmt"
userdomain "legalgo-BE-go/internal/domain/user" userdomain "legalgo-BE-go/internal/domain/user"
) )
@@ -10,7 +9,7 @@ func (ur *accessor) GetUserByID(id string) (*userdomain.User, error) {
var user userdomain.User var user userdomain.User
if id == "" { if id == "" {
return nil, errors.New("id is empty") return nil, fmt.Errorf("id is empty")
} }
if err := ur.db. if err := ur.db.
+6 -5
View File
@@ -1,21 +1,21 @@
package userrepository package userrepository
import ( import (
"errors" "fmt"
userdomain "legalgo-BE-go/internal/domain/user" userdomain "legalgo-BE-go/internal/domain/user"
) )
func (ur *accessor) GetUserProfile(email string) (*userdomain.UserProfile, error) { func (ur *accessor) GetUserProfile(id string) (*userdomain.UserProfile, error) {
var user *userdomain.User var user *userdomain.User
if email == "" { if id == "" {
return nil, errors.New("email is empty") return nil, fmt.Errorf("email is empty")
} }
if err := ur.db. if err := ur.db.
Preload("Subscribe"). Preload("Subscribe").
Preload("Subscribe.SubscribePlan"). Preload("Subscribe.SubscribePlan").
First(&user, "email = ?", email). First(&user, "id = ?", id).
Error; err != nil { Error; err != nil {
return nil, err return nil, err
} }
@@ -25,6 +25,7 @@ func (ur *accessor) GetUserProfile(email string) (*userdomain.UserProfile, error
Email: user.Email, Email: user.Email,
Phone: user.Phone, Phone: user.Phone,
Subscribe: user.Subscribe, Subscribe: user.Subscribe,
CreatedAt: user.CreatedAt,
} }
return userProfile, nil return userProfile, nil
+68
View File
@@ -0,0 +1,68 @@
package adshttp
import (
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
adsdomain "legalgo-BE-go/internal/domain/ads"
adssvc "legalgo-BE-go/internal/services/ads"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func Create(
router chi.Router,
adsSvc adssvc.Ads,
validate *validator.Validate,
) {
router.
With(authmiddleware.Authorize()).
Post("/ads/create", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var spec adsdomain.AdsReq
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed to unmarshal body",
)
return
}
if err := validate.Struct(spec); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
if err := adsSvc.Create(spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "ads created successfully",
})
})
}
+53
View File
@@ -0,0 +1,53 @@
package adshttp
import (
"fmt"
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
adssvc "legalgo-BE-go/internal/services/ads"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
func Delete(
router chi.Router,
adsSvc adssvc.Ads,
) {
router.
With(authmiddleware.Authorize()).
Delete("/ads/{ads_id}/delete", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
adsID := chi.URLParam(r, "ads_id")
if adsID == "" {
response.RespondJsonErrorWithCode(
ctx,
w,
fmt.Errorf("ads id is not provided"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"ads id is not provided",
)
return
}
if err := adsSvc.Delete(adsID); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "ads has been deleted",
})
})
}
+32
View File
@@ -0,0 +1,32 @@
package adshttp
import (
adssvc "legalgo-BE-go/internal/services/ads"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetAll(
router chi.Router,
adsSvc adssvc.Ads,
) {
router.Get("/ads", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
subsPlan, err := adsSvc.GetAll()
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, subsPlan)
})
}
+10
View File
@@ -0,0 +1,10 @@
package adshttp
import "go.uber.org/fx"
var Module = fx.Module("ads-http", fx.Invoke(
Create,
GetAll,
Update,
Delete,
))
+82
View File
@@ -0,0 +1,82 @@
package adshttp
import (
"fmt"
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
adsdomain "legalgo-BE-go/internal/domain/ads"
adssvc "legalgo-BE-go/internal/services/ads"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func Update(
router chi.Router,
validate *validator.Validate,
adsSvc adssvc.Ads,
) {
router.
With(authmiddleware.Authorize()).
Put("/ads/{ads_id}/update", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
adsID := chi.URLParam(r, "ads_id")
if adsID == "" {
response.RespondJsonErrorWithCode(
ctx,
w,
fmt.Errorf("ads id is not provided"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"ads id is not provided",
)
return
}
var spec adsdomain.AdsReq
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed to unmarshal body",
)
return
}
if err := validate.Struct(spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
if err := adsSvc.Update(adsID, spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "update ads success",
})
})
}
+86
View File
@@ -0,0 +1,86 @@
package logshttp
import (
logsdomain "legalgo-BE-go/internal/domain/logs"
logssvc "legalgo-BE-go/internal/services/logs"
usersvc "legalgo-BE-go/internal/services/user"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func CreateLogAds(
router chi.Router,
userSvc usersvc.User,
logsSvc logssvc.Log,
validate *validator.Validate,
) {
router.Post("/logs/ads", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var specReq logsdomain.LogsSpec
var spec logsdomain.LogsRequest
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed unmarshal body",
)
return
}
if err := validate.Struct(spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
specReq.ContentID = spec.AdsID
userDetail, _ := utils.GetTokenDetail(r)
if userDetail.ID != "" {
specReq.UserID = &userDetail.ID
}
if ip := r.Header.Get("X-Ip-Address"); ip != "" {
specReq.IP = &ip
}
if userAgent := r.Header.Get("X-User-Agent"); userAgent != "" {
specReq.UserAgent = &userAgent
}
if err := logsSvc.CreateLogAds(specReq); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "logs ads recorded successfully",
})
})
}
+37
View File
@@ -0,0 +1,37 @@
package logshttp
import (
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
logssvc "legalgo-BE-go/internal/services/logs"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetUserAds(
router chi.Router,
logSvc logssvc.Log,
) {
router.With(authmiddleware.Authorize()).Get("/logs/ads", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
userDetail, err := utils.GetTokenDetail(r)
subsPlan, err := logSvc.GetAllLogAds(userDetail.ID)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, subsPlan)
})
}
+8
View File
@@ -0,0 +1,8 @@
package logshttp
import "go.uber.org/fx"
var Module = fx.Module("logs-http", fx.Invoke(
CreateLogAds,
GetUserAds,
))
+1 -14
View File
@@ -59,20 +59,7 @@ func Create(
return return
} }
staffProfile, err := staffRepo.GetStaffByEmail(destructedToken.Email) if err := newsSvc.Create(spec, destructedToken.ID); err != nil {
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
if err := newsSvc.Create(spec, staffProfile.ID); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
w, w,
+9 -2
View File
@@ -15,7 +15,7 @@ func GetAll(
) { ) {
router.Get("/news", func(w http.ResponseWriter, r *http.Request) { router.Get("/news", func(w http.ResponseWriter, r *http.Request) {
var ( var (
news []newsdomain.News news []newsdomain.NewsResponse
err error err error
) )
ctx := r.Context() ctx := r.Context()
@@ -23,8 +23,15 @@ func GetAll(
category := query.Get("categories") category := query.Get("categories")
tags := query.Get("tags") tags := query.Get("tags")
activeOnly := query.Get("active")
search := query.Get("q")
news, err = newsSvc.GetAll(category, tags) news, err = newsSvc.GetAll(newsdomain.Filter{
Category: category,
Tags: tags,
Active: activeOnly,
Search: search,
})
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
+77
View File
@@ -0,0 +1,77 @@
package newshttp
import (
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
logssvc "legalgo-BE-go/internal/services/logs"
newssvc "legalgo-BE-go/internal/services/news"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetByID(
router chi.Router,
newsSvc newssvc.News,
logSvc logssvc.Log,
) {
router.With(authmiddleware.Authorize()).Get("/staff/news/{id}", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := chi.URLParam(r, "id")
token, err := utils.GetToken(r)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
staffDetail, err := utils.DestructToken(token)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
if staffDetail.Role != "staff" {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrUnauthorized.Code,
response.ErrUnauthorized.HttpCode,
"unauthorized",
)
return
}
news, err := newsSvc.GetByID(id)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, news)
})
}
+36
View File
@@ -1,8 +1,11 @@
package newshttp package newshttp
import ( import (
logsdomain "legalgo-BE-go/internal/domain/logs"
logssvc "legalgo-BE-go/internal/services/logs"
newssvc "legalgo-BE-go/internal/services/news" newssvc "legalgo-BE-go/internal/services/news"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@@ -11,6 +14,7 @@ import (
func GetBySlug( func GetBySlug(
router chi.Router, router chi.Router,
newsSvc newssvc.News, newsSvc newssvc.News,
logSvc logssvc.Log,
) { ) {
router.Get("/news/{slug}", func(w http.ResponseWriter, r *http.Request) { router.Get("/news/{slug}", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@@ -29,6 +33,38 @@ func GetBySlug(
return return
} }
userDetail, _ := utils.GetTokenDetail(r)
if userDetail.Role != "staff" {
var specReq logsdomain.LogsSpec
specReq.ContentID = news.ID
if userDetail.ID != "" {
specReq.UserID = &userDetail.ID
}
if ip := r.Header.Get("X-Ip-Address"); ip != "" {
specReq.IP = &ip
}
if userAgent := r.Header.Get("X-User-Agent"); userAgent != "" {
specReq.UserAgent = &userAgent
}
if err := logSvc.CreateLogNews(specReq); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
}
response.RespondJsonSuccess(ctx, w, news) response.RespondJsonSuccess(ctx, w, news)
}) })
} }
+1
View File
@@ -5,6 +5,7 @@ import "go.uber.org/fx"
var Module = fx.Module("news", fx.Invoke( var Module = fx.Module("news", fx.Invoke(
GetAll, GetAll,
GetBySlug, GetBySlug,
GetByID,
Create, Create,
Update, Update,
Delete, Delete,
+3 -16
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
newsdomain "legalgo-BE-go/internal/domain/news" newsdomain "legalgo-BE-go/internal/domain/news"
authsvc "legalgo-BE-go/internal/services/auth"
newssvc "legalgo-BE-go/internal/services/news" newssvc "legalgo-BE-go/internal/services/news"
staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -16,7 +16,7 @@ import (
func Update( func Update(
router chi.Router, router chi.Router,
newsSvc newssvc.News, newsSvc newssvc.News,
authSvc authsvc.Auth, authSvc staffsvc.Auth,
) { ) {
router.With(authmiddleware.Authorize()). router.With(authmiddleware.Authorize()).
Put("/news/{news_id}/update", func(w http.ResponseWriter, r *http.Request) { Put("/news/{news_id}/update", func(w http.ResponseWriter, r *http.Request) {
@@ -48,19 +48,6 @@ func Update(
return return
} }
staff, err := authSvc.GetStaffProfile(destructedToken.Email)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
var spec newsdomain.NewsUpdate var spec newsdomain.NewsUpdate
if err := utils.UnmarshalBody(r, &spec); err != nil { if err := utils.UnmarshalBody(r, &spec); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
@@ -76,7 +63,7 @@ func Update(
spec.ID = newsID spec.ID = newsID
if err := newsSvc.Update(staff.ID, spec); err != nil { if err := newsSvc.Update(destructedToken.ID, spec); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
w, w,
+7 -1
View File
@@ -1,10 +1,13 @@
package internalhttp package internalhttp
import ( import (
adshttp "legalgo-BE-go/internal/api/http/ads"
categoryhttp "legalgo-BE-go/internal/api/http/category" categoryhttp "legalgo-BE-go/internal/api/http/category"
logshttp "legalgo-BE-go/internal/api/http/logs"
newshttp "legalgo-BE-go/internal/api/http/news" newshttp "legalgo-BE-go/internal/api/http/news"
osshttp "legalgo-BE-go/internal/api/http/oss" osshttp "legalgo-BE-go/internal/api/http/oss"
staffhttp "legalgo-BE-go/internal/api/http/staffhttp" staffhttp "legalgo-BE-go/internal/api/http/staff"
subscribehttp "legalgo-BE-go/internal/api/http/subscribe"
subscribeplanhttp "legalgo-BE-go/internal/api/http/subscribe_plan" subscribeplanhttp "legalgo-BE-go/internal/api/http/subscribe_plan"
taghttp "legalgo-BE-go/internal/api/http/tag" taghttp "legalgo-BE-go/internal/api/http/tag"
userhttp "legalgo-BE-go/internal/api/http/user" userhttp "legalgo-BE-go/internal/api/http/user"
@@ -29,6 +32,9 @@ var Module = fx.Module("router",
newshttp.Module, newshttp.Module,
osshttp.Module, osshttp.Module,
userhttp.Module, userhttp.Module,
subscribehttp.Module,
adshttp.Module,
logshttp.Module,
) )
func initRouter() chi.Router { func initRouter() chi.Router {
+59
View File
@@ -0,0 +1,59 @@
package staffhttp
import (
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
)
func GetStaffs(
router chi.Router,
staffSvc staffsvc.Auth,
) {
router.With(authmiddleware.Authorize()).Get("/staff/get-all", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
staffDetail, err := utils.GetTokenDetail(r)
if err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed to get staff token",
)
return
}
if staffDetail.Role != "staff" {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrUnauthorized.Code,
response.ErrUnauthorized.HttpCode,
"unauthorized",
)
return
}
staffs, err := staffSvc.GetStaffs()
if err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, staffs)
})
}
@@ -2,7 +2,7 @@ package staffhttp
import ( import (
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
authsvc "legalgo-BE-go/internal/services/auth" staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -12,7 +12,7 @@ import (
func GetUsers( func GetUsers(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, authSvc staffsvc.Auth,
) { ) {
router.With(authmiddleware.Authorize()).Get("/staff/users", func(w http.ResponseWriter, r *http.Request) { router.With(authmiddleware.Authorize()).Get("/staff/users", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@@ -5,7 +5,7 @@ import (
responsedomain "legalgo-BE-go/internal/domain/reponse" responsedomain "legalgo-BE-go/internal/domain/reponse"
staffdomain "legalgo-BE-go/internal/domain/staff" staffdomain "legalgo-BE-go/internal/domain/staff"
authsvc "legalgo-BE-go/internal/services/auth" staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
@@ -16,7 +16,7 @@ import (
func Login( func Login(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, authSvc staffsvc.Auth,
validate *validator.Validate, validate *validator.Validate,
rdb *redis.Client, rdb *redis.Client,
) { ) {
@@ -49,7 +49,7 @@ func Login(
return return
} }
token, err := authSvc.LoginAsStaff(spec) token, err := authSvc.Login(spec)
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
@@ -9,5 +9,6 @@ var Module = fx.Module("auth-api",
Update, Update,
GetProfile, GetProfile,
GetUsers, GetUsers,
GetStaffs,
), ),
) )
@@ -1,7 +1,7 @@
package staffhttp package staffhttp
import ( import (
authsvc "legalgo-BE-go/internal/services/auth" staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -11,7 +11,7 @@ import (
func GetProfile( func GetProfile(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, authSvc staffsvc.Auth,
) { ) {
router.Get("/staff/profile", func(w http.ResponseWriter, r *http.Request) { router.Get("/staff/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@@ -28,7 +28,7 @@ func GetProfile(
return return
} }
staffProfile, err := authSvc.GetStaffProfile(destructedToken.Email) staffProfile, err := authSvc.GetProfile(destructedToken.ID)
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
@@ -3,9 +3,8 @@ package staffhttp
import ( import (
"net/http" "net/http"
responsedomain "legalgo-BE-go/internal/domain/reponse"
staffdomain "legalgo-BE-go/internal/domain/staff" staffdomain "legalgo-BE-go/internal/domain/staff"
authsvc "legalgo-BE-go/internal/services/auth" staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
@@ -17,7 +16,7 @@ import (
func Register( func Register(
router chi.Router, router chi.Router,
validate *validator.Validate, validate *validator.Validate,
authSvc authsvc.Auth, authSvc staffsvc.Auth,
rdb *redis.Client, rdb *redis.Client,
) { ) {
router.Post("/staff/register", func(w http.ResponseWriter, r *http.Request) { router.Post("/staff/register", func(w http.ResponseWriter, r *http.Request) {
@@ -49,7 +48,7 @@ func Register(
return return
} }
token, err := authSvc.RegisterStaff(spec) _, err := authSvc.Register(spec)
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
@@ -62,21 +61,10 @@ func Register(
return return
} }
if err := utils.StoreTokenRedis(ctx, rdb, token, spec.Email); err != nil { response.RespondJsonSuccess(ctx, w, struct {
response.ResponseWithErrorCode( Message string
ctx, }{
w, Message: "staff created successfully.",
err, })
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
responsePayload := &responsedomain.Auth{
Token: token,
}
response.RespondJsonSuccess(ctx, w, responsePayload)
}) })
} }
@@ -1,9 +1,8 @@
package staffhttp package staffhttp
import ( import (
"errors"
staffdomain "legalgo-BE-go/internal/domain/staff" staffdomain "legalgo-BE-go/internal/domain/staff"
authsvc "legalgo-BE-go/internal/services/auth" staffsvc "legalgo-BE-go/internal/services/staff"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -13,25 +12,25 @@ import (
func Update( func Update(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, authSvc staffsvc.Auth,
) { ) {
router.Patch("/staff/{id}/update", func(w http.ResponseWriter, r *http.Request) { router.Put("/staff/update", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
id := chi.URLParam(r, "id") destructedToken, err := utils.GetTokenDetail(r)
if id == "" { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
w, w,
errors.New("provided id is empty"), err,
response.ErrBadRequest.Code, response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode, response.ErrBadRequest.HttpCode,
"required params is not provided", err.Error(),
) )
return return
} }
var spec staffdomain.StaffRegister var spec staffdomain.StaffUpdate
if err := utils.UnmarshalBody(r, &spec); err != nil { if err := utils.UnmarshalBody(r, &spec); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
@@ -45,14 +44,7 @@ func Update(
return return
} }
staff := staffdomain.Staff{ if err := authSvc.Update(destructedToken.ID, spec); err != nil {
ID: id,
Email: spec.Email,
Password: spec.Password,
Name: spec.Name,
}
if err := authSvc.UpdateStaff(staff); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
w, w,
+3 -1
View File
@@ -2,4 +2,6 @@ package subscribehttp
import "go.uber.org/fx" import "go.uber.org/fx"
var Module = fx.Module("subscribe", fx.Invoke()) var Module = fx.Module("subscribe", fx.Invoke(
Update,
))
+12 -4
View File
@@ -1,9 +1,9 @@
package subscribehttp package subscribehttp
import ( import (
userrepository "legalgo-BE-go/internal/accessor/user"
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
userdomain "legalgo-BE-go/internal/domain/user" userdomain "legalgo-BE-go/internal/domain/user"
authsvc "legalgo-BE-go/internal/services/auth"
subscribesvc "legalgo-BE-go/internal/services/subscribe" subscribesvc "legalgo-BE-go/internal/services/subscribe"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
@@ -14,7 +14,7 @@ import (
func Update( func Update(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, userRepo userrepository.User,
subSvc subscribesvc.Subscribe, subSvc subscribesvc.Subscribe,
) { ) {
router. router.
@@ -60,9 +60,11 @@ func Update(
return return
} }
user, err := authSvc.GetUserProfile(detail.Email) user, err := userRepo.GetUserProfile(detail.ID)
if err := subSvc.Update(user.ID, body); err != nil { body.ID = user.Subscribe.ID
if err := subSvc.Update(body); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
w, w,
@@ -73,5 +75,11 @@ func Update(
) )
return return
} }
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "update user plan success",
})
}) })
} }
+1 -1
View File
@@ -49,7 +49,7 @@ func CreateSubscribePlan(
return return
} }
if err := subsSvc.CreatePlan(spec); err != nil { if err := subsSvc.Create(spec); err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
w, w,
@@ -0,0 +1,53 @@
package subscribeplanhttp
import (
"fmt"
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
subscribeplansvc "legalgo-BE-go/internal/services/subscribe_plan"
"legalgo-BE-go/internal/utilities/response"
"net/http"
"github.com/go-chi/chi/v5"
)
func Delete(
router chi.Router,
subscribePlanSvc subscribeplansvc.SubscribePlan,
) {
router.
With(authmiddleware.Authorize()).
Delete("/subscribe-plan/{subsplan_id}/delete", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
subsPlanID := chi.URLParam(r, "subsplan_id")
if subsPlanID == "" {
response.RespondJsonErrorWithCode(
ctx,
w,
fmt.Errorf("subscribe plan id is not provided"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"subscribe plan id is not provided",
)
return
}
if err := subscribePlanSvc.Delete(subsPlanID); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "subscribe plan has been deleted",
})
})
}
@@ -6,5 +6,7 @@ var Module = fx.Module("subscribe-plan",
fx.Invoke( fx.Invoke(
CreateSubscribePlan, CreateSubscribePlan,
GetAllPlan, GetAllPlan,
Update,
Delete,
), ),
) )
@@ -0,0 +1,82 @@
package subscribeplanhttp
import (
"fmt"
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
subscribeplansvc "legalgo-BE-go/internal/services/subscribe_plan"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func Update(
router chi.Router,
validate *validator.Validate,
subsPlanSvc subscribeplansvc.SubscribePlan,
) {
router.
With(authmiddleware.Authorize()).
Put("/subscribe-plan/{subsplan_id}/update", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
tagID := chi.URLParam(r, "subsplan_id")
if tagID == "" {
response.RespondJsonErrorWithCode(
ctx,
w,
fmt.Errorf("subscribe plan id is not provided"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"subscribe plan id is not provided",
)
return
}
var spec subscribeplandomain.SubscribePlanUpdate
if err := utils.UnmarshalBody(r, &spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed to unmarshal body",
)
return
}
if err := validate.Struct(spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
if err := subsPlanSvc.Update(tagID, spec); err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
response.RespondJsonSuccess(ctx, w, struct {
Message string
}{
Message: "update subscribe plan success",
})
})
}
+6 -6
View File
@@ -16,23 +16,23 @@ func Delete(
) { ) {
router. router.
With(authmiddleware.Authorize()). With(authmiddleware.Authorize()).
Delete("/tag/{category_id}/delete", func(w http.ResponseWriter, r *http.Request) { Delete("/tag/{tag_id}/delete", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
categoryID := chi.URLParam(r, "category_id") tagID := chi.URLParam(r, "tag_id")
if categoryID == "" { if tagID == "" {
response.RespondJsonErrorWithCode( response.RespondJsonErrorWithCode(
ctx, ctx,
w, w,
fmt.Errorf("category id is not provided"), fmt.Errorf("tag id is not provided"),
response.ErrBadRequest.Code, response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode, response.ErrBadRequest.HttpCode,
"category id is not provided", "tag id is not provided",
) )
return return
} }
if err := tagSvc.Delete(categoryID); err != nil { if err := tagSvc.Delete(tagID); err != nil {
response.RespondJsonErrorWithCode( response.RespondJsonErrorWithCode(
ctx, ctx,
w, w,
+1 -2
View File
@@ -14,8 +14,7 @@ func GetAll(
) { ) {
router.Get("/tag", func(w http.ResponseWriter, r *http.Request) { router.Get("/tag", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
tags, err := tagSvc.GetAllModel() tags, err := tagSvc.GetAll()
// tags, err := tagSvc.GetAll()
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
+3 -3
View File
@@ -3,7 +3,7 @@ package userhttp
import ( import (
responsedomain "legalgo-BE-go/internal/domain/reponse" responsedomain "legalgo-BE-go/internal/domain/reponse"
userdomain "legalgo-BE-go/internal/domain/user" userdomain "legalgo-BE-go/internal/domain/user"
authsvc "legalgo-BE-go/internal/services/auth" usersvc "legalgo-BE-go/internal/services/user"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -15,7 +15,7 @@ import (
func Login( func Login(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, userSvc usersvc.User,
validate *validator.Validate, validate *validator.Validate,
rdb *redis.Client, rdb *redis.Client,
) { ) {
@@ -48,7 +48,7 @@ func Login(
return return
} }
token, err := authSvc.LoginAsUser(spec) token, err := userSvc.LoginAsUser(spec)
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
+3 -3
View File
@@ -1,7 +1,7 @@
package userhttp package userhttp
import ( import (
authsvc "legalgo-BE-go/internal/services/auth" usersvc "legalgo-BE-go/internal/services/user"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -11,7 +11,7 @@ import (
func GetProfile( func GetProfile(
router chi.Router, router chi.Router,
authSvc authsvc.Auth, userSvc usersvc.User,
) { ) {
router.Get("/user/profile", func(w http.ResponseWriter, r *http.Request) { router.Get("/user/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@@ -28,7 +28,7 @@ func GetProfile(
return return
} }
userProfile, err := authSvc.GetUserProfile(destructedToken.Email) userProfile, err := userSvc.GetUserProfile(destructedToken.ID)
if err != nil { if err != nil {
response.ResponseWithErrorCode( response.ResponseWithErrorCode(
ctx, ctx,
+2 -2
View File
@@ -3,7 +3,7 @@ package userhttp
import ( import (
responsedomain "legalgo-BE-go/internal/domain/reponse" responsedomain "legalgo-BE-go/internal/domain/reponse"
userdomain "legalgo-BE-go/internal/domain/user" userdomain "legalgo-BE-go/internal/domain/user"
authsvc "legalgo-BE-go/internal/services/auth" usersvc "legalgo-BE-go/internal/services/user"
"legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils" "legalgo-BE-go/internal/utilities/utils"
"net/http" "net/http"
@@ -16,7 +16,7 @@ import (
func Register( func Register(
router chi.Router, router chi.Router,
validate *validator.Validate, validate *validator.Validate,
authSvc authsvc.Auth, authSvc usersvc.User,
rdb *redis.Client, rdb *redis.Client,
) { ) {
router.Post("/user/register", func(w http.ResponseWriter, r *http.Request) { router.Post("/user/register", func(w http.ResponseWriter, r *http.Request) {
+27
View File
@@ -0,0 +1,27 @@
package adsdomain
import (
"time"
)
type Ads struct {
ID string `json:"id"`
ImageUrl string `json:"image_url"`
Url string `json:"url"`
StartDate *time.Time `json:"start_date"`
EndDate *time.Time `json:"end_date"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type AdsResponse struct {
Ads
Clicked int64 `json:"clicked"`
}
type AdsReq struct {
Image string `json:"image" validate:"required"`
URL string `json:"url" validate:"required"`
StartDate *time.Time `json:"start_date" validate:"required"`
EndDate *time.Time `json:"end_date" validate:"required"`
}
+1
View File
@@ -4,4 +4,5 @@ type AuthToken struct {
Email string Email string
SessionID string SessionID string
Role string Role string
ID string
} }
+22
View File
@@ -0,0 +1,22 @@
package logsdomain
import (
adsdomain "legalgo-BE-go/internal/domain/ads"
)
type LogsRequest struct {
AdsID string `json:"ads_id" validate:"required"`
}
type LogsSpec struct {
ContentID string `json:"content_id" validate:"required"`
IP *string
UserID *string
UserAgent *string
Category string
}
type LogResponse struct {
ID string `json:"id"`
News []adsdomain.Ads `json:"news"`
}
+13 -2
View File
@@ -27,8 +27,8 @@ type News struct {
Title string `json:"title"` Title string `json:"title"`
Content string `json:"content"` Content string `json:"content"`
FeaturedImage string `json:"featured_image"` FeaturedImage string `json:"featured_image"`
Tags []tagdomain.Tag `gorm:"many2many:news_tags" json:"tags"` Tags []tagdomain.Tag `gorm:"many2many:news_tags;foreignKey:ID;joinForeignKey:news_id;References:ID;joinReferences:tag_id" json:"tags"`
Categories []categorydomain.Category `gorm:"many2many:news_categories" json:"categories"` Categories []categorydomain.Category `gorm:"many2many:news_categories;foreignKey:ID;joinForeignKey:news_id;References:ID;joinReferences:category_id" json:"categories"`
IsPremium bool `json:"is_premium"` IsPremium bool `json:"is_premium"`
Slug string `json:"slug"` Slug string `json:"slug"`
AuthorID string `json:"author_id"` AuthorID string `json:"author_id"`
@@ -39,6 +39,11 @@ type News struct {
Author Staff `json:"author"` Author Staff `json:"author"`
} }
type NewsResponse struct {
News
Views int64 `json:"views"`
}
type NewsUpdate struct { type NewsUpdate struct {
ID string `json:"id"` ID string `json:"id"`
Title string `json:"title"` Title string `json:"title"`
@@ -50,7 +55,13 @@ type NewsUpdate struct {
LiveAt time.Time `json:"live_at"` LiveAt time.Time `json:"live_at"`
} }
type Filter struct {
Category, Tags, Active, Search string
}
type NewsFilter struct { type NewsFilter struct {
Tags []string Tags []string
Category []string Category []string
Active string
Search string
} }
+6
View File
@@ -15,6 +15,12 @@ type StaffRegister struct {
ProfilePicture string `json:"profile_picture"` ProfilePicture string `json:"profile_picture"`
} }
type StaffUpdate struct {
Email string `json:"email" validate:"required"`
Name string `json:"name" validate:"required"`
ProfilePicture string `json:"profile_picture"`
}
type StaffProfile struct { type StaffProfile struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
+9 -19
View File
@@ -1,28 +1,18 @@
package subscribedomain package subscribedomain
import ( import (
subscribeplandm "legalgo-BE-go/internal/domain/subscribe_plan_model" subscribeplan "legalgo-BE-go/internal/domain/subscribe_plan"
"time" "time"
) )
type SubscribeDepecrate struct {
ID string `json:"id"`
SubscribePlanID string `json:"subscribe_plan_id"`
}
type SubscribeUpdateReqDepecrate struct {
ID string `json:"id"`
Status string `json:"status"`
}
// refactored
type Subscribe struct { type Subscribe struct {
ID string `gorm:"primaryKey" json:"id"` ID string `json:"id"`
SubscribePlanID string `gorm:"not null" json:"subscribe_plan_id"` SubscribePlanID string `json:"subscribe_plan_id"`
StartDate time.Time `gorm:"default:CURRENT_TIMESTAMP"` StartDate time.Time `json:"start_date"`
EndDate time.Time `gorm:"default:null"` EndDate *time.Time `json:"end_date"`
Status string `gorm:"default:'inactive'"` Status int8 `json:"status"`
AutoRenew bool `gorm:"default:true"` AutoRenew bool `json:"auto_renew"`
UpdatedAt time.Time `json:"updated_at"`
SubscribePlan subscribeplandm.SubscribePlan `gorm:"foreignKey:SubscribePlanID;constraint:OnDelete:CASCADE" json:"subscribe_plan"` SubscribePlan subscribeplan.SubscribePlan `gorm:"foreignKey:SubscribePlanID" json:"subscribe_plan"`
} }
@@ -1,17 +0,0 @@
package subscribedm
import (
subscribeplandm "legalgo-BE-go/internal/domain/subscribe_plan_model"
"time"
)
type Subscribe struct {
ID string `json:"id"`
SubscribePlanID string `json:"subscribe_plan_id"`
StartDate time.Time `json:"start_date"`
EndDate *time.Time `json:"end_date"`
Status string `json:"status"`
AutoRenew bool `json:"auto_renew"`
SubscribePlan subscribeplandm.SubscribePlan `gorm:"foreignKey:SubscribePlanID" json:"subscribe_plan"`
}
+26 -7
View File
@@ -1,12 +1,31 @@
package subscribeplandomain package subscribeplandomain
type SubscribePlanReq struct { import "time"
Code string `json:"code" validate:"required"`
Name string `json:"name" validate:"required"`
}
type SubscribePlan struct { type SubscribePlan struct {
ID string `json:"id"` ID string `json:"id"`
Code string `json:"code"` Code string `json:"code"`
Name string `json:"name"` Name string `json:"name"`
Length int `json:"length"`
Price float32 `json:"price"`
Status int8 `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type SubscribePlanUpdate struct {
Code string `json:"code" validate:"required"`
Name string `json:"name" validate:"required"`
Length int `json:"length"`
Price float32 `json:"price"`
Status int8 `json:"status"`
UpdatedAt time.Time `json:"updated_at"`
}
type SubscribePlanReq struct {
Code string `json:"code" validate:"required"`
Name string `json:"name" validate:"required"`
Status int8 `json:"status"`
Length int `json:"length"`
Price float32 `json:"price"`
} }
@@ -1,8 +0,0 @@
package subscribeplandm
// refactored
type SubscribePlan struct {
ID string `json:"id"`
Code string `json:"code"`
Name string `json:"name"`
}
+22 -12
View File
@@ -1,15 +1,19 @@
package userdomain package userdomain
import subscribedm "legalgo-BE-go/internal/domain/subscribe_model" import (
subscribe "legalgo-BE-go/internal/domain/subscribe"
"time"
)
type User struct { type User struct {
ID string `json:"id"` ID string `json:"id"`
SubscribeID string `json:"subscribe_id"` SubscribeID string `json:"subscribe_id"`
Password string `json:"password"` Password string `json:"password"`
Email string `json:"email"` Email string `json:"email"`
Phone string `json:"phone"` Phone string `json:"phone"`
CreatedAt time.Time `json:"created_at"`
Subscribe subscribedm.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"` Subscribe subscribe.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"`
} }
type UserRegister struct { type UserRegister struct {
@@ -20,11 +24,12 @@ type UserRegister struct {
} }
type UserProfile struct { type UserProfile struct {
ID string `json:"id"` ID string `json:"id"`
Email string `json:"email"` Email string `json:"email"`
Phone string `json:"phone"` Phone string `json:"phone"`
CreatedAt time.Time `json:"created_at"`
Subscribe subscribedm.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"` Subscribe subscribe.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"`
} }
type UserLogin struct { type UserLogin struct {
@@ -33,5 +38,10 @@ type UserLogin struct {
} }
type UserSubsUpdate struct { type UserSubsUpdate struct {
Status string `json:"status"` ID string `json:"id"`
Status int8 `json:"status"`
SubscribePlanID string `json:"subscribe_plan_id"`
AutoRenew bool `json:"auto_renew"`
StartDate time.Time `json:"start_date"`
EndDate *time.Time `json:"end_date"`
} }
+1
View File
@@ -10,4 +10,5 @@ const (
ISSUED_AT JWTClaim = "iat" ISSUED_AT JWTClaim = "iat"
RESOURCES JWTClaim = "resources" RESOURCES JWTClaim = "resources"
ROLE JWTClaim = "role" ROLE JWTClaim = "role"
ID JWTClaim = "skb"
) )
+29
View File
@@ -0,0 +1,29 @@
package adssvc
import (
"fmt"
adsdomain "legalgo-BE-go/internal/domain/ads"
"strings"
"github.com/google/uuid"
)
func (i *impl) Create(spec adsdomain.AdsReq) error {
if !(strings.HasPrefix(spec.Image, "http")) {
return fmt.Errorf("image url is not started with http")
}
if !(strings.HasPrefix(spec.URL, "http")) {
return fmt.Errorf("url is not started with http")
}
newSpec := adsdomain.Ads{
ID: uuid.NewString(),
ImageUrl: spec.Image,
Url: spec.URL,
StartDate: spec.StartDate,
EndDate: spec.EndDate,
}
return i.adsRepo.Create(newSpec)
}
+5
View File
@@ -0,0 +1,5 @@
package adssvc
func (i *impl) Delete(id string) error {
return i.adsRepo.Delete(id)
}
+7
View File
@@ -0,0 +1,7 @@
package adssvc
import adsdomain "legalgo-BE-go/internal/domain/ads"
func (i *impl) GetAll() ([]adsdomain.AdsResponse, error) {
return i.adsRepo.GetAll()
}
+25
View File
@@ -0,0 +1,25 @@
package adssvc
import (
adsrepository "legalgo-BE-go/internal/accessor/ads"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
type impl struct {
adsRepo adsrepository.Ads
}
type Ads interface {
Create(adsdomain.AdsReq) error
GetAll() ([]adsdomain.AdsResponse, error)
Update(string, adsdomain.AdsReq) error
Delete(string) error
}
func New(
adsRepo adsrepository.Ads,
) Ads {
return &impl{
adsRepo,
}
}

Some files were not shown because too many files have changed in this diff Show More