Skip to content

Commit

Permalink
Merge branch 'release/v1.7.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
namnhce committed Aug 30, 2024
2 parents e2d682a + e44cf84 commit 62a89fe
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 8 deletions.
49 changes: 49 additions & 0 deletions pkg/controller/discord/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type IController interface {
Log(in model.LogDiscordInput) error
PublicAdvanceSalaryLog(in model.LogDiscordInput) error
ListDiscordResearchTopics(ctx context.Context, days, limit, offset int) ([]model.DiscordResearchTopic, int64, error)
UserOgifStats(ctx context.Context, discordID string, after time.Time) (OgifStats, error)
}

type controller struct {
Expand Down Expand Up @@ -272,3 +273,51 @@ func (c *controller) topicPopularity(topicID string, days int) (int64, []model.D

return totalMessages, result, lastActiveTime, nil
}

// OgifStats contains list of ogif and some stats
type OgifStats struct {
OgifList []model.EventSpeaker `json:"ogifList"`
UserAllTimeSpeaksCount int64 `json:"userAllTimeSpeaksCount"`
UserAllTimeRank int64 `json:"userAllTimeRank"`
UserCurrentSpeaksCount int64 `json:"userCurrentSpeaksCount"`
UserCurrentRank int64 `json:"userCurrentRank"`
TotalSpeakCount int64 `json:"totalSpeakCount"`
CurrentSpeakCount int64 `json:"currentSpeakCount"`
}

// UserOgifStats returns list ogif with some stats
func (c *controller) UserOgifStats(ctx context.Context, discordID string, after time.Time) (OgifStats, error) {
logger := c.logger.AddField("discordID", discordID).AddField("after", after)

ogftList, err := c.store.EventSpeaker.List(c.repo.DB(), discordID, &after, "ogif")
if err != nil {
logger.Error(err, "error when retrieving list event speaker")
return OgifStats{}, err
}

ogifStats, err := c.store.EventSpeaker.GetSpeakerStats(c.repo.DB(), discordID, &after, "ogif")
if err != nil {
logger.Error(err, "error when retrieving speaker stats")
}

allTimeOgifStats, err := c.store.EventSpeaker.GetSpeakerStats(c.repo.DB(), discordID, nil, "ogif")
if err != nil {
logger.Error(err, "error when retrieving all time speaker stats")
return OgifStats{}, err
}

allTimeTotalCount, err := c.store.EventSpeaker.Count(c.repo.DB(), "", nil, "ogif")
if err != nil {
logger.Error(err, "error when counting all time total speak")
}

return OgifStats{
OgifList: ogftList,
UserAllTimeSpeaksCount: allTimeOgifStats.TotalSpeakCount,
UserAllTimeRank: allTimeOgifStats.SpeakRank,
UserCurrentSpeaksCount: ogifStats.TotalSpeakCount,
UserCurrentRank: ogifStats.SpeakRank,
TotalSpeakCount: allTimeTotalCount,
CurrentSpeakCount: int64(len(ogftList)),
}, nil
}
27 changes: 27 additions & 0 deletions pkg/handler/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,3 +703,30 @@ func (h *handler) ListDiscordResearchTopics(c *gin.Context) {
Total: total,
}, nil, nil, ""))
}

