DEV Community

Cover image for Attempting to Learn Go - Ghost to Hugo 4
Steve Layton
Steve Layton

Posted on • Originally published at shindakun.dev on

Attempting to Learn Go - Ghost to Hugo 4

Intro

Here we are once again! If you missed the last couple of posts I suggest reading them first to get a feeling for how our little prototype has evolved. This time around we’re going to be doing some refactoring to clean up a bit. The majority of what we’ll be doing is adding methods to our “database” struct.

The Method

What is a method? Well, you can think of it as a function that is attached to a struct. Or as A Tour of Go puts it

A method is a function with a special receiver argument.

In our code we have a struct GhostDatabase. We can add methods with the following signature where the receiver is our struct.

func (gd *GhostDatabase) getLength() int
Enter fullscreen mode Exit fullscreen mode

We could then call the method with the following

var db GhostDatabase

...load JSON code here...

length := db.getLength()
Enter fullscreen mode Exit fullscreen mode

OK so what’s our complete method look like? In the case of most of the methods we’ll be putting in place is pretty easy to reason about.

func (gd *GhostDatabase) getLength() int {
    return len(gd.Db[0].Data.Posts)
}
Enter fullscreen mode Exit fullscreen mode

Many Methods

Now lets quickly knock out some useful methods. For the most part they do what they say on the tin, so I won’t go into detail on each one.

func (gd *GhostDatabase) getMobiledoc(i int) string {
    return gd.Db[0].Data.Posts[i].Mobiledoc
}

func (gd *GhostDatabase) getPostId(i int) string {
    return gd.Db[0].Data.Posts[i].ID
}

func (gd *GhostDatabase) getPostTitle(i int) string {
    return gd.Db[0].Data.Posts[i].Title
}

func (gd *GhostDatabase) getPostSlug(i int) string {
    return gd.Db[0].Data.Posts[i].Slug
}

func (gd *GhostDatabase) getPostStatus(i int) string {
    return gd.Db[0].Data.Posts[i].Status
}

func (gd *GhostDatabase) getPostCreatedAt(i int) time.Time {
    return gd.Db[0].Data.Posts[i].CreatedAt
}

func (gd *GhostDatabase) getPostUpdatedAt(i int) time.Time {
    return gd.Db[0].Data.Posts[i].UpdatedAt
}

func (gd *GhostDatabase) getPostPublishedAt(i int) time.Time {
    return gd.Db[0].Data.Posts[i].PublishedAt
}

func (gd *GhostDatabase) getPostFeatureImage(i int) string {
    return gd.Db[0].Data.Posts[i].FeatureImage
}
Enter fullscreen mode Exit fullscreen mode

Tags

One thing that we haven’t looked into so far is retrieving the tags associated with a post. Since we’re working on adding methods now is a great time to work that out. Let’s talk through what we need to do.

First we need to loop through the “database” of post tags. From here we check to see if the PostID field matches with the post ID, pid, we pass into the function. We then assign the tag ID to a variable, tagId.

Next we’ll loop our way though the Tags “database” and check to see if the current tag id matches with tagId. If there is a match we append the tag name to a slice r. Once we’re done we return r.

Let’s see what that looks like in practice.

func (gd *GhostDatabase) getTags(pid string) []string {
    var r []string
    for i := 0; i < len(gd.Db[0].Data.PostsTags); i++ {
        if gd.Db[0].Data.PostsTags[i].PostID == pid {
            tagId := gd.Db[0].Data.PostsTags[i].TagID
            for j := 0; j < len(gd.Db[0].Data.Tags); j++ {
                if gd.Db[0].Data.Tags[j].ID == tagId {
                    r = append(r, gd.Db[0].Data.Tags[j].Name)
                }
            }
        }
    }
    return r
}
Enter fullscreen mode Exit fullscreen mode

Not to shabby.

Next Time

That’s all of our methods for now. With them out of the way I believe we have all the parts need to actually start writing our Markdown files!



Code Listing

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "os"
    "reflect"
    "strconv"
    "strings"
    "time"
)

