Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add Tibia Forums Section details (v4/forum/section/{name}) #220

Open
wants to merge 2 commits into
base: feature-forum
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion src/TibiaDataUtils.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,19 @@ func TibiaDataDatetime(date string) string {
loc, _ := time.LoadLocation("Europe/Berlin")

// format used in datetime on html: Jan 02 2007, 19:20:30 CET
formatting := "Jan 02 2006, 15:04:05 MST"
var formatting string

// parsing and setting format of return
switch dateLength := len(date); {
case dateLength > 19:
// format used in datetime on html: Jan 02 2007, 19:20:30 CET
formatting = "Jan 02 2006, 15:04:05 MST"
case dateLength == 19:
// format used in datetime on html: 03.06.2023 01:19:00
formatting = "02.01.2006 15:04:05"
default:
log.Printf("Weird format detected: %s", date)
}

// parsing html in time with location set in loc
returnDate, err = time.ParseInLocation(formatting, date, loc)
Expand Down Expand Up @@ -329,3 +341,19 @@ func TibiaDataGetNewsType(data string) string {
return "unknown"
}
}

// TibiaDataForumNameValidator func - return valid forum string
func TibiaDataForumNameValidator(name string) string {
switch strings.ToLower(name) {
case "world boards", "world", "worldboards":
return "worldboards"
case "trade boards", "trade", "tradeboards":
return "tradeboards"
case "community boards", "community", "communityboards":
return "communityboards"
case "support boards", "support", "supportboards":
return "supportboards"
default:
return "worldboards"
}
}
26 changes: 26 additions & 0 deletions src/TibiaDataUtils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ func TestTibiaUTCDateFormat(t *testing.T) {
assert.Equal(t, "2021-12-24T09:52:16Z", TibiaDataDatetime("Dec 24 2021, 09:52:16 UTC"))
}

func TestTibiaForumDateFormat(t *testing.T) {
assert.Equal(t, "2023-06-20T13:55:36Z", TibiaDataDatetime("20.06.2023 15:55:36"))
}

