2023-05-24 22:51:37 +00:00
|
|
|
package aboutme
|
2023-03-15 12:32:41 +00:00
|
|
|
|
2023-03-17 01:16:51 +00:00
|
|
|
import (
|
2023-05-24 22:51:37 +00:00
|
|
|
"errors"
|
2023-06-07 00:42:50 +00:00
|
|
|
"html/template"
|
2023-05-03 21:50:08 +00:00
|
|
|
"net/http"
|
2023-05-24 22:51:37 +00:00
|
|
|
"path"
|
2023-05-17 22:45:39 +00:00
|
|
|
"personalwebsite/apps/appCtx"
|
2023-05-24 22:51:37 +00:00
|
|
|
"personalwebsite/errormessage"
|
2023-06-07 00:42:50 +00:00
|
|
|
"personalwebsite/libs"
|
2023-04-29 19:37:08 +00:00
|
|
|
"personalwebsite/webfilesystem"
|
2023-03-17 01:16:51 +00:00
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
2023-04-29 19:37:08 +00:00
|
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
2023-03-17 01:16:51 +00:00
|
|
|
)
|
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
type AboutMeApp struct {
|
2023-05-16 10:51:28 +00:00
|
|
|
fs *webfilesystem.WebFileSystem
|
|
|
|
appID string
|
2023-06-07 00:42:50 +00:00
|
|
|
mLib libs.MarkdownLib
|
2023-03-15 12:32:41 +00:00
|
|
|
}
|
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
func NewAboutMeApp(webFs *webfilesystem.WebFileSystem) *AboutMeApp {
|
|
|
|
newApp := AboutMeApp{
|
2023-05-16 10:51:28 +00:00
|
|
|
fs: webFs,
|
|
|
|
appID: "AboutMe",
|
2023-03-17 01:16:51 +00:00
|
|
|
}
|
2023-05-16 10:51:28 +00:00
|
|
|
return &newApp
|
2023-03-15 12:32:41 +00:00
|
|
|
}
|
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
func (p *AboutMeApp) PublicRoutes(route *gin.RouterGroup) {
|
2023-05-17 22:45:39 +00:00
|
|
|
route.POST("render", func(ctx *gin.Context) {
|
2023-05-07 01:00:22 +00:00
|
|
|
filePath := ctx.Query("path")
|
|
|
|
if filePath == "" {
|
|
|
|
ctx.Status(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2023-05-17 22:45:39 +00:00
|
|
|
appCtx := appCtx.AppContext{}
|
|
|
|
err := ctx.BindJSON(&appCtx)
|
|
|
|
if err != nil {
|
|
|
|
ctx.Status(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ginH, err := p.Render(appCtx, filePath)
|
2023-05-03 21:50:08 +00:00
|
|
|
if err != nil {
|
|
|
|
ctx.JSON(http.StatusInternalServerError, "TODO") //TODO
|
2023-05-05 22:50:57 +00:00
|
|
|
return
|
2023-05-03 21:50:08 +00:00
|
|
|
}
|
2023-05-17 22:45:39 +00:00
|
|
|
if appCtx.IsMobile {
|
2023-05-03 21:50:08 +00:00
|
|
|
ctx.HTML(http.StatusOK, "personal-properties/mobile-app.tmpl", ginH)
|
|
|
|
} else {
|
|
|
|
ctx.HTML(http.StatusOK, "personal-properties/app.tmpl", ginH)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
func (p *AboutMeApp) PrivateRoutes(router *gin.RouterGroup) {
|
2023-05-16 10:51:28 +00:00
|
|
|
p.PublicRoutes(router)
|
2023-06-07 00:42:50 +00:00
|
|
|
// router.GET("writeMock", func(ctx *gin.Context) {
|
|
|
|
// err := p.WriteMock()
|
|
|
|
// if err != nil {
|
|
|
|
// ctx.Status(http.StatusInternalServerError)
|
|
|
|
// }
|
|
|
|
// ctx.Status(http.StatusOK)
|
|
|
|
// })
|
|
|
|
|
|
|
|
router.GET("getMock", func(ctx *gin.Context) {
|
|
|
|
ctx.JSON(http.StatusOK, PropertiesFileData{
|
|
|
|
Header: HeaderIsland{},
|
|
|
|
Islands: []Island{
|
|
|
|
{
|
|
|
|
Header: "qq",
|
|
|
|
Properties: []IslandProperty{
|
|
|
|
{
|
|
|
|
Key: "22",
|
|
|
|
KeyComments: []string{
|
|
|
|
"45",
|
|
|
|
"12",
|
|
|
|
},
|
|
|
|
Values: []string{
|
|
|
|
"aaaa",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
2023-05-16 10:51:28 +00:00
|
|
|
})
|
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
router.GET("read", func(ctx *gin.Context) {
|
|
|
|
filePath := ctx.Query("path")
|
|
|
|
if filePath == "" {
|
|
|
|
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
|
|
|
|
Message: "File path is empty",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
propData, err := p.Read(filePath)
|
|
|
|
if err != nil {
|
|
|
|
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.JSON(http.StatusOK, propData)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.POST("edit", func(ctx *gin.Context) {
|
|
|
|
filePath := ctx.Query("path")
|
|
|
|
if filePath == "" {
|
|
|
|
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
|
|
|
|
Message: "File path is empty",
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
propsData := PropertiesFileData{}
|
|
|
|
err := ctx.BindJSON(&propsData)
|
|
|
|
if err != nil {
|
2023-06-07 00:42:50 +00:00
|
|
|
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2023-05-24 22:51:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.Edit(filePath, propsData)
|
|
|
|
if err != nil {
|
|
|
|
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx.Status(http.StatusOK)
|
|
|
|
})
|
|
|
|
|
2023-03-17 01:16:51 +00:00
|
|
|
}
|
2023-05-16 10:51:28 +00:00
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
func (p *AboutMeApp) GetAppID() string {
|
2023-05-16 10:51:28 +00:00
|
|
|
return p.appID
|
2023-03-17 01:16:51 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
// func (p *AboutMeApp) WriteMock() error {
|
|
|
|
// fileHeader := webfilesystem.FileHeader{
|
|
|
|
// MongoId: primitive.NewObjectID(),
|
|
|
|
// Name: "aboutme.props",
|
|
|
|
// Type: "personal-properties",
|
|
|
|
// Icon: "",
|
|
|
|
// }
|
|
|
|
// fileData := PropertiesFileData{
|
|
|
|
// Header: HeaderIsland{
|
|
|
|
// Name: "Test Name",
|
|
|
|
// IconPath: "test icon path",
|
|
|
|
// Info1: "Info1",
|
|
|
|
// Info2: "Info2",
|
|
|
|
// },
|
|
|
|
// Props: []PropIsland{
|
|
|
|
// {
|
|
|
|
// Header: "Test Prop Header",
|
|
|
|
// Props: []PropElement{
|
|
|
|
// {
|
|
|
|
// Key: "Test key",
|
|
|
|
// KeyComments: []string{"Test key comment 1", "Test key comment 1"},
|
|
|
|
// Values: []Value{
|
|
|
|
// {
|
|
|
|
// Blocks: []ValueBlock{
|
|
|
|
// {
|
|
|
|
// Type: "string",
|
|
|
|
// Data: []string{"aappo"},
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// Type: "link",
|
|
|
|
// Data: []string{"https://ya.ru", "Azazaza"},
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// Header: "Test Prop Header 2",
|
|
|
|
// Props: []PropElement{
|
|
|
|
// {
|
|
|
|
// Key: "Test key",
|
|
|
|
// KeyComments: []string{"Test key comment 1", "Test key comment 1"},
|
|
|
|
// Values: []Value{
|
|
|
|
// {
|
|
|
|
// Blocks: []ValueBlock{
|
|
|
|
// {
|
|
|
|
// Type: "string",
|
|
|
|
// Data: []string{"aappo"},
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// Type: "link",
|
|
|
|
// Data: []string{"https://ya.ru", "Azazaza"},
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// }
|
|
|
|
// _, _, err := p.fs.Write("/Applications/AboutMe.app/aboutme.props", &fileHeader, fileData)
|
|
|
|
// return err
|
|
|
|
// }
|
2023-05-05 22:50:57 +00:00
|
|
|
|
2023-05-24 22:51:37 +00:00
|
|
|
func (p *AboutMeApp) Read(filePath string) (*PropertiesFileData, error) {
|
|
|
|
propData := PropertiesFileData{}
|
|
|
|
fileHeader, err := p.fs.Read(path.Join(filePath, "aboutme.props"), &propData)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if fileHeader.Type != "personal-properties" {
|
|
|
|
return nil, errors.New("wrong file type")
|
|
|
|
}
|
|
|
|
return &propData, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *AboutMeApp) Edit(filePath string, blogData PropertiesFileData) error {
|
|
|
|
propsPath := path.Join(filePath, "aboutme.props")
|
|
|
|
fileHeader, err := p.fs.Read(propsPath, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if fileHeader.Type != "personal-properties" {
|
|
|
|
return errors.New("wrong file type")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.fs.Remove(propsPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fileHeader.MongoId = primitive.NewObjectID()
|
|
|
|
_, _, err = p.fs.Write(propsPath, fileHeader, blogData)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *AboutMeApp) Render(appCtx appCtx.AppContext, filePath string) (gin.H, error) {
|
2023-06-07 00:42:50 +00:00
|
|
|
//Read file from WebFS
|
|
|
|
propsData := &PropertiesFileData{}
|
2023-05-17 22:45:39 +00:00
|
|
|
filePath = p.fs.RelativeToAbsolute(appCtx, filePath)
|
2023-05-07 01:00:22 +00:00
|
|
|
_, err := p.fs.Read(filePath, &propsData)
|
2023-04-29 20:17:34 +00:00
|
|
|
if err != nil {
|
2023-05-05 22:50:57 +00:00
|
|
|
return nil, err
|
2023-04-29 20:17:34 +00:00
|
|
|
}
|
2023-06-07 00:42:50 +00:00
|
|
|
|
|
|
|
//Render Markdown strings
|
|
|
|
renderedIslands := []RenderedIsland{}
|
|
|
|
for _, island := range propsData.Islands {
|
|
|
|
newRenderedIsland := RenderedIsland{
|
|
|
|
Header: island.Header,
|
|
|
|
Properties: []RenderedIslandProperty{},
|
|
|
|
}
|
|
|
|
for _, property := range island.Properties {
|
|
|
|
newRenderedIslandProperty := RenderedIslandProperty{
|
|
|
|
Key: property.Key,
|
|
|
|
KeyComments: property.KeyComments,
|
|
|
|
Values: []template.HTML{},
|
|
|
|
}
|
|
|
|
for _, value := range property.Values {
|
|
|
|
renderedValue := p.mLib.Render([]byte(value), true)
|
|
|
|
newRenderedIslandProperty.Values = append(newRenderedIslandProperty.Values, renderedValue)
|
|
|
|
}
|
|
|
|
newRenderedIsland.Properties = append(newRenderedIsland.Properties, newRenderedIslandProperty)
|
|
|
|
}
|
|
|
|
renderedIslands = append(renderedIslands, newRenderedIsland)
|
|
|
|
}
|
|
|
|
|
|
|
|
//Make icon path absolute
|
2023-05-17 22:45:39 +00:00
|
|
|
propsData.Header.IconPath = p.fs.RelativeToAbsolute(appCtx, propsData.Header.IconPath)
|
2023-06-07 00:42:50 +00:00
|
|
|
|
2023-05-05 22:50:57 +00:00
|
|
|
return gin.H{
|
2023-06-07 00:42:50 +00:00
|
|
|
"HeaderProps": propsData.Header,
|
|
|
|
"Islands": renderedIslands,
|
2023-05-05 22:50:57 +00:00
|
|
|
}, nil
|
|
|
|
}
|
2023-04-29 20:17:34 +00:00
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
type PropertiesFileData struct {
|
2023-06-07 00:45:56 +00:00
|
|
|
Header HeaderIsland `bson:"header" json:"header"`
|
|
|
|
Islands []Island `bson:"islands" json:"islands"` //TODO rename
|
2023-06-07 00:42:50 +00:00
|
|
|
}
|
|
|
|
|
2023-04-29 20:17:34 +00:00
|
|
|
type HeaderIsland struct {
|
2023-06-07 00:45:56 +00:00
|
|
|
Name string `bson:"name" json:"name"`
|
|
|
|
IconPath string `bson:"iconpath" json:"iconpath"`
|
|
|
|
Value1 string `bson:"value1" json:"value1"` //TODO Rename to value
|
|
|
|
Value2 string `bson:"value2" json:"value2"`
|
2023-03-15 12:32:41 +00:00
|
|
|
}
|
2023-03-17 01:16:51 +00:00
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
type Island struct {
|
2023-06-07 00:45:56 +00:00
|
|
|
Header string `bson:"header" json:"header"`
|
|
|
|
Properties []IslandProperty `bson:"properties" json:"properties"`
|
2023-06-06 22:49:26 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
type IslandProperty struct {
|
2023-06-07 00:45:56 +00:00
|
|
|
Key string `bson:"key" json:"key"`
|
|
|
|
KeyComments []string `bson:"keycomment" json:"keycomment"`
|
|
|
|
Values []string `bson:"values" json:"values"`
|
2023-06-06 22:49:26 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
type RenderedIsland struct {
|
|
|
|
Header string
|
|
|
|
Properties []RenderedIslandProperty
|
2023-03-17 01:16:51 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
type RenderedIslandProperty struct {
|
|
|
|
Key string
|
|
|
|
KeyComments []string
|
|
|
|
Values []template.HTML
|
2023-03-18 00:34:56 +00:00
|
|
|
}
|
|
|
|
|
2023-06-07 00:42:50 +00:00
|
|
|
// type Value struct {
|
|
|
|
// Blocks []ValueBlock
|
|
|
|
// }
|
|
|
|
|
|
|
|
// type ValueBlock struct {
|
|
|
|
// Type string
|
|
|
|
// Data string
|
|
|
|
// }
|