From d8f6968f64274ab7160997407c522559fcb1c407 Mon Sep 17 00:00:00 2001 From: ericprd Date: Thu, 20 Mar 2025 11:11:08 +0800 Subject: [PATCH] fix: improvement logs and record news access --- database/{log_ads_model.go => log_model.go} | 3 +- database/log_news_model.go | 11 ------ database/new_db.go | 3 +- internal/accessor/ads/get-all.go | 4 +- internal/accessor/log/create_log_ads.go | 5 ++- internal/accessor/log/impl.go | 2 +- internal/accessor/news/get_all.go | 8 +++- internal/api/http/news/get_by_slug.go | 41 +++++++++++++++++++++ internal/domain/logs/spec.go | 9 +++-- internal/domain/news/spec.go | 1 + internal/services/logs/create_logs_ads.go | 3 +- internal/services/logs/create_logs_news.go | 15 ++++++++ internal/services/logs/impl.go | 1 + 13 files changed, 81 insertions(+), 25 deletions(-) rename database/{log_ads_model.go => log_model.go} (85%) delete mode 100644 database/log_news_model.go create mode 100644 internal/services/logs/create_logs_news.go diff --git a/database/log_ads_model.go b/database/log_model.go similarity index 85% rename from database/log_ads_model.go rename to database/log_model.go index 749b7fc..d65ed64 100644 --- a/database/log_ads_model.go +++ b/database/log_model.go @@ -2,12 +2,13 @@ package database import "time" -type LogAds struct { +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"` } diff --git a/database/log_news_model.go b/database/log_news_model.go deleted file mode 100644 index d173e76..0000000 --- a/database/log_news_model.go +++ /dev/null @@ -1,11 +0,0 @@ -package database - -import "time" - -type LogNews struct { - ID string `gorm:"primaryKey;not null" json:"id"` - NewsID string `gorm:"not null" json:"news_id"` - UserID string `gorm:"not null" json:"user_id"` - CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` - UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` -} diff --git a/database/new_db.go b/database/new_db.go index d76045b..4e1b436 100644 --- a/database/new_db.go +++ b/database/new_db.go @@ -55,7 +55,6 @@ func (db *DB) Migrate() error { &Tag{}, &Category{}, &Ads{}, - &LogAds{}, - &LogNews{}, + &ContentLog{}, ) } diff --git a/internal/accessor/ads/get-all.go b/internal/accessor/ads/get-all.go index a5e0d11..b95a20c 100644 --- a/internal/accessor/ads/get-all.go +++ b/internal/accessor/ads/get-all.go @@ -9,8 +9,8 @@ func (a *accessor) GetAll() ([]adsdomain.AdsResponse, error) { var ads []adsdomain.AdsResponse if err := a.db.Table("ads"). - Select("ads.*, COUNT(log_ads.content_id) as clicked"). - Joins("LEFT JOIN log_ads ON log_ads.content_id = ads.id"). + 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) diff --git a/internal/accessor/log/create_log_ads.go b/internal/accessor/log/create_log_ads.go index e8d40e7..42ff8fc 100644 --- a/internal/accessor/log/create_log_ads.go +++ b/internal/accessor/log/create_log_ads.go @@ -7,10 +7,11 @@ import ( "github.com/google/uuid" ) -func (a *accessor) CreateLogAds(spec logsdomain.LogsSpec) error { - newSpec := database.LogAds{ +func (a *accessor) CreateLog(spec logsdomain.LogsSpec) error { + newSpec := database.ContentLog{ ID: uuid.NewString(), ContentID: spec.ContentID, + Category: spec.Category, } if spec.UserID != nil { diff --git a/internal/accessor/log/impl.go b/internal/accessor/log/impl.go index 4118957..30f80c5 100644 --- a/internal/accessor/log/impl.go +++ b/internal/accessor/log/impl.go @@ -11,7 +11,7 @@ type accessor struct { } type Log interface { - CreateLogAds(logsdomain.LogsSpec) error + CreateLog(logsdomain.LogsSpec) error GetAllLogAds(string) ([]adsdomain.Ads, error) } diff --git a/internal/accessor/news/get_all.go b/internal/accessor/news/get_all.go index d753e5f..adfa76e 100644 --- a/internal/accessor/news/get_all.go +++ b/internal/accessor/news/get_all.go @@ -7,7 +7,8 @@ func (a *accessor) GetAll(filter newsdomain.NewsFilter) ([]newsdomain.News, erro query := a.db. Preload("Tags"). Preload("Categories"). - Preload("Author") + Preload("Author"). + Joins("LEFT JOIN content_logs ON content_logs.content_id = news.id") if len(filter.Category) > 0 { query = query.Joins("JOIN news_categories nc ON nc.news_id = news.id"). @@ -19,6 +20,11 @@ func (a *accessor) GetAll(filter newsdomain.NewsFilter) ([]newsdomain.News, erro Where("nt.tag_id IN (?)", filter.Tags) } + query. + Select("news.*, COUNT(content_logs.content_id) as clicked"). + Group("news.id"). + Order("news.created_at DESC") + if err := query. Find(&news).Error; err != nil { return nil, err diff --git a/internal/api/http/news/get_by_slug.go b/internal/api/http/news/get_by_slug.go index 69a3d19..e81adab 100644 --- a/internal/api/http/news/get_by_slug.go +++ b/internal/api/http/news/get_by_slug.go @@ -1,9 +1,13 @@ package newshttp import ( + logsdomain "legalgo-BE-go/internal/domain/logs" + 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" + "strings" "github.com/go-chi/chi/v5" ) @@ -11,6 +15,7 @@ import ( func GetBySlug( router chi.Router, newsSvc newssvc.News, + logSvc logssvc.Log, ) { router.Get("/news/{slug}", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -29,6 +34,42 @@ func GetBySlug( return } + var specReq logsdomain.LogsSpec + + specReq.ContentID = news.ID + + userDetail, _ := utils.GetTokenDetail(r) + + if userDetail.ID != "" { + specReq.UserID = &userDetail.ID + } + + ip := r.RemoteAddr + + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + ip = strings.Split(forwarded, ",")[0] + } + + if ip != "" { + specReq.IP = &ip + } + + if userAgent := r.UserAgent(); 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) }) } diff --git a/internal/domain/logs/spec.go b/internal/domain/logs/spec.go index 8fefd44..eac3dfb 100644 --- a/internal/domain/logs/spec.go +++ b/internal/domain/logs/spec.go @@ -9,10 +9,11 @@ type LogsRequest struct { } type LogsSpec struct { - ContentID string `json:"content_id" validate:"required"` - IP *string `json:"ip"` - UserID *string `json:"user_id"` - UserAgent *string `json:"user_agent"` + ContentID string `json:"content_id" validate:"required"` + IP *string + UserID *string + UserAgent *string + Category string } type LogResponse struct { diff --git a/internal/domain/news/spec.go b/internal/domain/news/spec.go index 1eda171..e6435db 100644 --- a/internal/domain/news/spec.go +++ b/internal/domain/news/spec.go @@ -35,6 +35,7 @@ type News struct { LiveAt time.Time `json:"live_at"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` + Clicked int64 `json:"clicked"` Author Staff `json:"author"` } diff --git a/internal/services/logs/create_logs_ads.go b/internal/services/logs/create_logs_ads.go index 2e53f32..3bfe1f0 100644 --- a/internal/services/logs/create_logs_ads.go +++ b/internal/services/logs/create_logs_ads.go @@ -6,7 +6,8 @@ import ( ) func (i *impl) CreateLogAds(spec logsdomain.LogsSpec) error { - if err := i.logsRepo.CreateLogAds(spec); err != nil { + spec.Category = "ads" + if err := i.logsRepo.CreateLog(spec); err != nil { return fmt.Errorf("failed to create ads log: %v", err) } diff --git a/internal/services/logs/create_logs_news.go b/internal/services/logs/create_logs_news.go new file mode 100644 index 0000000..cafb9b2 --- /dev/null +++ b/internal/services/logs/create_logs_news.go @@ -0,0 +1,15 @@ +package logssvc + +import ( + "fmt" + logsdomain "legalgo-BE-go/internal/domain/logs" +) + +func (i *impl) CreateLogNews(spec logsdomain.LogsSpec) error { + spec.Category = "news" + if err := i.logsRepo.CreateLog(spec); err != nil { + return fmt.Errorf("failed to create news log: %v", err) + } + + return nil +} diff --git a/internal/services/logs/impl.go b/internal/services/logs/impl.go index 7e7a253..92d7c32 100644 --- a/internal/services/logs/impl.go +++ b/internal/services/logs/impl.go @@ -12,6 +12,7 @@ type impl struct { type Log interface { CreateLogAds(logsdomain.LogsSpec) error + CreateLogNews(logsdomain.LogsSpec) error GetAllLogAds(string) ([]adsdomain.Ads, error) }