Skip to content

Commit

Permalink
fix(major):refactoring/code splitting
Browse files Browse the repository at this point in the history
  • Loading branch information
LinceMathew committed Feb 24, 2024
1 parent b92410d commit 10b6ad4
Show file tree
Hide file tree
Showing 13 changed files with 1,103 additions and 1,050 deletions.
2 changes: 1 addition & 1 deletion another.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import "fmt"

func another() {
fmt.Println("another")
}
}
139 changes: 139 additions & 0 deletions blogConfiguration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package main

func addBlogConfigurations(meta map[string]interface{}) map[string]interface{} {

if config == nil {
log.Fatal("Configuration is not initialized. Call loadGlobalConfig to initialize it.")
}

globalSidebarTOC := config.GetDefault("blog-configuration.SIDEBAR_TOC", "").(bool)
globalFeatured := config.GetDefault("blog-configuration.FEATURED", "").(bool)
globalStatus := config.GetDefault("blog-configuration.STATUS", "").(string)
if _, ok := meta["featured"]; !ok {
meta["featured"] = globalFeatured
}
if _, ok := meta["status"]; !ok {
meta["status"] = globalStatus
}
if meta["status"] == nil || meta["featured"] == nil {
log.Error("required featured and status")
}

defaultStyle := `pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.article-image {
max-width: 600px;
margin: 0 auto !important;
float: none !important;
}`

sidebarTocHead := `<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.css">
<style>
.gh-content {
position: relative;
}
.gh-toc > .toc-list {
position: relative;
}
.toc-list {
overflow: hidden;
list-style: none;
}
@media (min-width: 1300px) {
.gh-sidebar {
position: absolute;
top: 0;
bottom: 0;
margin-top: 4vmin;
margin-left: 20px;
grid-column: wide-end / main-end; /* Place the TOC to the right of the content */
width: inline-block;
white-space: nowrap;
}
.gh-toc-container {
position: sticky; /* On larger screens, TOC will stay in the same spot on the page */
top: 4vmin;
}
}
.gh-toc .is-active-link::before {
background-color: var(--ghost-accent-color); /* Defines TOC accent color based on Accent color set in Ghost Admin */
}
</style>`
sidebarTocFooter := `<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.min.js"></script>
<script>
const parent = document.querySelector(".gh-content.gh-canvas");
// Create the <aside> element
const asideElement = document.createElement("aside");
asideElement.setAttribute("class", "gh-sidebar");
//asideElement.style.zIndex = 0; // sent to back so it doesn't show on top of images
// Create the container div for title and TOC
const containerElement = document.createElement("div");
containerElement.setAttribute("class", "gh-toc-container");
// Create the title element
const titleElement = document.createElement("div");
titleElement.textContent = "Table of Contents";
titleElement.style.fontWeight = "bold";
containerElement.appendChild(titleElement);
// Create the <div> element for TOC
const divElement = document.createElement("div");
divElement.setAttribute("class", "gh-toc");
containerElement.appendChild(divElement);
// Append the <div> element to the <aside> element
asideElement.appendChild(containerElement);
parent.insertBefore(asideElement, parent.firstChild);
tocbot.init({
// Where to render the table of contents.
tocSelector: '.gh-toc',
// Where to grab the headings to build the table of contents.
contentSelector: '.gh-content',
// Which headings to grab inside of the contentSelector element.
headingSelector: 'h1, h2, h3, h4',
// Ensure correct positioning
hasInnerContainers: true,
});
// Get the table of contents element
const toc = document.querySelector(".gh-toc");
const sidebar = document.querySelector(".gh-sidebar");
// Check the number of items in the table of contents
const tocItems = toc.querySelectorAll('li').length;
// Only show the table of contents if it has more than 5 items
if (tocItems > 2) {
sidebar.style.display = 'block';
} else {
sidebar.style.display = 'none';
}
</script>`

if existingHead, ok := meta["codeinjection_head"].(string); ok {
meta["codeinjection_head"] = existingHead + "<style>" + defaultStyle + "</style>"
} else {
meta["codeinjection_head"] = "<style> " + defaultStyle + "</style>"
}
blogMetaSidebarTOC := meta["sidebar_toc"]

if blogMetaSidebarTOC != nil {
globalSidebarTOC = blogMetaSidebarTOC.(bool)
}
if globalSidebarTOC {
if existingHead, ok := meta["codeinjection_head"].(string); ok {
meta["codeinjection_head"] = existingHead + sidebarTocHead
log.Debug("Done Sidebar TOC Code injection")
} else {
meta["codeinjection_head"] = sidebarTocHead
}
meta["codeinjection_foot"] = sidebarTocFooter
}

return meta
}
44 changes: 44 additions & 0 deletions featureImage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import "path/filepath"

func uploadFeatureImage(meta map[string]interface{}, token string, featureImage string) {
if featureImagePath, ok := meta["feature_image"].(string); ok {
hashValue, err := sha256Sum(featureImagePath)
if err != nil {
log.Error("Error calculating SHA-256 sum:", err)
return
}

fileExtension := filepath.Ext(featureImagePath)
imageName := hashValue + fileExtension
imageBackend := config.GetDefault("image-configuration.IMAGE_BACKEND", "").(string)

if imageBackend == "s3" {
log.Debug("Uploading feature image to AWS S3")
meta["feature_image"], err = uploadToS3(featureImagePath, imageName)
if err != nil {
log.Error("Error uploading file to S3:", err)
} else {
log.Info("Images uploading to S3")
}
} else {
log.Debug("Uploading feature image to Ghost Database")
var featureImgList []string
if featureImage != "" {
featureImgList = []string{featureImage}
} else {
featureImgList = []string{}
}
meta["feature_image"], err = uploadToGhost(token, featureImagePath, imageName, featureImgList)
if err != nil {
log.Error("Error uploading feature image to Ghost:", err)
}

}

log.Info("Uploaded feature image")
} else {
log.Info("Feature image not provided")
}
}
207 changes: 207 additions & 0 deletions ghost.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package main