func (h *handler) UserOgifStats(c *gin.Context) {
discordID := c.Query("discordID")
if discordID == "" {
c.JSON(http.StatusBadRequest, view.CreateResponse[any](nil, nil, errors.New("discord_id is required"), nil, ""))
return
}

var afterTime time.Time
after := c.Query("after")
if after != "" {
var err error
afterTime, err = time.Parse(time.RFC3339, after)
if err != nil {
c.JSON(http.StatusBadRequest, view.CreateResponse[any](nil, nil, errors.New("invalid after time format"), nil, ""))
return
}
}

stats, err := h.controller.Discord.UserOgifStats(c.Request.Context(), discordID, afterTime)
if err != nil {
c.JSON(http.StatusInternalServerError, view.CreateResponse[any](nil, nil, errors.New("discord_id is required"), nil, ""))
return
}

c.JSON(http.StatusOK, view.CreateResponse(stats, nil, nil, nil, ""))
}
1 change: 1 addition & 0 deletions pkg/handler/discord/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ type IHandler interface {
ListScheduledEvent(c *gin.Context)
SetScheduledEventSpeakers(c *gin.Context)
ListDiscordResearchTopics(c *gin.Context)
UserOgifStats(c *gin.Context)
}
18 changes: 10 additions & 8 deletions pkg/model/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ type Event struct {
Description string `json:"description"`
Date time.Time `json:"date"`
Image string `json:"image" gorm:"-"`
DiscordEventID string `json:"discord_event_id"`
DiscordChannelID string `json:"discord_channel_id"`
DiscordMessageID string `json:"discord_message_id"`
DiscordCreatorID string `json:"discord_creator_id"`
DiscordEventID string `json:"discordEventId"`
DiscordChannelID string `json:"discordChannelId"`
DiscordMessageID string `json:"discordMessageId"`
DiscordCreatorID string `json:"discordCreatorId"`
EventType DiscordScheduledEventType `json:"type"`
EventSpeakers []EventSpeaker `json:"event_speakers"`
IsOver bool `json:"is_over" gorm:"-"`
EventSpeakers []EventSpeaker `json:"eventSpeakers"`
IsOver bool `json:"isOver" gorm:"-"`
}

// EventSpeaker struct
type EventSpeaker struct {
EventID UUID `json:"event_id"`
DiscordAccountID UUID `json:"discord_account_id"`
EventID UUID `json:"eventId"`
DiscordAccountID UUID `json:"discordAccountId"`
Topic string `json:"topic,omitempty"`

Event *Event `json:"event"`
}

type DiscordScheduledEventType string
Expand Down
5 changes: 5 additions & 0 deletions pkg/routes/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,11 @@ func loadV1Routes(r *gin.Engine, h *handler.Handler, repo store.DBRepo, s *store
newsGroup.GET("", amw.WithAuth, h.News.Fetch)
}

ogifGroup := v1.Group("/ogif")
{
ogifGroup.GET("", amw.WithAuth, pmw.WithPerm(model.PermissionEmployeesDiscordRead), h.Discord.UserOgifStats)
}

/////////////////
// PUBLIC API GROUP
/////////////////
Expand Down
6 changes: 6 additions & 0 deletions pkg/routes/v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,12 @@ func Test_loadV1Routes(t *testing.T) {
Handler: "github.com/dwarvesf/fortress-api/pkg/handler/youtube.IHandler.LatestBroadcast-fm",
},
},
"/api/v1/ogif": {
"GET": {
Method: "GET",
Handler: "github.com/dwarvesf/fortress-api/pkg/handler/discord.IHandler.UserOgifStats-fm",
},
},
}

l := logger.NewLogrusLogger()
Expand Down
92 changes: 92 additions & 0 deletions pkg/store/eventspeaker/event_speaker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package eventspeaker