func TestEnvFunctions(t *testing.T) {
assert := assert.New(t)

Expand Down Expand Up @@ -72,6 +76,28 @@ func TestTibiaDataGetNewsType(t *testing.T) {
assert.Equal("unknown", TibiaDataGetNewsType("TibiaData"))
}

func TestTibiaDataForumNameValidator(t *testing.T) {
assert := assert.New(t)

assert.Equal("worldboards", TibiaDataForumNameValidator("world boards"))
assert.Equal("worldboards", TibiaDataForumNameValidator("world"))
assert.Equal("worldboards", TibiaDataForumNameValidator("worldboards"))

assert.Equal("tradeboards", TibiaDataForumNameValidator("trade boards"))
assert.Equal("tradeboards", TibiaDataForumNameValidator("trade"))
assert.Equal("tradeboards", TibiaDataForumNameValidator("tradeboards"))

assert.Equal("communityboards", TibiaDataForumNameValidator("community boards"))
assert.Equal("communityboards", TibiaDataForumNameValidator("community"))
assert.Equal("communityboards", TibiaDataForumNameValidator("communityboards"))

assert.Equal("supportboards", TibiaDataForumNameValidator("support boards"))
assert.Equal("supportboards", TibiaDataForumNameValidator("support"))
assert.Equal("supportboards", TibiaDataForumNameValidator("supportboards"))

assert.Equal("worldboards", TibiaDataForumNameValidator("def"))
}

func TestHTMLLineBreakRemover(t *testing.T) {
const str = "a\nb\nc\nd\ne\nf\ng\nh\n"

Expand Down
116 changes: 116 additions & 0 deletions src/TibiaForumSection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package main

import (
"fmt"
"net/http"
"regexp"
"strings"

"github.com/PuerkitoBio/goquery"
)

type SectionBoardLastPost struct {
ID int `json:"id"`
PostedAt string `json:"posted_at"`
CharacterName string `json:"character_name"`
}

type SectionBoard struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Posts int `json:"posts"`
Threads int `json:"threads"`
LastPost SectionBoardLastPost `json:"last_post"`
}

type ForumSectionResponse struct {
Boards []SectionBoard `json:"boards"`
Information Information `json:"information"`
}

var (
boardInformationRegex = regexp.MustCompile(`.*boardid=(.*)">(.*)<\/a><br\/><font class="ff_info">(.*)<\/font><\/td><td class="TextRight">(.*)<\/td><td class="TextRight">(.*)<\/td><td><span class="LastPostInfo">`)
lastPostIdRegex = regexp.MustCompile(`.*postid=(.*)#post`)
lastPostPostedAtRegex = regexp.MustCompile(`.*height="9"\/><\/a>(.*)<\/span><span><font class="ff_info">`)
lastPostCharacterNameRegex = regexp.MustCompile(`.*subtopic=characters&amp;name=.*\">(.*)<\/a><\/span>`)
)

// TibiaForumSectionImpl func
func TibiaForumSectionImpl(BoxContentHTML string) (*ForumSectionResponse, error) {
// Loading HTML data into ReaderHTML for goquery with NewReader
ReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(BoxContentHTML))
if err != nil {
return nil, fmt.Errorf("[error] TibiaForumSectionImpl failed at goquery.NewDocumentFromReader, err: %s", err)
}

var (
BoardsData []SectionBoard
LastPostId int
LastPostPostedAt, LastPostCharacterName string

insideError error
)

// Running query over each div
ReaderHTML.Find(".TableContentContainer .TableContent tbody tr:not(.LabelH)").EachWithBreak(func(index int, s *goquery.Selection) bool {
// Storing HTML into CreatureDivHTML
BoardsDivHTML, err := s.Html()
if err != nil {
insideError = fmt.Errorf("[error] TibiaForumSectionImpl failed at BoardsDivHTML, err := s.Html(), err: %s", err)
return false
}

subma1 := boardInformationRegex.FindAllStringSubmatch(BoardsDivHTML, -1)
if len(subma1) == 0 {
return false
}

subma2 := lastPostIdRegex.FindAllStringSubmatch(BoardsDivHTML, -1)
if len(subma2) > 0 {
LastPostId = TibiaDataStringToInteger(subma2[0][1])
}

subma3 := lastPostPostedAtRegex.FindAllStringSubmatch(BoardsDivHTML, -1)
if len(subma3) > 0 {
LastPostPostedAt = TibiaDataDatetime(strings.Trim(TibiaDataSanitizeStrings(subma3[0][1]), " "))
}

subma4 := lastPostCharacterNameRegex.FindAllStringSubmatch(BoardsDivHTML, -1)
if len(subma4) > 0 {
LastPostCharacterName = TibiaDataSanitizeStrings(subma4[0][1])
}

BoardsData = append(BoardsData, SectionBoard{
ID: TibiaDataStringToInteger(subma1[0][1]),
Name: subma1[0][2],
Description: TibiaDataSanitizeEscapedString(subma1[0][3]),
Posts: TibiaDataStringToInteger(subma1[0][4]),
Threads: TibiaDataStringToInteger(subma1[0][5]),
LastPost: SectionBoardLastPost{
ID: LastPostId,
PostedAt: LastPostPostedAt,
CharacterName: LastPostCharacterName,
},
})

return true
})

if insideError != nil {
return nil, insideError
}

//
// Build the data-blob
return &ForumSectionResponse{
Boards: BoardsData,
Information: Information{
APIDetails: TibiaDataAPIDetails,
Timestamp: TibiaDataDatetime(""),
Status: Status{
HTTPCode: http.StatusOK,
},
},
}, nil
}
171 changes: 171 additions & 0 deletions src/TibiaForumSection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package main

import (
"github.com/TibiaData/tibiadata-api-go/src/static"
"github.com/stretchr/testify/assert"
"io"
"testing"
)

func TestForumsSectionWorldBoard(t *testing.T) {
file, err := static.TestFiles.Open("testdata/forums/section/worldboard.html")
if err != nil {
t.Fatalf("file opening error: %s", err)
}
defer file.Close()

data, err := io.ReadAll(file)
if err != nil {
t.Fatalf("File reading error: %s", err)
}

boardsJson, err := TibiaForumSectionImpl(string(data))
if err != nil {
t.Fatal(err)
}

assert := assert.New(t)

assert.Equal(90, len(boardsJson.Boards))

adra := boardsJson.Boards[0]
assert.Equal(146482, adra.ID)
assert.Equal("Adra", adra.Name)
assert.Equal("This board is for general discussions related to the game world Adra.", adra.Description)
assert.Equal(388, adra.Threads)
assert.Equal(1158, adra.Posts)
assert.Equal(39395612, adra.LastPost.ID)
assert.Equal("Rcdohl", adra.LastPost.CharacterName)
assert.Equal("2023-06-02T23:19:00Z", adra.LastPost.PostedAt)

alumbra := boardsJson.Boards[1]
assert.Equal(147016, alumbra.ID)
assert.Equal("Alumbra", alumbra.Name)
assert.Equal("This board is for general discussions related to the game world Alumbra.", alumbra.Description)
assert.Equal(563, alumbra.Threads)
assert.Equal(1011, alumbra.Posts)
assert.Equal(39395777, alumbra.LastPost.ID)
assert.Equal("Mad Mustazza", alumbra.LastPost.CharacterName)
assert.Equal("2023-06-04T15:51:13Z", alumbra.LastPost.PostedAt)
}