import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"

"github.com/golang-jwt/jwt"
)

type Post struct {
ID string `json:"id"`
UpdatedAt string `json:"updated_at"`
Mobiledoc string `json:"mobiledoc"`
FeatureImage string `json:"feature_image"`
}

type ResponseData struct {
Posts []Post `json:"posts"`
}

var postsApiBase string

func getJWToken() (string, error) {

ghostAdminKey := config.GetDefault("ghost-configuration.ADMIN_API_KEY", "").(string)
ghostVersion := config.GetDefault("ghost-configuration.GHOST_VERSION", "").(string)

parts := strings.Split(ghostAdminKey, ":")
if len(parts) != 2 {
return "", fmt.Errorf("invalid admin key format")
}
id, secret := parts[0], parts[1]

var audValue string
if ghostVersion == "v5" {
audValue = "/admin/"
} else {
audValue = "/" + ghostVersion + "/admin/"
}

iat := time.Now().Unix()
exp := iat + 5*60 // expires in 5 minutes

token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"iat": iat,
"exp": exp,
"aud": audValue,
})

token.Header["kid"] = id

secretBytes, err := hex.DecodeString(secret)
if err != nil {
return "", fmt.Errorf("failed to decode secret: %v", err)
}

signedToken, err := token.SignedString(secretBytes)
if err != nil {
return "", fmt.Errorf("failed to sign token: %v", err)
}

return signedToken, nil
}

func sha256Sum(filename string) (string, error) {
h := sha256.New()

file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()

if _, err := io.Copy(h, file); err != nil {
return "", err
}

hashInBytes := h.Sum(nil)
hash := hex.EncodeToString(hashInBytes)

return hash, nil
}

func getPostId(slug string, headers http.Header) (*Post, error) {
ghostVersion := config.GetDefault("ghost-configuration.GHOST_VERSION", "").(string)
ghostUrl := config.GetDefault("ghost-configuration.GHOST_URL", "").(string)

if ghostVersion == "v5" {
postsApiBase = ghostUrl + "/api/admin/posts/"
} else {
postsApiBase = ghostUrl + "/api/" + ghostVersion + "/admin/posts/"
}

client := &http.Client{}
req, err := http.NewRequest("GET", postsApiBase+"slug/"+slug+"/", nil)
if err != nil {
return nil, err
}
req.Header = headers

resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return nil, nil
}
return nil, fmt.Errorf("unable to communicate with the Ghost Admin API: %s", body)
}

var data ResponseData
err = json.Unmarshal(body, &data)
if err != nil {
return nil, err
}

if len(data.Posts) > 0 {
return &data.Posts[0], nil
}

return nil, errors.New("no posts found for the given slug")
}

func makeRequest(headers http.Header, body map[string]interface{}, pid string, updated_at string) {
var method, apiEndpoint string
ghostVersion := config.GetDefault("ghost-configuration.GHOST_VERSION", "").(string)
ghostUrl := config.GetDefault("ghost-configuration.GHOST_URL", "").(string)

if ghostVersion == "v5" {
postsApiBase = ghostUrl + "/api/admin/posts/"
} else {
postsApiBase = ghostUrl + "/api/" + ghostVersion + "/admin/posts/"
}
if pid == "" {
method = http.MethodPost
apiEndpoint = postsApiBase + "?source=html"
} else {
method = http.MethodPut
body["posts"].([]map[string]interface{})[0]["updated_at"] = updated_at
apiEndpoint = postsApiBase + pid + "?source=html"
}

client := &http.Client{}
bodyJson, err := json.Marshal(body)
if err != nil {
log.Error("Error marshaling body to JSON:", err)
return
}

req, err := http.NewRequest(method, apiEndpoint, bytes.NewBuffer(bodyJson))
if err != nil {
log.Error("Error creating request:", err)
return
}
req.Header = headers
req.Header.Set("Content-Type", "application/json")

resp, err := client.Do(req)
if err != nil {
log.Error("Error executing request:", err)
return
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
var errorMessage string
errorBytes, _ := io.ReadAll(resp.Body)
if err := json.Unmarshal(errorBytes, &errorMessage); err != nil {
errorMessage = string(errorBytes)
}
log.Error("Request failed with status: %s. Error message: %s\n", resp.Status, errorMessage)
return
}

// Unmarshal the response
var responseData map[string]interface{}
err = json.NewDecoder(resp.Body).Decode(&responseData)
if err != nil {
log.Error("Error unmarshaling response:", err)
return
}

// Log the result
if pid == "" {
log.Info("Created new post")
} else {
log.Info("Updated existing post based on slug")
}
fmt.Printf("Blog preview link: %s\n", responseData["posts"].([]interface{})[0].(map[string]interface{})["url"])
}
Loading

0 comments on commit 10b6ad4

Please sign in to comment.