type GhostDatabase struct {
    Db []struct {
        Meta struct {
            ExportedOn int64 `json:"exported_on"`
            Version string `json:"version"`
        } `json:"meta"`
        Data struct {
            Posts []struct {
                ID string `json:"id"`
                UUID string `json:"uuid"`
                Title string `json:"title"`
                Slug string `json:"slug"`
                Mobiledoc string `json:"mobiledoc"`
                HTML string `json:"html"`
                CommentID string `json:"comment_id"`
                Plaintext string `json:"plaintext"`
                FeatureImage string `json:"feature_image"`
                Featured int `json:"featured"`
                Type string `json:"type"`
                Status string `json:"status"`
                Locale interface{} `json:"locale"`
                Visibility string `json:"visibility"`
                EmailRecipientFilter string `json:"email_recipient_filter"`
                AuthorID string `json:"author_id"`
                CreatedAt time.Time `json:"created_at"`
                UpdatedAt time.Time `json:"updated_at"`
                PublishedAt time.Time `json:"published_at"`
                CustomExcerpt interface{} `json:"custom_excerpt"`
                CodeinjectionHead interface{} `json:"codeinjection_head"`
                CodeinjectionFoot interface{} `json:"codeinjection_foot"`
                CustomTemplate interface{} `json:"custom_template"`
                CanonicalURL interface{} `json:"canonical_url"`
            } `json:"posts"`
            PostsAuthors []struct {
                ID string `json:"id"`
                PostID string `json:"post_id"`
                AuthorID string `json:"author_id"`
                SortOrder int `json:"sort_order"`
            } `json:"posts_authors"`
            PostsMeta []interface{} `json:"posts_meta"`
            PostsTags []struct {
                ID string `json:"id"`
                PostID string `json:"post_id"`
                TagID string `json:"tag_id"`
                SortOrder int `json:"sort_order"`
            } `json:"posts_tags"`
            Roles []struct {
                ID string `json:"id"`
                Name string `json:"name"`
                Description string `json:"description"`
                CreatedAt time.Time `json:"created_at"`
                UpdatedAt time.Time `json:"updated_at"`
            } `json:"roles"`
            RolesUsers []struct {
                ID string `json:"id"`
                RoleID string `json:"role_id"`
                UserID string `json:"user_id"`
            } `json:"roles_users"`
            Settings []struct {
                ID string `json:"id"`
                Group string `json:"group"`
                Key string `json:"key"`
                Value string `json:"value"`
                Type string `json:"type"`
                Flags interface{} `json:"flags"`
                CreatedAt time.Time `json:"created_at"`
                UpdatedAt time.Time `json:"updated_at"`
            } `json:"settings"`
            Tags []struct {
                ID string `json:"id"`
                Name string `json:"name"`
                Slug string `json:"slug"`
                Description interface{} `json:"description"`
                FeatureImage interface{} `json:"feature_image"`
                ParentID interface{} `json:"parent_id"`
                Visibility string `json:"visibility"`
                OgImage interface{} `json:"og_image"`
                OgTitle interface{} `json:"og_title"`
                OgDescription interface{} `json:"og_description"`
                TwitterImage interface{} `json:"twitter_image"`
                TwitterTitle interface{} `json:"twitter_title"`
                TwitterDescription interface{} `json:"twitter_description"`
                MetaTitle interface{} `json:"meta_title"`
                MetaDescription interface{} `json:"meta_description"`
                CodeinjectionHead interface{} `json:"codeinjection_head"`
                CodeinjectionFoot interface{} `json:"codeinjection_foot"`
                CanonicalURL interface{} `json:"canonical_url"`
                AccentColor interface{} `json:"accent_color"`
                CreatedAt time.Time `json:"created_at"`
                UpdatedAt time.Time `json:"updated_at"`
            } `json:"tags"`
            Users []struct {
                ID string `json:"id"`
                Name string `json:"name"`
                Slug string `json:"slug"`
                Password string `json:"password"`
                Email string `json:"email"`
                ProfileImage string `json:"profile_image"`
                CoverImage interface{} `json:"cover_image"`
                Bio interface{} `json:"bio"`
                Website interface{} `json:"website"`
                Location interface{} `json:"location"`
                Facebook interface{} `json:"facebook"`
                Twitter interface{} `json:"twitter"`
                Accessibility string `json:"accessibility"`
                Status string `json:"status"`
                Locale interface{} `json:"locale"`
                Visibility string `json:"visibility"`
                MetaTitle interface{} `json:"meta_title"`
                MetaDescription interface{} `json:"meta_description"`
                Tour interface{} `json:"tour"`
                LastSeen time.Time `json:"last_seen"`
                CreatedAt time.Time `json:"created_at"`
                UpdatedAt time.Time `json:"updated_at"`
            } `json:"users"`
        } `json:"data"`
    } `json:"db"`
}

