Compare commits

..

4 Commits

Author SHA1 Message Date
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
28 changed files with 319 additions and 20 deletions

View File

@ -6,6 +6,7 @@ import (
"legalgo-BE-go/config"
"legalgo-BE-go/database"
categorydomain "legalgo-BE-go/internal/domain/category"
subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan"
"github.com/google/uuid"
@ -36,9 +37,10 @@ func main() {
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")
db.Create(&subscribeplandomain.SubscribePlan{
ID: uuid.NewString(),
@ -50,5 +52,16 @@ func main() {
})
}
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,
})
}
log.Print("migrate success")
}

11
database/log_ads_model.go Normal file
View File

@ -0,0 +1,11 @@
package database
import "time"
type LogAds struct {
ID string `gorm:"primaryKey;not null" json:"id"`
AdsID string `gorm:"not null" json:"ads_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"`
}

View File

@ -0,0 +1,11 @@
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"`
}

View File

@ -55,5 +55,7 @@ func (db *DB) Migrate() error {
&Tag{},
&Category{},
&Ads{},
&LogAds{},
&LogNews{},
)
}

View File

@ -5,9 +5,14 @@ import (
adsdomain "legalgo-BE-go/internal/domain/ads"
)
func (a *accessor) GetAll() ([]adsdomain.Ads, error) {
var ads []adsdomain.Ads
if err := a.db.Find(&ads).Error; err != nil {
func (a *accessor) GetAll() ([]adsdomain.AdsResponse, error) {
var ads []adsdomain.AdsResponse
if err := a.db.Table("ads").
Select("ads.*, COUNT(log_ads.ads_id) as clicked").
Joins("LEFT JOIN log_ads ON log_ads.ads_id = ads.id").
Group("ads.id").
Scan(&ads).Error; err != nil {
return ads, fmt.Errorf("failed to get all ads: %v", err)
}

View File

@ -11,7 +11,7 @@ type accessor struct {
type Ads interface {
Create(adsdomain.Ads) error
GetAll() ([]adsdomain.Ads, error)
GetAll() ([]adsdomain.AdsResponse, error)
Update(adsdomain.Ads) error
Delete(string) error
}

View File

@ -0,0 +1,20 @@
package logrepository
import (
"legalgo-BE-go/database"
"github.com/google/uuid"
)
func (a *accessor) CreateLogAds(adsID, userID string) error {
spec := database.LogAds{
ID: uuid.NewString(),
AdsID: adsID,
UserID: userID,
}
if err := a.db.Create(&spec).Error; err != nil {
return err
}
return nil
}

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
}

View File

@ -0,0 +1,19 @@
package logrepository
import (
"legalgo-BE-go/database"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
type accessor struct {
db *database.DB
}
type Log interface {
CreateLogAds(adsID, userID string) error
GetAllLogAds(string) ([]adsdomain.Ads, error)
}
func New(db *database.DB) Log {
return &accessor{db}
}

View File

@ -3,6 +3,7 @@ package repository
import (
adsrepository "legalgo-BE-go/internal/accessor/ads"
categoryrepository "legalgo-BE-go/internal/accessor/category"
logrepository "legalgo-BE-go/internal/accessor/log"
newsrepository "legalgo-BE-go/internal/accessor/news"
"legalgo-BE-go/internal/accessor/oss"
redisaccessor "legalgo-BE-go/internal/accessor/redis"
@ -26,4 +27,5 @@ var Module = fx.Module("repository", fx.Provide(
newsrepository.New,
oss.New,
adsrepository.New,
logrepository.New,
))

View File

@ -20,6 +20,7 @@ func (a *accessor) GetUsers() ([]userdomain.UserProfile, error) {
Email: user.Email,
Phone: user.Phone,
Subscribe: user.Subscribe,
CreatedAt: user.CreatedAt,
})
}

View File

@ -25,6 +25,7 @@ func (ur *accessor) GetUserProfile(id string) (*userdomain.UserProfile, error) {
Email: user.Email,
Phone: user.Phone,
Subscribe: user.Subscribe,
CreatedAt: user.CreatedAt,
}
return userProfile, nil

View File

@ -0,0 +1,68 @@
package logshttp
import (
authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth"
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"
)
func CreateLogAds(
router chi.Router,
userSvc usersvc.User,
logsSvc logssvc.Log,
) {
router.With(authmiddleware.Authorize()).Post("/logs/ads", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
userDetail, err := utils.GetTokenDetail(r)
if err != nil {
response.RespondJsonErrorWithCode(
ctx,
w,
err,
response.ErrUnauthorized.Code,
response.ErrUnauthorized.HttpCode,
"unauthorized",
)
return
}
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 := logsSvc.CreateLogAds(spec.AdsID, userDetail.ID); 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",
})
})
}

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)
})
}

View File

@ -0,0 +1,8 @@
package logshttp
import "go.uber.org/fx"
var Module = fx.Module("logs-http", fx.Invoke(
CreateLogAds,
GetUserAds,
))

View File