import (
"time"

"gorm.io/gorm"

"github.com/dwarvesf/fortress-api/pkg/model"
Expand All @@ -21,3 +23,93 @@ func (s *store) Create(db *gorm.DB, e *model.EventSpeaker) (*model.EventSpeaker,
func (s *store) DeleteAllByEventID(db *gorm.DB, eventID string) error {
return db.Table("event_speakers").Where("event_id = ?", eventID).Delete(&model.EventSpeaker{}).Error
}

// List returns a lit of event speaker with loaded event info
func (s *store) List(db *gorm.DB, discordID string, after *time.Time, topic string) ([]model.EventSpeaker, error) {
var eventSpeakers []model.EventSpeaker
query := db.Table("event_speakers").
Joins("JOIN discord_accounts ON event_speakers.discord_account_id = discord_accounts.id").
Joins("JOIN events ON events.id = event_speakers.event_id").
Order("events.date DESC")

if after != nil {
query = query.Where("events.date > ?", after)
}

if topic != "" {
query = query.Where("LOWER(event_speakers.topic) LIKE LOWER(?)", "%"+topic+"%")
}

if discordID != "" {
query = query.Where("discord_accounts.discord_id = ?", discordID)
}

err := query.Preload("Event").
Find(&eventSpeakers).Error
if err != nil {
return nil, err
}
return eventSpeakers, nil
}

// Count returns the total count of event speakers with the same filtering criteria as List
func (s *store) Count(db *gorm.DB, discordID string, after *time.Time, topic string) (int64, error) {
var count int64
query := db.Table("event_speakers").
Joins("JOIN discord_accounts ON event_speakers.discord_account_id = discord_accounts.id").
Joins("JOIN events ON events.id = event_speakers.event_id")

if after != nil {
query = query.Where("events.date > ?", after)
}

if topic != "" {
query = query.Where("LOWER(event_speakers.topic) LIKE LOWER(?)", "%"+topic+"%")
}

if discordID != "" {
query = query.Where("discord_accounts.discord_id = ?", discordID)
}

err := query.Count(&count).Error
if err != nil {
return 0, err
}
return count, nil
}

// SpeakerStats
type SpeakerStats struct {
TotalSpeakCount int64 `gorm:"column:total_speak_count"`
SpeakRank int64 `gorm:"column:speak_rank"`
}

// GetSpeakerStats returns the total speak count and rank for a given discord_id
func (s *store) GetSpeakerStats(db *gorm.DB, discordID string, after *time.Time, topic string) (SpeakerStats, error) {
var stats SpeakerStats

subQuery := db.Table("event_speakers").
Select("discord_accounts.discord_id, COUNT(event_speakers.topic) as total_speak_count").
Joins("JOIN discord_accounts ON event_speakers.discord_account_id = discord_accounts.id").
Joins("JOIN events ON events.id = event_speakers.event_id")

if after != nil {
subQuery = subQuery.Where("events.date > ?", after)
}
if topic != "" {
subQuery = subQuery.Where("LOWER(event_speakers.topic) LIKE LOWER(?)", "%"+topic+"%")
}

subQuery = subQuery.Group("discord_accounts.discord_id")

err := db.Table("(?) as subquery", subQuery).
Select("total_speak_count, RANK() OVER (ORDER BY total_speak_count DESC) as speak_rank").
Where("discord_id = ?", discordID).
Scan(&stats).Error

if err != nil {
return SpeakerStats{}, err
}

return stats, nil
}
5 changes: 5 additions & 0 deletions pkg/store/eventspeaker/interface.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package eventspeaker

import (
"time"

"gorm.io/gorm"

"github.com/dwarvesf/fortress-api/pkg/model"
Expand All @@ -9,4 +11,7 @@ import (
type IStore interface {
Create(db *gorm.DB, s *model.EventSpeaker) (ep *model.EventSpeaker, err error)
DeleteAllByEventID(db *gorm.DB, eventID string) error
List(db *gorm.DB, discordID string, after *time.Time, topic string) ([]model.EventSpeaker, error)
GetSpeakerStats(db *gorm.DB, discordID string, after *time.Time, topic string) (SpeakerStats, error)
Count(db *gorm.DB, discordID string, after *time.Time, topic string) (int64, error)
}
19 changes: 19 additions & 0 deletions pkg/view/event_speaker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package view

import "github.com/dwarvesf/fortress-api/pkg/model"

// OgifStats contains list of ogif and some stats
type OgifStats struct {
OgifList []model.EventSpeaker `json:"ogifList"`
UserAllTimeSpeaksCount int64 `json:"userAllTimeSpeaksCount"`
UserAllTimeRank int64 `json:"userAllTimeRank"`
UserCurrentSpeaksCount int64 `json:"userCurrentSpeaksCount"`
UserCurrentRank int64 `json:"userCurrentRank"`
TotalSpeakCount int64 `json:"totalSpeakCount"`
CurrentSpeakCount int64 `json:"currentSpeakCount"`
}

// OgifStatsResponse return ogif stats response
type OgifStatsResponse struct {
Data OgifStats `json:"data"`
} // @name OgifStatsResponse

0 comments on commit 62a89fe

Please sign in to comment.