Skip to content

Commit

Permalink
Merge branch 'release/v1.3.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
namnhce committed Jul 4, 2024
2 parents 0e3c569 + 7cc0298 commit 3d2a003
Show file tree
Hide file tree
Showing 20 changed files with 311 additions and 14 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ require (
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.1
github.com/thoas/go-funk v0.9.3
github.com/vartanbeno/go-reddit/v2 v2.0.1
golang.org/x/crypto v0.16.0
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
golang.org/x/oauth2 v0.10.0
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M=
github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -666,6 +667,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/vartanbeno/go-reddit/v2 v2.0.1 h1:P6ITpf5YHjdy7DHZIbUIDn/iNAoGcEoDQnMa+L4vutw=
github.com/vartanbeno/go-reddit/v2 v2.0.1/go.mod h1:758/S10hwZSLm43NPtwoNQdZFSg3sjB5745Mwjb0ANI=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
Expand Down
4 changes: 3 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ type DiscordWebhook struct {
type DiscordID struct {
DwarvesGuild string
EventsChannel string
GolangChannel string
}

type Invoice struct {
Expand Down Expand Up @@ -259,7 +260,8 @@ func Generate(v ENV) *Config {
},
SecretToken: v.GetString("DISCORD_SECRET_TOKEN"),
IDs: DiscordID{
DwarvesGuild: v.GetString("DISCORD_DWARVES_GUILD_ID"),
DwarvesGuild: v.GetString("DISCORD_DWARVES_GUILD_ID"),
GolangChannel: v.GetString("DISCORD_GOLANG_CHANNEL_ID"),
},
},
Basecamp: Basecamp{
Expand Down
3 changes: 3 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/dwarvesf/fortress-api/pkg/controller/icy"
"github.com/dwarvesf/fortress-api/pkg/controller/invoice"
"github.com/dwarvesf/fortress-api/pkg/controller/memologs"
"github.com/dwarvesf/fortress-api/pkg/controller/reddit"
"github.com/dwarvesf/fortress-api/pkg/logger"
"github.com/dwarvesf/fortress-api/pkg/service"
"github.com/dwarvesf/fortress-api/pkg/store"
Expand All @@ -31,6 +32,7 @@ type Controller struct {
Icy icy.IController
MemoLog memologs.IController
CommunityNft communitynft.IController
Reddit reddit.IController
}

func New(store *store.Store, repo store.DBRepo, service *service.Service, worker *worker.Worker, logger logger.Logger, cfg *config.Config) *Controller {
Expand All @@ -46,5 +48,6 @@ func New(store *store.Store, repo store.DBRepo, service *service.Service, worker
Icy: icy.New(service, logger, cfg),
MemoLog: memologs.New(store, repo, service, logger, cfg),
CommunityNft: communitynft.New(store, repo, service, logger, cfg),
Reddit: reddit.New(store, service, logger, cfg),
}
}
26 changes: 21 additions & 5 deletions pkg/controller/memologs/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"strings"
"time"

"gorm.io/gorm"

"github.com/dwarvesf/fortress-api/pkg/logger"
"github.com/dwarvesf/fortress-api/pkg/model"
"gorm.io/gorm"
"github.com/dwarvesf/fortress-api/pkg/store/memolog"
)

const (
Expand All @@ -22,12 +24,20 @@ func (c *controller) Sync() ([]model.MemoLog, error) {
"method": "Sync",
})

latestMemo, err := c.store.MemoLog.Latest(c.repo.DB())
last7days := time.Now().AddDate(0, 0, -7)
latestMemos, err := c.store.MemoLog.List(c.repo.DB(), memolog.ListFilter{
From: &last7days,
})
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
l.Errorf(err, "failed to get latest memo")
return nil, err
}

latestMemosMap := make(map[string]model.MemoLog)
for _, memo := range latestMemos {
latestMemosMap[memo.URL] = memo
}

resp, err := http.Get(dfMemoRssURL)
if err != nil {
l.Errorf(err, "failed to get rss feed from %s, status code: %d", dfMemoRssURL, resp.StatusCode)
Expand All @@ -41,7 +51,8 @@ func (c *controller) Sync() ([]model.MemoLog, error) {
currentElem := ""
item := Item{}
newMemos := make([]model.MemoLog, 0)
for latestMemo.Title != item.Title || item.Title == "" {
stop := false
for !stop {
token, err := decoder.Token()
if err != nil {
break
Expand All @@ -58,11 +69,16 @@ func (c *controller) Sync() ([]model.MemoLog, error) {
if se.Name.Local == "item" {
inItem = false

if latestMemo.Title == item.Title {
break
if _, ok := latestMemosMap[item.Link]; ok {
continue
}

pubDate, _ := time.Parse(time.RFC1123Z, item.PubDate)
if pubDate.Before(last7days) {
stop = true
break
}

authorUsernames := make([]string, 0)
for _, s := range strings.Split(strings.TrimSpace(item.Author), ",") {
if s != "" {
Expand Down
40 changes: 40 additions & 0 deletions pkg/controller/reddit/golang_news.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package reddit

import (
"context"
)

const (
// defaultGolangChannelID is the default Discord channel ID for Golang news.
defaultGolangChannelID = "1257546039997501613"
)

// SyncGolangNews fetches new Golang news from Reddit and sends it to Discord.
func (c *controller) SyncGolangNews(ctx context.Context) error {
logger := c.logger.Field("func", "GolangNews")

popular, emerging, err := c.service.Reddit.FetchGolangNews(ctx)
if err != nil {
logger.Error(err, "failed to fetch Golang news")
return err
}

if len(popular) == 0 && len(emerging) == 0 {
logger.Info("no new Golang news")
return nil
}

logger.Infof("new Golang news: %d popular, %d emerging", len(popular), len(emerging))

golangChannelID := c.config.Discord.IDs.GolangChannel
if golangChannelID == "" {
golangChannelID = defaultGolangChannelID
}

if err := c.service.Discord.SendGolangNewsMessage(golangChannelID, emerging, popular); err != nil {
logger.Error(err, "failed to send Golang news message to discord")
return err
}

return nil
}
8 changes: 8 additions & 0 deletions pkg/controller/reddit/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package reddit

import "context"

type IController interface {
// SyncGolangNews fetches new Golang news from Reddit and sends it to Discord.
SyncGolangNews(ctx context.Context) error
}
24 changes: 24 additions & 0 deletions pkg/controller/reddit/new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package reddit

import (
"github.com/dwarvesf/fortress-api/pkg/config"
"github.com/dwarvesf/fortress-api/pkg/logger"
"github.com/dwarvesf/fortress-api/pkg/service"
"github.com/dwarvesf/fortress-api/pkg/store"
)

type controller struct {
store *store.Store
service *service.Service
logger logger.Logger
config *config.Config
}

func New(store *store.Store, service *service.Service, logger logger.Logger, cfg *config.Config) IController {
return &controller{
store: store,
service: service,
logger: logger,
config: cfg,
}
}
10 changes: 10 additions & 0 deletions pkg/handler/discord/discord.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package discord

import (
"context"
"errors"
"fmt"
"math/rand"
Expand Down Expand Up @@ -639,3 +640,12 @@ func (h *handler) SetScheduledEventSpeakers(c *gin.Context) {

c.JSON(http.StatusOK, view.CreateResponse[any](view.ToDiscordEvent(*event), nil, nil, nil, ""))
}

// PostGolangNews fetches Golang news from social platform and post to golang channel
func (h *handler) PostGolangNews(c *gin.Context) {
if err := h.controller.Reddit.SyncGolangNews(context.Background()); err != nil {
c.JSON(http.StatusInternalServerError, view.CreateResponse[any](nil, nil, err, nil, ""))
}

c.JSON(http.StatusOK, view.CreateResponse[any](nil, nil, nil, nil, "ok"))
}
1 change: 1 addition & 0 deletions pkg/handler/discord/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ type IHandler interface {
CreateScheduledEvent(c *gin.Context)
ListScheduledEvent(c *gin.Context)
SetScheduledEventSpeakers(c *gin.Context)
PostGolangNews(c *gin.Context)
}
1 change: 1 addition & 0 deletions pkg/routes/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func loadV1Routes(r *gin.Engine, h *handler.Handler, repo store.DBRepo, s *store
cronjob.POST("/sync-conversion-rates", amw.WithAuth, pmw.WithPerm(model.PermissionCronjobExecute), h.ConversionRate.Sync)
cronjob.POST("/sync-memo", amw.WithAuth, pmw.WithPerm(model.PermissionCronjobExecute), h.Discord.SyncMemo)
cronjob.POST("/notify-weekly-memos", amw.WithAuth, pmw.WithPerm(model.PermissionCronjobExecute), h.Discord.NotifyWeeklyMemos)
cronjob.POST("/golang-news", amw.WithAuth, pmw.WithPerm(model.PermissionCronjobExecute), h.Discord.PostGolangNews)
}

/////////////////
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 @@ -687,6 +687,12 @@ func Test_loadV1Routes(t *testing.T) {
Handler: "github.com/dwarvesf/fortress-api/pkg/handler/discord.IHandler.NotifyWeeklyMemos-fm",
},
},
"/cronjobs/golang-news": {
"POST": {
Method: "POST",
Handler: "github.com/dwarvesf/fortress-api/pkg/handler/discord.IHandler.PostGolangNews-fm",
},
},
"/webhooks/n8n": {
"POST": {
Method: "POST",
Expand Down
66 changes: 65 additions & 1 deletion pkg/service/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/bwmarrin/discordgo"
"github.com/shopspring/decimal"
"github.com/vartanbeno/go-reddit/v2/reddit"

"github.com/dwarvesf/fortress-api/pkg/config"
"github.com/dwarvesf/fortress-api/pkg/model"
Expand All @@ -28,6 +29,7 @@ const (
memoCategoryFleeting = "00_fleeting"
memoCategoryLiterature = "01_literature"
memoCategoryOthers = "others"
discordEmbedMaxLen = 4096
)

type discordClient struct {
Expand Down Expand Up @@ -770,7 +772,7 @@ func (d *discordClient) SendWeeklyMemosMessage(guildID string, memos []model.Mem
authorField = "**@unknown-user**"
}

memolistString.WriteString(fmt.Sprintf("[[%v](%s)] %s - %v \n", idx+1, mem.URL, mem.Title, authorField))
memolistString.WriteString(fmt.Sprintf("[[%v](%s)] %s - %v\n", idx+1, mem.URL, mem.Title, authorField))
}

memolistString.WriteString("\n")
Expand Down Expand Up @@ -805,3 +807,65 @@ func (d *discordClient) GetChannelMessages(channelID string, limit int) ([]*disc
func (d *discordClient) GetEventByID(eventID string) (*discordgo.GuildScheduledEvent, error) {
return d.session.GuildScheduledEvent(d.cfg.Discord.IDs.DwarvesGuild, eventID, false)
}

// SendGolangNewsMessage sends golang news message to discord
func (d *discordClient) SendGolangNewsMessage(channelID string, emerging, popular []reddit.Post) error {
content := make([]string, 0)

title := "<:golang:811989243080474664> **Reddit Go BUZZ** <:golang:811989243080474664>"

if len(popular) > 0 {
content = append(content, "<:pepestonk:850050324135673937> **POPULAR**")
for i, post := range popular {
content = append(content, fmt.Sprintf("[[%v](%s)] %s - 💬 %v", i+1, "https://www.reddit.com"+post.Permalink, post.Title, post.NumberOfComments))
}
}

content = append(content, "[See more...](https://www.reddit.com/r/golang/rising/)")

// Separate popular and emerging
content = append(content, "")

if len(emerging) > 0 {
content = append(content, "<:aww:819507963236057099> **EMERGING**")
for i, post := range emerging {
content = append(content, fmt.Sprintf("[[%v](%s)] %s - %s", i+1, "https://www.reddit.com"+post.Permalink, post.Title, timeAgo(post.Created.Time)))
}
}

content = append(content, "[See more...](https://www.reddit.com/r/golang/new/)")

msg := &discordgo.MessageEmbed{
Title: title,
Description: strings.Join(content, "\n"),
}

_, err := d.SendEmbeddedMessageWithChannel(nil, msg, channelID)
if err != nil {
return err
}

return nil
}

// timeAgo converts a time to a string representation of how long ago it was.
func timeAgo(t time.Time) string {
now := time.Now()
duration := now.Sub(t)

if duration.Hours() >= 1 {
hours := int(duration.Hours())
return fmt.Sprintf("%d hour%s ago", hours, pluralize(hours))
} else {
minutes := int(duration.Minutes())
return fmt.Sprintf("%d minute%s ago", minutes, pluralize(minutes))
}
}

// Helper function to add 's' for pluralization.
func pluralize(count int) string {
if count != 1 {
return "s"
}
return ""
}
3 changes: 3 additions & 0 deletions pkg/service/discord/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package discord

import (
"github.com/bwmarrin/discordgo"
"github.com/vartanbeno/go-reddit/v2/reddit"

"github.com/dwarvesf/fortress-api/pkg/model"
"github.com/dwarvesf/fortress-api/pkg/view"
Expand Down Expand Up @@ -40,4 +41,6 @@ type IService interface {
SendMessage(discordMsg model.DiscordMessage, webhookUrl string) (*model.DiscordMessage, error)
SendEmbeddedMessageWithChannel(original *model.OriginalDiscordMessage, embed *discordgo.MessageEmbed, channelId string) (*discordgo.Message, error)
SendDiscordMessageWithChannel(ses *discordgo.Session, msg *discordgo.Message, channelId string) error
// SendGolangNewsMessage sends golang news message to discord
SendGolangNewsMessage(channelID string, emerging, popular []reddit.Post) error
}
Loading

0 comments on commit 3d2a003

Please sign in to comment.