@ -3,6 +3,7 @@ package internalhttp
import (
adshttp "legalgo-BE-go/internal/api/http/ads"
categoryhttp "legalgo-BE-go/internal/api/http/category"
logshttp "legalgo-BE-go/internal/api/http/logs"
newshttp "legalgo-BE-go/internal/api/http/news"
osshttp "legalgo-BE-go/internal/api/http/oss"
staffhttp "legalgo-BE-go/internal/api/http/staff"
@ -33,6 +34,7 @@ var Module = fx.Module("router",
userhttp.Module,
subscribehttp.Module,
adshttp.Module,
logshttp.Module,
)
func initRouter() chi.Router {

View File

@ -14,6 +14,11 @@ type Ads struct {
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"`

View File

@ -0,0 +1,14 @@
package logsdomain
import (
adsdomain "legalgo-BE-go/internal/domain/ads"
)
type LogsRequest struct {
AdsID string `json:"ads_id" validate:"required"`
}
type LogResponse struct {
ID string `json:"id"`
News []adsdomain.Ads `json:"news"`
}

View File

@ -6,11 +6,12 @@ import (
)
type User struct {
ID string `json:"id"`
SubscribeID string `json:"subscribe_id"`
Password string `json:"password"`
Email string `json:"email"`
Phone string `json:"phone"`
ID string `json:"id"`
SubscribeID string `json:"subscribe_id"`
Password string `json:"password"`
Email string `json:"email"`
Phone string `json:"phone"`
CreatedAt time.Time `json:"created_at"`
Subscribe subscribe.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"`
}
@ -23,9 +24,10 @@ type UserRegister struct {
}
type UserProfile struct {
ID string `json:"id"`
Email string `json:"email"`
Phone string `json:"phone"`
ID string `json:"id"`
Email string `json:"email"`
Phone string `json:"phone"`
CreatedAt time.Time `json:"created_at"`
Subscribe subscribe.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"`
}

View File

@ -2,6 +2,6 @@ package adssvc
import adsdomain "legalgo-BE-go/internal/domain/ads"
func (i *impl) GetAll() ([]adsdomain.Ads, error) {
func (i *impl) GetAll() ([]adsdomain.AdsResponse, error) {
return i.adsRepo.GetAll()
}

View File

@ -11,7 +11,7 @@ type impl struct {
type Ads interface {
Create(adsdomain.AdsReq) error
GetAll() ([]adsdomain.Ads, error)
GetAll() ([]adsdomain.AdsResponse, error)
Update(string, adsdomain.AdsReq) error
Delete(string) error
}

View File

@ -0,0 +1,11 @@
package logssvc
import "fmt"
func (i *impl) CreateLogAds(adsID, userID string) error {
if err := i.logsRepo.CreateLogAds(adsID, userID); err != nil {
return fmt.Errorf("failed to create ads log: %v", err)
}
return nil
}

View File

@ -0,0 +1,20 @@
package logssvc
import (
"fmt"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
func (i *impl) GetAllLogAds(userID string) ([]adsdomain.Ads, error) {
var (
logs []adsdomain.Ads
err error
)
logs, err = i.logsRepo.GetAllLogAds(userID)
if err != nil {
return logs, fmt.Errorf("failed to get user logs ads: %v", err)
}
return logs, nil
}

View File

@ -0,0 +1,23 @@
package logssvc
import (
logrepository "legalgo-BE-go/internal/accessor/log"
adsdomain "legalgo-BE-go/internal/domain/ads"
)
type impl struct {
logsRepo logrepository.Log
}
type Log interface {
CreateLogAds(adsID, userID string) error
GetAllLogAds(string) ([]adsdomain.Ads, error)
}
func New(
logsRepo logrepository.Log,
) Log {
return &impl{
logsRepo,
}
}

View File

@ -3,6 +3,7 @@ package services
import (
adssvc "legalgo-BE-go/internal/services/ads"
categorysvc "legalgo-BE-go/internal/services/category"
logssvc "legalgo-BE-go/internal/services/logs"
newssvc "legalgo-BE-go/internal/services/news"
"legalgo-BE-go/internal/services/oss"
staffsvc "legalgo-BE-go/internal/services/staffsvc"
@ -25,5 +26,6 @@ var Module = fx.Module("services",
oss.NewOSSService,
usersvc.New,
adssvc.New,
logssvc.New,
),
)

View File

@ -4,8 +4,8 @@ import (
userdomain "legalgo-BE-go/internal/domain/user"
)
func (i *impl) GetUserProfile(email string) (*userdomain.UserProfile, error) {
user, err := i.userRepo.GetUserProfile(email)
func (i *impl) GetUserProfile(id string) (*userdomain.UserProfile, error) {
user, err := i.userRepo.GetUserProfile(id)
if err != nil {
return nil, err
}

View File

@ -50,7 +50,7 @@ func (i *impl) RegisterUser(spec userdomain.UserRegister) (string, error) {
err = i.userRepo.CreateUser(user)
if err != nil {
return "", fmt.Errorf(err.Error())
return "", fmt.Errorf("create user failed: %v", err)
}
authToken := authdomain.AuthToken{
@ -62,7 +62,7 @@ func (i *impl) RegisterUser(spec userdomain.UserRegister) (string, error) {
token, err := utils.GenerateToken(authToken)
if err != nil {
return "", fmt.Errorf(err.Error())
return "", fmt.Errorf("generate token failed: %v", err)
}
return token, nil
}

View File

@ -18,6 +18,7 @@ var (
ErrUnauthorized = &ErrorCode{Code: "UNAUTHORIZED", Message: "UNAUTHORIZED", HttpCode: http.StatusUnauthorized}
ErrDBRequest = &ErrorCode{Code: "BAD_DB_REQUEST", Message: "DB_ERROR", HttpCode: http.StatusBadRequest}
ErrExpiryToken = &ErrorCode{Code: "EXPIRED_TOKEN", Message: "EXPIRED_TOKEN", HttpCode: http.StatusUnauthorized}
ErrNotFound = &ErrorCode{Code: "NOT_FOUND", Message: "NOT_FOUND", HttpCode: http.StatusNotFound}
// 5xx
ErrMarshal = &ErrorCode{Code: "FAILED_MARSHAL", Message: "FAILED_MARSHAL_BODY", HttpCode: http.StatusInternalServerError}