type Mobiledoc struct {
    Version string `json:"version"`
    Markups []interface{} `json:"markups"`
    Atoms []interface{} `json:"atoms"`
    Cards [][]interface{} `json:"cards"`
    Sections [][]interface{} `json:"sections"`
    GhostVersion string `json:"ghostVersion"`
}

func (gd *GhostDatabase) getLength() int {
    return len(gd.Db[0].Data.Posts)
}

func (gd *GhostDatabase) getMobiledoc(i int) string {
    return gd.Db[0].Data.Posts[i].Mobiledoc
}

func (gd *GhostDatabase) getPostId(i int) string {
    return gd.Db[0].Data.Posts[i].ID
}

func (gd *GhostDatabase) getPostTitle(i int) string {
    return gd.Db[0].Data.Posts[i].Title
}

func (gd *GhostDatabase) getPostSlug(i int) string {
    return gd.Db[0].Data.Posts[i].Slug
}

func (gd *GhostDatabase) getPostStatus(i int) string {
    return gd.Db[0].Data.Posts[i].Status
}

func (gd *GhostDatabase) getPostCreatedAt(i int) time.Time {
    return gd.Db[0].Data.Posts[i].CreatedAt
}

func (gd *GhostDatabase) getPostUpdatedAt(i int) time.Time {
    return gd.Db[0].Data.Posts[i].UpdatedAt
}

func (gd *GhostDatabase) getPostPublishedAt(i int) time.Time {
    return gd.Db[0].Data.Posts[i].PublishedAt
}

func (gd *GhostDatabase) getPostFeatureImage(i int) string {
    return gd.Db[0].Data.Posts[i].FeatureImage
}

func (gd *GhostDatabase) getTags(pid string) []string {
    var r []string
    for i := 0; i < len(gd.Db[0].Data.PostsTags); i++ {
        if gd.Db[0].Data.PostsTags[i].PostID == pid {
            tagId := gd.Db[0].Data.PostsTags[i].TagID
            for j := 0; j < len(gd.Db[0].Data.Tags); j++ {
                if gd.Db[0].Data.Tags[j].ID == tagId {
                    r = append(r, gd.Db[0].Data.Tags[j].Name)
                }
            }
        }
    }
    return r
}

func main() {
    fmt.Println("ghost2hugo")

    file, err := os.Open("shindakun-dot-net.ghost.2022-03-18-22-02-58.json")
    if err != nil {
        fmt.Println(err)
    }

    defer file.Close()

    b, err := io.ReadAll(file)
    if err != nil {
        fmt.Println(err)
    }

    var db GhostDatabase

    err = json.Unmarshal(b, &db)
    if err != nil {
        fmt.Println(err)
    }

    for i := 0; i < db.getLength(); i++ {
        fmt.Println(db.getPostTitle(i))
        fmt.Println(db.getPostSlug(i))
        fmt.Println(db.getPostStatus(i))
        fmt.Println(db.getPostCreatedAt(i))
        fmt.Println(db.getPostUpdatedAt(i))
        fmt.Println(db.getPostPublishedAt(i))
        fmt.Println(db.getPostFeatureImage(i))

        id := db.getPostId(i)
        tags := db.getTags(id)
        fmt.Println(tags)

        c := strings.ReplaceAll(db.getMobiledoc(i), "`", "%'")
        cc := "`" + c + "`"

        ucn, err := strconv.Unquote(cc)
        if err != nil {
            fmt.Println(err, ucn)
        }

        ucn = strings.ReplaceAll(ucn, "%'", "`")

        var md Mobiledoc

        err = json.Unmarshal([]byte(ucn), &md)
        if err != nil {
            fmt.Println(err)
        }

        if reflect.ValueOf(md.Cards).Len() > 0 {
            card := md.Cards[0][1]
            bbb := card.(map[string]interface{})

            fmt.Println(bbb["markdown"])
        }

        fmt.Println("---")
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
thatcomputerguy profile image
Griff Polk

Hello fellow gamedev mod :)