func TestForumsSectionSupportBoards(t *testing.T) {
file, err := static.TestFiles.Open("testdata/forums/section/supportboards.html")
if err != nil {
t.Fatalf("file opening error: %s", err)
}
defer file.Close()

data, err := io.ReadAll(file)
if err != nil {
t.Fatalf("File reading error: %s", err)
}

boardsJson, err := TibiaForumSectionImpl(string(data))
if err != nil {
t.Fatal(err)
}

assert := assert.New(t)

assert.Equal(3, len(boardsJson.Boards))

paymentSupport := boardsJson.Boards[0]
assert.Equal(20, paymentSupport.ID)
assert.Equal("Payment Support", paymentSupport.Name)
assert.Equal("Here you can ask questions on orders, payments and other payment issues.", paymentSupport.Description)
assert.Equal(14468, paymentSupport.Threads)
assert.Equal(56032, paymentSupport.Posts)
assert.Equal(39400410, paymentSupport.LastPost.ID)
assert.Equal("Dorieta", paymentSupport.LastPost.CharacterName)
assert.Equal("2023-06-29T11:24:33Z", paymentSupport.LastPost.PostedAt)

technicalSupport := boardsJson.Boards[1]
assert.Equal(13, technicalSupport.ID)
assert.Equal("Technical Support", technicalSupport.Name)
assert.Equal("Here you can ask for help if you have a technical problem that is related to Tibia.", technicalSupport.Description)
assert.Equal(64722, technicalSupport.Threads)
assert.Equal(301828, technicalSupport.Posts)
assert.Equal(39400354, technicalSupport.LastPost.ID)
assert.Equal("Dio Sorcer", technicalSupport.LastPost.CharacterName)
assert.Equal("2023-06-29T01:47:59Z", technicalSupport.LastPost.PostedAt)

help := boardsJson.Boards[2]
assert.Equal(113174, help.ID)
assert.Equal("Help", help.Name)
assert.Equal("Here you can ask other players all kind of questions about Tibia. Note that members of the CipSoft team will usually not reply here.", help.Description)
assert.Equal(22788, help.Threads)
assert.Equal(106713, help.Posts)
assert.Equal(39400248, help.LastPost.ID)
assert.Equal("Dekraken durinars", help.LastPost.CharacterName)
assert.Equal("2023-06-28T17:17:45Z", help.LastPost.PostedAt)
}

func TestForumsSectionCommunityBoards(t *testing.T) {
file, err := static.TestFiles.Open("testdata/forums/section/communityboards.html")
if err != nil {
t.Fatalf("file opening error: %s", err)
}
defer file.Close()

data, err := io.ReadAll(file)
if err != nil {
t.Fatalf("File reading error: %s", err)
}

boardsJson, err := TibiaForumSectionImpl(string(data))
if err != nil {
t.Fatal(err)
}

assert := assert.New(t)

assert.Equal(6, len(boardsJson.Boards))

gameplay := boardsJson.Boards[0]
assert.Equal(120835, gameplay.ID)
assert.Equal("Gameplay (English Only)", gameplay.Name)
assert.Equal("Here is the place to talk about quests, achievements and the general gameplay of Tibia.", gameplay.Description)
assert.Equal(35364, gameplay.Threads)
assert.Equal(335328, gameplay.Posts)
assert.Equal(39400492, gameplay.LastPost.ID)
assert.Equal("Dreamsphere", gameplay.LastPost.CharacterName)
assert.Equal("2023-06-29T19:59:41Z", gameplay.LastPost.PostedAt)

auditorium := boardsJson.Boards[5]
assert.Equal(89516, auditorium.ID)
assert.Equal("Auditorium (English Only)", auditorium.Name)
assert.Equal("Meet Tibia's community managers and give feedback on news articles and Tibia related topics. State your opinion and see what others think and have to say.", auditorium.Description)
}

func TestForumsSectionTradeBoards(t *testing.T) {
file, err := static.TestFiles.Open("testdata/forums/section/tradeboards.html")
if err != nil {
t.Fatalf("file opening error: %s", err)
}
defer file.Close()

data, err := io.ReadAll(file)
if err != nil {
t.Fatalf("File reading error: %s", err)
}

boardsJson, err := TibiaForumSectionImpl(string(data))
if err != nil {
t.Fatal(err)
}

assert := assert.New(t)

assert.Equal(90, len(boardsJson.Boards))

adra := boardsJson.Boards[0]
assert.Equal(146485, adra.ID)
assert.Equal("Adra - Trade", adra.Name)
assert.Equal("Use this board to make Tibia related trade offers on the game world Adra. Note that all trades must conform to the Tibia Rules.", adra.Description)
assert.Equal(540, adra.Threads)
assert.Equal(599, adra.Posts)
assert.Equal(39400121, adra.LastPost.ID)
assert.Equal("Arge Reotona", adra.LastPost.CharacterName)
assert.Equal("2023-06-28T09:15:31Z", adra.LastPost.PostedAt)
}
Loading