Compare commits

..

17 Commits

79 changed files with 2224 additions and 1088 deletions

View File

@ -10,7 +10,7 @@ FROM golang:1.18-alpine
WORKDIR /usr/app
COPY --from=build /usr/app/personalwebsite /usr/app/personalwebsite
COPY ./templates /usr/app/templates
COPY ./resources /usr/app/resources
COPY ./res /usr/app/res
EXPOSE 8080

View File

@ -0,0 +1,28 @@
package blogwriter
import (
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type BlogWriterApplication struct {
fs *webfilesystem.WebFileSystem
appID string
}
func NewBlogWriterApp(webfs *webfilesystem.WebFileSystem) *BlogWriterApplication {
return &BlogWriterApplication{
fs: webfs,
appID: "BlogWriter",
}
}
func (bw *BlogWriterApplication) GetAppID() string {
return bw.appID
}
func (bw *BlogWriterApplication) PublicRoutes(routes *gin.RouterGroup) {}
func (bw *BlogWriterApplication) PrivateRoutes(routes *gin.RouterGroup) {
}

View File

@ -0,0 +1,7 @@
package appCtx
type AppContext struct {
IsMobile bool `json:"isMobile"`
BundlePath string `json:"bundlePath"`
RunPath string `json:"runPath"`
}

View File

@ -1,6 +1,6 @@
package blogviewer
type BlogFileData struct {
Header string `bson:"header"`
Blocks []Block `bson:"blocks"`
Header string `bson:"header"`
Blocks []*Block `bson:"blocks"`
}

View File

@ -1,8 +1,11 @@
package blogviewer
import (
"errors"
"net/http"
"personalwebsite/apps"
"path"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
@ -10,28 +13,66 @@ import (
)
type BlogViewerApplication struct {
fs *webfilesystem.WebFileSystem
manifest apps.ApplicationManifest
fs *webfilesystem.WebFileSystem
appID string
}
func NewBlogViewerApp(webFs *webfilesystem.WebFileSystem) *BlogViewerApplication {
return &BlogViewerApplication{
fs: webFs,
manifest: apps.ApplicationManifest{
AppId: "blog-viewer",
},
fs: webFs,
appID: "BlogViewer",
}
}
func (b *BlogViewerApplication) GetManifest() apps.ApplicationManifest {
return b.manifest
func (b *BlogViewerApplication) GetAppID() string {
return b.appID
}
func (b *BlogViewerApplication) PrivateRoutes(route *gin.RouterGroup) {
b.PublicRoutes(route)
func (b *BlogViewerApplication) GetId() string {
return b.manifest.AppId
route.POST("edit", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "File path is empty",
})
}
blogData := BlogFileData{}
err := ctx.BindJSON(&blogData)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
err = b.Edit(filePath, blogData)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
ctx.Status(http.StatusOK)
})
route.GET("read", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "File path is empty",
})
}
blogData, err := b.Read(filePath)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
ctx.JSON(http.StatusOK, blogData)
})
}
func (b *BlogViewerApplication) Route(route *gin.RouterGroup) {
func (b *BlogViewerApplication) PublicRoutes(route *gin.RouterGroup) {
route.GET("writeMockBlog", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
@ -46,22 +87,27 @@ func (b *BlogViewerApplication) Route(route *gin.RouterGroup) {
ctx.JSON(http.StatusOK, "OK")
})
route.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
route.POST("render", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
isMobile := isMobileParam == "true"
ginH, err := b.Render(path, isMobile)
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
ginH, err := b.Render(path, appCtx)
if err != nil {
ctx.JSON(http.StatusInternalServerError, "TODO")
return
}
if isMobile {
if appCtx.IsMobile {
ctx.HTML(http.StatusOK, "blog-viewer/mobile-app.tmpl", ginH)
} else {
ctx.HTML(http.StatusOK, "blog-viewer/app.tmpl", ginH)
@ -71,25 +117,17 @@ func (b *BlogViewerApplication) Route(route *gin.RouterGroup) {
}
func (b *BlogViewerApplication) WriteMock(path string) error {
blogFileHeader := webfilesystem.FileHeader{
blogFileHeader := webfilesystem.FileHeader{ //TODO to fs.CreateDirectory()
MongoId: primitive.NewObjectID(),
Name: "blog1.blog",
Type: "",
Type: "directory",
Icon: "",
Data: [12]byte{},
}
blogFileData := BlogFileData{
Header: "OMG THIS IS BLOG",
Blocks: []Block{
{
Type: "plain-text",
Data: []string{
"Apoqiwepoqiwepo",
".,mas;dakls;d",
"q[poqwieqpipoi]",
},
},
},
blogFileData := webfilesystem.DirectoryData{
MongoId: primitive.NewObjectID(),
Parent: [12]byte{},
Children: []primitive.ObjectID{},
}
_, _, err := b.fs.Write("/home/user/blog1.blog", &blogFileHeader, blogFileData)
@ -97,16 +135,87 @@ func (b *BlogViewerApplication) WriteMock(path string) error {
println(err.Error())
return err
}
blogContentFileHeader := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(),
Name: ".content",
Type: "blog-content",
Icon: "",
Data: [12]byte{},
}
blogContentFileData := BlogFileData{
Header: "OMG THIS IS BLOG",
}
blogContentFileData.Blocks = append(blogContentFileData.Blocks, &Block{
Type: "plain-text",
Data: []string{
"Apoqiwepoqiwepo",
".,mas;dakls;d",
"q[poqwieqpipoi]",
},
})
_, _, err = b.fs.Write("/home/user/blog1.blog/.content", &blogContentFileHeader, blogContentFileData)
if err != nil {
println(err.Error())
return err
}
return nil
}
func (b *BlogViewerApplication) Render(filePath string, isMobile bool) (gin.H, error) {
data := BlogFileData{}
_, err := b.fs.Read(filePath, &data)
func (b *BlogViewerApplication) Read(filePath string) (*BlogFileData, error) {
fileData := BlogFileData{}
fileHeader, err := b.fs.Read(path.Join(filePath, ".content"), &fileData)
if err != nil {
return nil, err
}
if fileHeader.Type != "blog-content" {
return nil, errors.New("wrong file type")
}
return &fileData, nil
}
func (b *BlogViewerApplication) Edit(filePath string, blogData BlogFileData) error {
contentPath := path.Join(filePath, ".content")
fileHeader, err := b.fs.Read(contentPath, nil)
if err != nil {
return err
}
if fileHeader.Type != "blog-content" {
return errors.New("wrong file type")
}
err = b.fs.Remove(contentPath)
if err != nil {
return err
}
fileHeader.MongoId = primitive.NewObjectID()
_, _, err = b.fs.Write(contentPath, fileHeader, blogData)
if err != nil {
return err
}
return nil
}
func (b *BlogViewerApplication) Render(filePath string, appCtx appCtx.AppContext) (gin.H, error) {
data := &BlogFileData{}
_, err := b.fs.Read(path.Join(filePath, ".content"), &data)
if err != nil {
return nil, err
}
for _, block := range data.Blocks {
if block.Type == "image" {
newData := []string{}
for _, image := range block.Data {
newData = append(newData, b.fs.RelativeToAbsolute(appCtx, image))
}
block.Data = newData
}
}
return gin.H{
"header": data.Header,
"blocks": data.Blocks,

View File

@ -1,7 +1,7 @@
package finder
import (
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
@ -9,115 +9,56 @@ import (
)
type FinderApplication struct {
fs *webfilesystem.WebFileSystem
manifest apps.ApplicationManifest
fs *webfilesystem.WebFileSystem
appID string
// manifest apps.ApplicationManifest
}
func NewFinderApplication(webFs *webfilesystem.WebFileSystem) *FinderApplication {
return &FinderApplication{
fs: webFs,
manifest: apps.ApplicationManifest{
AppId: "finder",
},
fs: webFs,
appID: "Finder",
}
}
func (f *FinderApplication) GetManifest() apps.ApplicationManifest {
return f.manifest
}
func (f *FinderApplication) GetId() string {
return f.manifest.AppId
func (f *FinderApplication) GetAppID() string {
return f.appID
}
func (f *FinderApplication) Render(isMobile bool) gin.H {
func (f *FinderApplication) Render(appCtx appCtx.AppContext) gin.H {
return gin.H{}
}
func (f *FinderApplication) RenderContextMenu(context string, filePath string, data string) gin.H {
func (f *FinderApplication) RenderPublicContextMenu(context string, filePath string, data string) gin.H {
islands := [][]wde.ContexMenuRow{}
islands = append(islands, []wde.ContexMenuRow{})
//TODO: Links read as source files in props info
islands = append(islands, []wde.ContexMenuRow{
{Label: "Get Info", Action: "getInfo"},
})
if context == "FileTileView" {
islands = append(islands, []wde.ContexMenuRow{
{Label: "Get Info", Action: "getInfo"},
{Label: "New Directory", Action: "createDir"},
})
return gin.H{
"Islands": islands,
}
}
switch context {
case "directory":
if f.fs.GetExtension(filePath) == "app" {
islands = append(islands, []wde.ContexMenuRow{
{Label: "Open as Directory", Action: "openAsDir"},
})
}
default:
islands = append(islands, []wde.ContexMenuRow{
{Label: "temp Menu 1", Action: ""},
{Label: "temp Menu 2", Action: ""},
})
}
islands = append(islands, []wde.ContexMenuRow{
{Label: "Delete File", Action: "deleteFile"},
})
return gin.H{
"Islands": islands,
}
}
func (f *FinderApplication) RenderProps(filePath string) (gin.H, error) {
// file, err := f.fs.NewReadDeprecated(filePath)
// if err != nil {
// return nil
// }
fileHeader, err := f.fs.Read(filePath, nil)
if err != nil {
return nil, err
}
return gin.H{
// "fileId": fileHeader.MongoId,
// "fileDataId": fileHeader.Data,
"file": fileHeader,
}, nil
}
// func (f *FinderApplication) Routes(routes *gin.RouterGroup) {
// routes.GET("render", func(ctx *gin.Context) {
// isMobileParam := ctx.Query("isMobile")
// isMobile := isMobileParam == "true"
// admin := true
// if isMobile {
// ctx.HTML(http.StatusOK, "finder/mobile-app.tmpl", f.Render(isMobile))
// return
// }
// if admin {
// ctx.HTML(http.StatusOK, "finder/admin-app.tmpl", f.Render(isMobile))
// return
// }
// ctx.HTML(http.StatusOK, "finder/app.tmpl", f.Render(isMobile))
// })
// routes.GET("renderMobileDesktop", func(ctx *gin.Context) {
// ctx.HTML(http.StatusOK, "finder/mobile-desktop.tmpl", gin.H{})
// })
// routes.GET("renderDesktop", func(ctx *gin.Context) {
// path := ctx.Query("path")
// if path == "" {
// ctx.JSON(http.StatusBadRequest, "no path provided")
// return
// }
// ctx.HTML(http.StatusOK, "finder/desktop.tmpl", gin.H{})
// })
// routes.GET("contextMenu", func(ctx *gin.Context) {
// context := ctx.Query("context")
// data := ctx.Query("data")
// ginH := f.RenderContextMenu(context, data)
// ctx.HTML(http.StatusOK, "wde-widgets/context-menu.tmpl", ginH)
// })
// }

View File

@ -1,22 +1,61 @@
package finder
import (
"personalwebsite/apps"
"personalwebsite/webfilesystem"
"personalwebsite/apps/appCtx"
"personalwebsite/wde"
"github.com/gin-gonic/gin"
)
type FinderAdminApp struct {
fs *webfilesystem.WebFileSystem
manifest apps.ApplicationManifest
}
func (f *FinderApplication) RenderAdminWindow(appCtx appCtx.AppContext) gin.H {
func NewFinderAdminApp(webfs *webfilesystem.WebFileSystem) FinderAdminApp {
return FinderAdminApp{
fs: webfs,
manifest: apps.ApplicationManifest{},
return gin.H{}
}
func (f *FinderApplication) RenderPrivateContextMenu(context string, filePath string, data string) gin.H {
islands := [][]wde.ContexMenuRow{}
// islands = append(islands, []wde.ContexMenuRow{})
islands = append(islands, []wde.ContexMenuRow{
{Label: "Get Info", Action: "getInfo"},
})
if context == "FileTileView" {
islands = append(islands, []wde.ContexMenuRow{
{Label: "New Directory", Action: "createDir"},
})
return gin.H{
"Islands": islands,
}
}
islands = append(islands, []wde.ContexMenuRow{
{Label: "Create path link", Action: "createPathLink"},
})
switch context {
case "directory":
switch f.fs.GetExtension(filePath) {
case "app":
islands = append(islands, []wde.ContexMenuRow{
{Label: "Open as Directory", Action: "openAsDir"},
})
case "blog":
islands = append(islands, []wde.ContexMenuRow{
{Label: "Open as Directory", Action: "openAsDir"},
})
}
default:
islands = append(islands, []wde.ContexMenuRow{
{Label: "temp Menu 1", Action: ""},
{Label: "temp Menu 2", Action: ""},
})
}
islands = append(islands, []wde.ContexMenuRow{
{Label: "Delete File", Action: "deleteFile"},
})
return gin.H{
"Islands": islands,
}
}
func (f *FinderAdminApp) RenderWindow() {
}

View File

@ -2,24 +2,23 @@ package finder
import (
"net/http"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
"github.com/gin-gonic/gin"
)
func (f *FinderApplication) Routes(routes *gin.RouterGroup) {
routes.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
admin := true
if isMobile {
ctx.HTML(http.StatusOK, "finder/mobile-app.tmpl", f.Render(isMobile))
func (f *FinderApplication) PublicRoutes(routes *gin.RouterGroup) {
routes.POST("render", func(ctx *gin.Context) {
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "Error in decoding app bundle",
})
return
}
if admin {
ctx.HTML(http.StatusOK, "finder/admin-app.tmpl", f.Render(isMobile))
return
}
ctx.HTML(http.StatusOK, "finder/app.tmpl", f.Render(isMobile))
ctx.HTML(http.StatusOK, "finder/app.tmpl", f.Render(appCtx))
})
routes.GET("renderMobileDesktop", func(ctx *gin.Context) {
@ -36,17 +35,58 @@ func (f *FinderApplication) Routes(routes *gin.RouterGroup) {
routes.GET("contextMenu", func(ctx *gin.Context) {
context := ctx.Query("context")
// if context == "" {
// ctx.Status(http.StatusBadRequest)
// return
// }
filePath := ctx.Query("path")
if filePath == "" {
ctx.Status(http.StatusBadRequest)
return
}
data := ctx.Query("data")
ginH := f.RenderContextMenu(context, filePath, data)
ginH := f.RenderPublicContextMenu(context, filePath, data)
ctx.HTML(http.StatusOK, "wde-widgets/context-menu.tmpl", ginH)
})
routes.GET("renderProps", func(ctx *gin.Context) {
filePath := ctx.Query("path")
ginH, err := f.RenderProps(filePath)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.HTML(http.StatusOK, "finder/props.tmpl", ginH)
})
}
func (f *FinderApplication) PrivateRoutes(routes *gin.RouterGroup) {
routes.POST("render", func(ctx *gin.Context) {
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "Error in decoding app context",
})
return
}
ctx.HTML(http.StatusOK, "finder/admin-app.tmpl", f.Render(appCtx))
})
routes.GET("renderDesktop", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
ctx.HTML(http.StatusOK, "finder/desktop.tmpl", gin.H{})
})
routes.GET("contextMenu", func(ctx *gin.Context) {
context := ctx.Query("context")
filePath := ctx.Query("path")
if filePath == "" {
ctx.Status(http.StatusBadRequest)
return
}
data := ctx.Query("data")
ginH := f.RenderPrivateContextMenu(context, filePath, data)
ctx.HTML(http.StatusOK, "wde-widgets/context-menu.tmpl", ginH)
})

View File

@ -2,28 +2,27 @@ package imgviewer
import (
"net/http"
websiteapp "personalwebsite/apps"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type ImgViewerApp struct {
fs *webfilesystem.WebFileSystem
manifest websiteapp.ApplicationManifest
fs *webfilesystem.WebFileSystem
appID string
}
func NewImgViewerApp(webFs *webfilesystem.WebFileSystem) ImgViewerApp {
func NewImgViewerApp(webFs *webfilesystem.WebFileSystem) *ImgViewerApp {
newApp := ImgViewerApp{
fs: webFs,
manifest: websiteapp.ApplicationManifest{
AppId: "img-viewer",
},
fs: webFs,
appID: "ImgViewer",
}
return newApp
return &newApp
}
func (p *ImgViewerApp) Route(route *gin.RouterGroup) {
func (p *ImgViewerApp) PrivateRoutes(route *gin.RouterGroup) {
p.PublicRoutes(route)
}
func (p *ImgViewerApp) PublicRoutes(route *gin.RouterGroup) {
route.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
@ -45,11 +44,8 @@ func (p *ImgViewerApp) Route(route *gin.RouterGroup) {
})
}
func (p *ImgViewerApp) GetManifest() websiteapp.ApplicationManifest {
return p.manifest
}
func (p *ImgViewerApp) GetId() string {
return p.manifest.AppId
func (p *ImgViewerApp) GetAppID() string {
return p.appID
}
func (p *ImgViewerApp) Render(filePath string, isMobile bool) (gin.H, error) {

View File

@ -2,50 +2,47 @@ package personalprops
import (
"net/http"
websiteapp "personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)
//TODO Rename to AboutMe
type PersonalPropertiesApp struct {
fs *webfilesystem.WebFileSystem
manifest websiteapp.ApplicationManifest
fs *webfilesystem.WebFileSystem
appID string
}
func NewPersPropsApp(webFs *webfilesystem.WebFileSystem) PersonalPropertiesApp {
func NewPersPropsApp(webFs *webfilesystem.WebFileSystem) *PersonalPropertiesApp {
newApp := PersonalPropertiesApp{
fs: webFs,
manifest: websiteapp.ApplicationManifest{
AppId: "personal-properties",
},
fs: webFs,
appID: "AboutMe",
}
return newApp
return &newApp
}
func (p *PersonalPropertiesApp) Route(route *gin.RouterGroup) {
route.GET("writeMock", func(ctx *gin.Context) {
err := p.WriteMock()
if err != nil {
ctx.Status(http.StatusInternalServerError)
}
ctx.Status(http.StatusOK)
})
route.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
func (p *PersonalPropertiesApp) PublicRoutes(route *gin.RouterGroup) {
route.POST("render", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.Status(http.StatusBadRequest)
return
}
ginH, err := p.Render(filePath)
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
ginH, err := p.Render(appCtx, filePath)
if err != nil {
ctx.JSON(http.StatusInternalServerError, "TODO") //TODO
return
}
if isMobile {
if appCtx.IsMobile {
ctx.HTML(http.StatusOK, "personal-properties/mobile-app.tmpl", ginH)
} else {
ctx.HTML(http.StatusOK, "personal-properties/app.tmpl", ginH)
@ -53,11 +50,20 @@ func (p *PersonalPropertiesApp) Route(route *gin.RouterGroup) {
})
}
func (p *PersonalPropertiesApp) GetManifest() websiteapp.ApplicationManifest {
return p.manifest
func (p *PersonalPropertiesApp) PrivateRoutes(router *gin.RouterGroup) {
p.PublicRoutes(router)
router.GET("writeMock", func(ctx *gin.Context) {
err := p.WriteMock()
if err != nil {
ctx.Status(http.StatusInternalServerError)
}
ctx.Status(http.StatusOK)
})
}
func (p *PersonalPropertiesApp) GetId() string {
return p.manifest.AppId
func (p *PersonalPropertiesApp) GetAppID() string {
return p.appID
}
func (p *PersonalPropertiesApp) WriteMock() error {
@ -101,13 +107,14 @@ func (p *PersonalPropertiesApp) WriteMock() error {
return err
}
func (p *PersonalPropertiesApp) Render(filePath string) (gin.H, error) {
func (p *PersonalPropertiesApp) Render(appCtx appCtx.AppContext, filePath string) (gin.H, error) {
propsData := PropertiesFileData{}
filePath = p.fs.RelativeToAbsolute(appCtx, filePath)
_, err := p.fs.Read(filePath, &propsData)
if err != nil {
return nil, err
}
propsData.Header.IconPath = p.fs.RelativeToAbsolute(appCtx, propsData.Header.IconPath)
return gin.H{
"headerProps": propsData.Header,
"allprops": propsData.Props,

View File

@ -12,9 +12,12 @@ import (
//TODO to libs
type WebDEApplication interface {
// Render()
GetManifest() ApplicationManifest
GetAppID() string
PublicRoutes(*gin.RouterGroup)
PrivateRoutes(*gin.RouterGroup)
// GetManifest() ApplicationManifest //TODO: Delete
// GEtHtml()
GetId() string
// GetId() string
}
type ApplicationManifest struct {
@ -36,6 +39,25 @@ type ApplicationsStorage struct {
}
func (as *ApplicationsStorage) createApp(appName string, appId string, appPath string) error {
appBundleName := appName + ".app"
newAppBundleHeader := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(),
Name: appBundleName,
Type: "directory",
Icon: "",
Data: primitive.NewObjectID(),
}
newAppBundleData := webfilesystem.DirectoryData{
MongoId: primitive.NewObjectID(),
Parent: primitive.NewObjectID(),
Children: []primitive.ObjectID{},
}
_, _, err := as.fs.Write(appPath+"/"+appBundleName, &newAppBundleHeader, &newAppBundleData)
if err != nil {
return err
}
newAppData := ApplicationManifest{
AppId: appId,
Js: []string{},
@ -49,34 +71,27 @@ func (as *ApplicationsStorage) createApp(appName string, appId string, appPath s
Icon: "",
Data: primitive.NewObjectID(),
}
//TODO: Create folder for app, etc
_, _, err := as.fs.Write(appPath+"/"+newAppFile.Name, &newAppFile, newAppData)
_, _, err = as.fs.Write(appPath+"/"+appBundleName+"/"+newAppFile.Name, &newAppFile, newAppData)
if err != nil {
return err
}
return nil
}
// func NewApplicationsStorage() *ApplicationsStorage {
// newStorage := ApplicationsStorage{}
// return &newStorage
// }
func (aStorage *ApplicationsStorage) Route(route *gin.RouterGroup) {
func (aStorage *ApplicationsStorage) PrivateRoute(route *gin.RouterGroup) {
route.GET("/get", func(ctx *gin.Context) {
appId := ctx.Query("appid")
if appId == "" {
ctx.Status(http.StatusBadRequest)
return
}
app, isExist := aStorage.Apps[appId]
if !isExist {
ctx.Status(http.StatusNoContent)
return
}
ctx.JSON(http.StatusOK, app.GetManifest())
// app, isExist := aStorage.Apps[appId]
// if !isExist {
// ctx.Status(http.StatusNoContent)
// return
// }
// ctx.JSON(http.StatusOK, app.GetManifest())
ctx.String(http.StatusMovedPermanently, "Obsolete")
})
route.GET("/loadApp", func(ctx *gin.Context) {
@ -120,7 +135,7 @@ func (aStorage *ApplicationsStorage) Route(route *gin.RouterGroup) {
err := aStorage.createApp(appId, appName, appPath)
if err != nil {
ctx.Status(http.StatusInternalServerError)
ctx.String(http.StatusInternalServerError, err.Error())
return
}
ctx.Status(http.StatusOK)

View File

@ -0,0 +1,5 @@
package errormessage
type ErrorMessage struct {
Message string `json:"message"`
}

2
go.mod
View File

@ -21,6 +21,7 @@ require (
github.com/bytedance/sonic v1.8.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/disintegration/imaging v1.6.2
github.com/gin-contrib/cors v1.4.0
github.com/gin-contrib/location v0.0.2
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
@ -39,6 +40,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/thinkerou/favicon v0.2.0
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
go.mongodb.org/mongo-driver v1.11.4

30
go.sum
View File

@ -4,27 +4,35 @@ github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZX
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
@ -48,12 +56,16 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@ -67,11 +79,15 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6f
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -82,11 +98,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/thinkerou/favicon v0.2.0 h1:/qO//fFevzhx68pAAPjuiOwB2ykoKwLcZW9luMZ8PEU=
github.com/thinkerou/favicon v0.2.0/go.mod h1:PM31DMRkXDVi9/sGwb/a/evMB536N9VfVNC+Dtf4iDQ=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
@ -101,11 +121,13 @@ go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizX
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@ -115,12 +137,15 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
@ -128,13 +153,18 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -38,7 +38,7 @@ func (c *Cat) Get(filePath string) (string, error) {
return fileData.Data, nil
}
func (c *Cat) Route(route *gin.RouterGroup) {
func (c *Cat) PublicRoutes(route *gin.RouterGroup) {
route.GET("get", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
@ -52,7 +52,13 @@ func (c *Cat) Route(route *gin.RouterGroup) {
return
}
ctx.String(http.StatusOK, "plaintext", data)
})
mode := ctx.Query("mode")
switch mode {
case "json":
ctx.JSON(http.StatusOK, data)
default:
ctx.String(http.StatusOK, "plaintext", data)
}
})
}

View File

@ -17,7 +17,7 @@ func NewImgLib(webfs *webfilesystem.WebFileSystem) *ImagLib {
}
}
func (l *ImagLib) Route(route *gin.RouterGroup) {
func (l *ImagLib) PublicRoutes(route *gin.RouterGroup) {
route.GET("get", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
@ -31,10 +31,6 @@ func (l *ImagLib) Route(route *gin.RouterGroup) {
ctx.Status(http.StatusInternalServerError)
return
}
// _, err = l.fs.readFSDocs(fileId, &imgData)
// if err != nil {
// ctx.Status(http.StatusInternalServerError)
// }
ctx.Data(http.StatusOK, "image/jpeg", imgData.Bin)
})

205
main.go
View File

@ -4,21 +4,18 @@ import (
"context"
"errors"
"log"
"net/http"
"os"
"personalwebsite/apps"
blogwriter "personalwebsite/apps/BlogWriter"
"personalwebsite/apps/blogviewer"
"personalwebsite/apps/finder"
imgviewer "personalwebsite/apps/img-viewer"
"personalwebsite/apps/personalprops"
"personalwebsite/libs"
"personalwebsite/routewde"
"personalwebsite/routes"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
@ -54,110 +51,130 @@ func main() {
log.Fatal(err)
}
router := gin.New()
router.Use(location.Default())
router.LoadHTMLGlob("templates/**/*")
router.Static("/res", "resources")
// Set a lower memory limit for multipart forms (default is 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{})
})
webfs := webfilesystem.NewWebFileSystem(client, dBName, webFsCollection)
appsStorage := apps.NewApplicationsStorage(map[string]apps.WebDEApplication{}, webfs)
// router := gin.New()
// router.Use(location.Default())
// router.LoadHTMLGlob("templates/**/*")
// router.Static("/res", "resources")
// // Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
// router.GET("/", func(ctx *gin.Context) {
// ctx.HTML(http.StatusOK, "index.tmpl", gin.H{})
// })
webde := wde.NewWDE(webfs)
//TODO Split to different apps init for private and public?
persPropsApp := personalprops.NewPersPropsApp(webfs)
// finderApp := finder.FinderApplication{}
finderApp := finder.NewFinderApplication(webfs)
imgViewerApp := imgviewer.NewImgViewerApp(webfs)
blogViewerApp := blogviewer.NewBlogViewerApp(webfs)
appsStorage := apps.NewApplicationsStorage(map[string]apps.WebDEApplication{}, webfs)
appsStorage.Apps["personal-properties"] = &persPropsApp
blogWriterApp := blogwriter.NewBlogWriterApp(webfs)
appsStorage.Apps["personal-properties"] = persPropsApp
appsStorage.Apps["finder"] = finderApp
appsStorage.Apps["img-viewer"] = &imgViewerApp
appsStorage.Apps["blog-viewer"] = blogViewerApp
appsStorage.Apps["img-viewer"] = imgViewerApp
appsStorage.Apps[blogViewerApp.GetAppID()] = blogViewerApp
appsStorage.Apps["BlogWriter"] = blogWriterApp
system := router.Group("system")
{
libsGroup := system.Group("libs")
{
imgLibGroup := libsGroup.Group("img")
{
imgLib := libs.NewImgLib(webfs)
imgLib.Route(imgLibGroup)
}
go routes.PublicRoutes(webfs, webde, appsStorage)
routes.PrivateRoutes(webfs, webde, appsStorage)
catLibGroup := libsGroup.Group("cat")
{
catLib := libs.NewCatLib(webfs)
catLib.Route(catLibGroup)
}
// system := router.Group("system")
// {
// libsGroup := system.Group("libs")
// {
// imgLibGroup := libsGroup.Group("img")
// {
// imgLib := libs.NewImgLib(webfs)
// imgLib.PublicRoutes(imgLibGroup)
// }
appsStorageGroup := libsGroup.Group("apps")
{
appsStorage.Route(appsStorageGroup)
}
}
// catLibGroup := libsGroup.Group("cat")
// {
// catLib := libs.NewCatLib(webfs)
// catLib.PublicRoutes(catLibGroup)
// }
wdeGroup := system.Group("wde")
{
routewde.Route(wdeGroup, webde)
}
apps := system.Group("applications") //TODO to libs
{
apps.GET("/:appid/:method", func(ctx *gin.Context) {
appId := ctx.Param("appid")
method := ctx.Param("method")
// appsStorageGroup := libsGroup.Group("apps")
// {
// appsStorage.Route(appsStorageGroup)
// }
// }
app, isExist := appsStorage.Apps[appId]
if !isExist {
ctx.Status(http.StatusNoContent)
return
}
switch method {
case "getmanifest":
ctx.JSON(http.StatusOK, app.GetManifest())
case "app.js":
ctx.File("resources/sys/" + appId + "/" + appId + ".js")
case "app.css":
ctx.File("resources/sys/" + appId + "/" + appId + ".css")
default:
ctx.Status(http.StatusBadRequest)
}
})
}
}
// wdeGroup := system.Group("wde")
// {
// routewde.PublicRoutes(wdeGroup, webde)
// }
// apps := system.Group("applications") //TODO to libs
// {
// apps.GET("/:appid/:method", func(ctx *gin.Context) {
// appId := ctx.Param("appid")
// method := ctx.Param("method")
fs := router.Group("fs")
{
webfs.Route(fs)
}
app := router.Group("app")
{
persPropApp := app.Group("AboutMe")
{
persPropsApp.Route(persPropApp)
}
finderAppRoute := app.Group("Finder")
{
finderApp.Routes(finderAppRoute)
}
imgViewerRoute := app.Group("img-viewer")
{
imgViewerApp.Route(imgViewerRoute)
}
blogViewerRoute := app.Group("blog-viewer")
{
blogViewerApp.Route(blogViewerRoute)
}
// app, isExist := appsStorage.Apps[appId]
// if !isExist {
// ctx.Status(http.StatusNoContent)
// return
// }
// switch method {
// case "getmanifest":
// ctx.JSON(http.StatusOK, app.GetManifest())
// case "app.js":
// ctx.File("resources/sys/" + appId + "/" + appId + ".js")
// case "app.css":
// ctx.File("resources/sys/" + appId + "/" + appId + ".css")
// default:
// ctx.Status(http.StatusBadRequest)
// }
// })
// }
// }
err = router.Run(":8080")
if err != nil {
log.Panicf("error: %s", err)
}
}
// fs := router.Group("fs")
// {
// fsGroup := systemGroup.Group("fs")
// {
// webfs.PublicRoutes(fsGroup)
// }
// }
// app := router.Group("app")
// {
// persPropApp := app.Group("AboutMe")
// {
// persPropsApp.Route(persPropApp)
// }
// finderAppRoute := app.Group("Finder")
// {
// finderApp.Routes(finderAppRoute)
// }
// imgViewerRoute := app.Group("img-viewer")
// {
// imgViewerApp.Route(imgViewerRoute)
// }
// blogViewerRoute := app.Group("blog-viewer")
// {
// blogViewerApp.Route(blogViewerRoute)
// }
// router.Use(cors.New(cors.Config{
// AllowAllOrigins: true,
// // AllowOrigins: []string{"http://localhost:8080", "http://localhost:9090"},
// // AllowMethods: []string{"PUT", "PATCH"},
// // AllowHeaders: []string{"Origin"},
// ExposeHeaders: []string{"Content-Length"},
// AllowCredentials: true,
// // AllowOriginFunc: func(origin string) bool {
// // return origin == "https://github.com"
// // },
// MaxAge: 12 * time.Hour,
// }))
// err = router.Run(":8080")
// if err != nil {
// log.Panicf("error: %s", err)
// }
// }
}
// func index(c *gin.Context) {

View File

@ -0,0 +1,11 @@
{
"folders": [
{
"path": "."
},
{
"path": "../personal-website-frontend"
}
],
"settings": {}
}

View File

@ -1,5 +1,5 @@
class AboutMe{
appId = "AboutMe"
static appID = "AboutMe"
/**
* @param {HTMLElement} appElem
*/
@ -8,18 +8,17 @@ class AboutMe{
}
/**
* @param {string} chroot
* @param {[]string} args
* @param {[]string} args
* @param {Object} runContext
*/
async NewWindow(chroot, args){
console.log(chroot)
if (chroot == ""){
chroot = "/home/user" //FIXME
}
console.log(`${chroot}/AboutMe.app/aboutme.props`)
const params = new URLSearchParams({isMobile: WebDesktopEnvironment.isMobile, path: `${chroot}/AboutMe.app/aboutme.props`})
const response = await fetch(`/app/${this.appId}/render?`+ params)
console.log(response)
async NewWindow(args, runContext){
const params = new URLSearchParams({
path: `:/aboutme.props`,
})
const response = await fetch(`/app/${AboutMe.appID}/render?`+ params,{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
WebDesktopEnvironment.Alert("Error TODO") //TODO
return

View File

@ -1,26 +1,28 @@
class BlogViewer{
appId = "blog-viewer"
constructor(){
}
static appID = "BlogViewer"
/**
* @param {string[]} chroot //TODO
* @param {string[]} args
* @param {string[]} args
* @param {Object} runContext
*/
async NewWindow(args){
const response = await fetch(`app/${this.appId}/render?` + new URLSearchParams({
isMobile: WebDesktopEnvironment.isMobile,
async NewWindow(args, runContext){
const params = new URLSearchParams({
path: args[0],
}))
})
runContext.runPath = args[0]
const response = await fetch(`app/${BlogViewer.appID}/render?` + params, {
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
WebDesktopEnvironment.Alert("Error render TODO") //TODO
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 500, 350 )
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 500, 350 )
newWindow.innerHTML = html
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".ScrollContent"))
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)

View File

@ -25,7 +25,25 @@
/* gap: 50px; */
/* row-gap: 20px; */
/* padding: 0px 20px 0px 20px; */
margin: 0px 20px 0px 20px;
/* margin: 0px 20px 0px 20px; */
}
.BlogView .ScrollContent {
position: relative;
width: 92%;
left: 4%;
right: 4%;
height: auto;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px;
/* row-gap: 20px; */
/* padding: 0px 20px 0px 20px; */
/* margin: 0px 20px 0px 20px; */
/* padding-left: 20px; */
}
.BlogView .header-h1{
@ -43,6 +61,19 @@
padding-bottom: 2px;
}
.BlogView .image{
width: 100%;
}
.image .ImageProp{
position: relative;
width: 100%;
height: auto;
/* left: 50%;
margin-left: -50%; */
}
.BlogView .plain-text{
/* Auto layout */
display: flex;

View File

@ -0,0 +1,10 @@
class BlogWriter{
static AppId = "BlogWriter"
/**
* @param {string[]} args
*/
async NewWindow(args){
console.log("kek")
}
}

View File

@ -0,0 +1,311 @@
class Finder{
static AppId = "Finder"
/**
* @param {string[]} args
*/
async NewWindow(args, runContext){
let newFinder = new FinderWindow()
await newFinder.Init(args, runContext)
}
/**
* @param {string} path
* @returns {boolean}
*/
static async RenderProperites(path){
if (path == null || path ==""){
return
}
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/app/${Finder.AppId}/renderProps?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("Error in properties render") //TODO
return false
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(Finder.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
}
}
class FinderWindow{
curPath = ""
fileView = undefined
windowElem = undefined
async Init(args, runContext){
if (args[1] === "-desktop"){
//todo pass div id, not div in args[]
const params = new URLSearchParams({
isMobile: WebDesktopEnvironment.isMobile,
path: args[0]
})
const response = await fetch(`/app/${Finder.AppId}/renderDesktop?` + params,
{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
WebDesktopEnvironment.Alert("Error in render desktop") //TODO
}
const html = await response.text()
args[2].innerHTML = html
this.fileView = new FileView(
args[2].querySelector(".FileTileView"), (event) =>{this.Click(event)},
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() }
)
this.RenderDir(args[0])
return
}
const params = new URLSearchParams({isMobile: WebDesktopEnvironment.isMobile})
const response = await fetch(`/app/${Finder.AppId}/render?` + params,
{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(Finder.AppId, 500, 350 )
newWindow.innerHTML = html
this.fileView = new FileView(
newWindow.querySelector(".FileTileView"),
(event) => { this.Click(event) },
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() }
)
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
newWindow.querySelector("#RootButton").addEventListener('click', () =>{
this.RenderDir('/')
})
newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
this.RenderDir('/home/user')
})
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.RenderDir(args[0])
}
/**
* @param {string} path
*/
RenderDir(path){
this.curPath = path
this.fileView.OpenFolder(path)
}
ReRenderDir(){
this.RenderDir(this.curPath)
}
/**
* @param {DragEvent} event
* @param {HTMLElement} draggedElem
*/
async DropEvent(event){
// console.log(event.dataTransfer.getData("dropType"))
if (event.dataTransfer.getData("dropType") == "move"){
const sourcePath= event.dataTransfer.getData("filePath")
const targetPath = this.curPath + "/" + event.dataTransfer.getData("fileName")
const res = await WebFS.MoveFile(sourcePath, targetPath)
if (res){
this.ReRenderDir()
} else {
WebDesktopEnvironment.Alert("UWAGA TODO MOVE FILE ERROR") //TODO
}
} else {
console.log(event, this.curPath)
let files = event.dataTransfer.files
for (let i = 0; i < files.length; i++) {
const file = files[i];
console.log("file:" + file.name)
const res = await WebFS.UploadFile(file, this.curPath)
if (res){
this.ReRenderDir()
}
}
return
const params = new URLSearchParams({
parentPath: this.curPath,
})
const response = await fetch('/fs/upload/?' + params,
{
method: "POST", //TODO Change to PUT?
body: formData
})
if (response.status != 200){
WebDesktopEnvironment.Alert("ERROR IN UPLOADING FILE")//TODO
} else {
this.ReRenderDir()
}
}
}
/**
* @param {MouseEvent} event
*/
Click(event){
this.OpenFile(this.curPath, event.target.getAttribute("name"), event.target.getAttribute("filetype"))
}
/**
* @param {string} filePath
*/
async OpenFile(parentPath, fileName, fileType){
// console.log(parentPath, fileName, fileType)
// const splittedPath = filePath.split("/")
// const fileName = splittedPath[splittedPath.length - 1]
const fileExtension = fileName.split(".")[fileName.split(".").length - 1] //FIXME
switch (true) {
case fileType == "objectlink":
WebDesktopEnvironment.Alert("Links not supported yet")
break
case fileType == "pathlink":
let res = await WebFS.ReadPathLink(`${parentPath}/${fileName}`)
console.log(res)
this.OpenFile(res.parentPath, res.name, res.filetype)
break
case fileExtension == "app":
WebDesktopEnvironment.Open(`${parentPath}/${fileName}`, [])
break
case fileExtension == "blog":
WebDesktopEnvironment.Open(`/Applications/BlogViewer.app`, [`${parentPath}/${fileName}`])
break
case fileType == "directory":
WebDesktopEnvironment.Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
WebDesktopEnvironment.Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
WebDesktopEnvironment.Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
WebDesktopEnvironment.Alert("Unsupported file type")
break;
}
}
/**
* @param {MouseEvent} event
*/
RightClick(event){
this.CreateContextMenu(event.target, [event.clientY, event.clientX])
}
/**
* @param {HTMLElement} target
* @param {string[]} pos
*/
async CreateContextMenu(target, pos){
let context = ""
const fileName = target.getAttribute("name") //TODO check for null
const fileType = target.getAttribute("fileType")
if (target.classList.contains("FileTileView"))
{
context = "FileTileView"
} else {
context = fileType
}
let path = ""
if (fileName === null){
path = this.curPath
} else {
path = `${this.curPath}/${fileName}`
}
const params = new URLSearchParams({context: context, path: path})
const response = await fetch(`/app/${Finder.AppId}/contextMenu?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("ERROR in Context menu TODO"); //TODO
return
}
const html = await response.text()
let overlay = document.createElement("div") //TODO Move to WDE.CreateOverlay()
overlay.setAttribute('id', 'finder-context-menu-overlay')
overlay.style.position = 'absolute'
overlay.style.width = "100%"
overlay.style.height = "100%"
let menu = document.createElement("div")
menu.setAttribute('class', 'ContextMenu WindowFrameShadow')
menu.style.position = 'absolute';
menu.style.top = pos[0] + "px";
menu.style.left = pos[1] + "px";
menu.innerHTML = html
// menu.children[0].firstElementChild.remove()
menu.children[0].lastElementChild.remove() //FIXME Can't ommit rendering of horLine in end of menu on backend
overlay.appendChild(menu)
document.body.appendChild(overlay)
overlay.addEventListener('click', async (event) => {
if (event.target.classList.contains("Row")){ //TODO add uuid id to rows to more accurate checks??
let res = false
switch (event.target.children[0].getAttribute("action")) {
case "createPathLink":
res = await WebFS.CreatePathLink(`${this.curPath}/${fileName}`, `${this.curPath}/Link to ${fileName}` )
if (res){
this.ReRenderDir()
}
break
case "createDir":
res = await WebFS.CreateDirectory(`${this.curPath}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "deleteFile":
res = await WebFS.DeleteFile(`${this.curPath}/${fileName}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "getInfo":
Finder.RenderProperites(path)
break
case "openAsDir":
WebDesktopEnvironment.Open(`/Applications/${Finder.AppId}.app`,[`${this.curPath}/${fileName}`])
break
default:
break;
}
}
overlay.remove()
})
overlay.addEventListener('contextmenu', (event) => {
event.preventDefault();
overlay.remove()
})
}
}

View File

@ -1,131 +1,32 @@
class Finder{
static appId = "Finder"
appId = "Finder"
fileView = undefined
path = "/"
homePath = "/home/user"
windowElement
// previousPath = "/"
pathHistory = [] //FIXME Fixed length
constructor(){
// this.appElem = appElem
// WebDesktopEnvironment.RegisterApp(this)
}
class FinderAdmin{
static AppId = "FinderAdmin"
/**
* @param {string[]} args
*/
async NewWindow(args){
async NewWindow(args, runContext){
let newFinder = new FinderWindow()
await newFinder.Init(args)
return
this.path = args[0]
if (args[1] == "desktop"){
this.NewDesktop(args)
return
}
// const params = new URLSearchParams({isMobile: WebDesktopEnvironment.isMobile})
fetch(`/app/${Finder.appId}/render?` + params)
.then((response) => response.text())
.then((html) => {
let newWindow = WebDesktopEnvironment.CreateNewWindow(Finder.appId, 500, 350 )
newWindow.innerHTML = html
this.fileView = new FileView(newWindow.querySelector(".FileTileView"),
(event) =>{ this.Click(event) },
(event) =>{ this.RightClick(event) },
(event, draggedElem) =>{ this.DropEvent(event, draggedElem) },
)
this.OpenDir(this.path)
newWindow.querySelector("#RootButton").addEventListener('click', () =>{
this.OpenDir('/')
})
newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
this.OpenDir('/home/user')
})
this.windowElement = newWindow
if (!WebDesktopEnvironment.isMobile){
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
// console.log(newWindow.querySelector("#closeWindowButton"))
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
}
})
.catch((error) => {
WebDesktopEnvironment.Alert(error);
})
await newFinder.Init(args, runContext)
}
/**
* @param {string[]} args
*/
NewDesktop(args){
fetch(`${window.location.origin}/application/${Finder.appId}/renderDesktop?` + new URLSearchParams({
isMobile: WebDesktopEnvironment.isMobile,
path: args[0]
}))
.then((response) => response.text())
.then((html) => {
// console.log(args)
args[2].innerHTML = html
this.fileView = new FileView(args[2].querySelector(".FileTileView"), (event) =>{
this.Click(event, true)
})
this.OpenDir(this.path)
})
.catch((error) => {
WebDesktopEnvironment.Alert(error);
})
}
// OpenPreviousDir(){
// if (this.pathHistory.length > 0){
// // console.log(this.pathHistory)
// let path = this.pathHistory[this.pathHistory.length - 1]
// // console.log(typeof( this.pathHistory))
// this.pathHistory.pop()
// this.OpenDir(this.path)
// }
// }
/**
* @param {string} path
*/
OpenDir(path){
this.path = path
this.fileView.OpenFolder(path)
}
// /**
// */
// OpenNewDir(){
// WebDesktopEnvironment.Open("finder", [this.path])
// }
/**
* @param {string} path
* @returns {boolean}
* @param {string} path
* @returns {boolean}
*/
static async RenderProperites(path){
if (path == null || path ==""){
return
}
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/application/${Finder.appId}/renderProps?` + params)
const response = await fetch(`/app/Finder/renderProps?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("Error in properties render") //TODO
return false
}
const html = response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(Finder.appId, 350, 500 )
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(FinderAdmin.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
@ -135,89 +36,99 @@ class Finder{
class FinderWindow{
CurPath = ""
curPath = ""
fileView = undefined
windowElem = undefined
async Init(args){
// console.log(args)
addressBar = undefined
async Init(args, runContext){
if (args[1] === "-desktop"){
//todo pass div id, not div in args[]
const params = new URLSearchParams({
isMobile: WebDesktopEnvironment.isMobile,
path: args[0]
})
const response = await fetch(`/app/${Finder.appId}/renderDesktop?` + params)
const response = await fetch(`/app/Finder/renderDesktop?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("Error in render desktop") //TODO
}
const html = await response.text()
args[2].innerHTML = html
this.fileView = new FileView(args[2].querySelector(".FileTileView"), (event) =>{
this.Click(event, true)
})
this.RenderDir(args[0])
return
}
const params = new URLSearchParams({isMobile: WebDesktopEnvironment.isMobile})
const response = await fetch(`/app/${Finder.appId}/render?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("Finder ERROR TODO") //TODO
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(Finder.appId, 500, 350 )
newWindow.innerHTML = html
// console.log(this.ReRenderDir)
this.fileView = new FileView(
newWindow.querySelector(".FileTileView"),
(event) => { this.Click(event) },
this.fileView = new FileView(
args[2].querySelector(".FileTileView"), (event) =>{this.Click(event)},
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() }
)
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
)
this.RenderDir(args[0])
return
}
const params = new URLSearchParams({isMobile: WebDesktopEnvironment.isMobile})
const response = await fetch(`/app/Finder/render?` + params,{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(FinderAdmin.AppId, 500, 350 )
newWindow.innerHTML = html
this.fileView = new FileView(
newWindow.querySelector(".FileTileView"),
(event) => { this.Click(event) },
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() }
)
WebDesktopEnvironment.CloseWindow(newWindow)
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
})
newWindow.querySelector("#RootButton").addEventListener('click', () =>{
this.RenderDir('/')
})
newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
this.RenderDir('/home/user')
})
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.RenderDir(args[0])
}
newWindow.querySelector("#RootButton").addEventListener('click', () =>{
this.RenderDir('/')
})
newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
this.RenderDir('/home/user')
})
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.addressBar = newWindow.querySelector(".AddressBar")
this.RenderDir(args[0])
}
/**
* @param {string} path
*/
RenderDir(path){
this.CurPath = path
console.log(path)
this.curPath = path
this.addressBar.innerHTML = path
this.fileView.OpenFolder(path)
}
ReRenderDir(){
this.RenderDir(this.CurPath)
this.RenderDir(this.curPath)
}
/**
* @param {DragEvent} event
* @param {HTMLElement} draggedElem
* @param {DragEvent} event
* @param {HTMLElement} draggedElem
*/
async DropEvent(event){
// console.log(event.dataTransfer.getData("dropType"))
if (event.dataTransfer.getData("dropType") == "move"){
const sourcePath= event.dataTransfer.getData("filePath")
const targetPath = this.CurPath + "/" + event.dataTransfer.getData("fileName")
const targetPath = this.curPath + "/" + event.dataTransfer.getData("fileName")
const res = await WebFS.MoveFile(sourcePath, targetPath)
if (res){
this.ReRenderDir()
@ -225,17 +136,20 @@ class FinderWindow{
WebDesktopEnvironment.Alert("UWAGA TODO MOVE FILE ERROR") //TODO
}
} else {
WebDesktopEnvironment.Alert("Not fixed yet")
return
let formData = new FormData()
console.log(event, this.curPath)
let files = event.dataTransfer.files
for (let i = 0; i < files.length; i++) {
const element = files[i];
console.log(element)
formData.append("file", element) //FIXME Conn reset
const file = files[i];
console.log("file:" + file.name)
const res = await WebFS.UploadFile(file, this.curPath)
if (res){
this.ReRenderDir()
}
}
return
const params = new URLSearchParams({
parentPath: this.CurPath,
parentPath: this.curPath,
})
const response = await fetch('/fs/upload/?' + params,
{
@ -255,26 +169,40 @@ class FinderWindow{
* @param {MouseEvent} event
*/
Click(event){
let fileType = event.target.getAttribute("fileType")
let fileName = event.target.getAttribute("name")
this.OpenFile(this.curPath, event.target.getAttribute("name"), event.target.getAttribute("filetype"))
}
/**
* @param {string} filePath
*/
async OpenFile(parentPath, fileName, fileType){
// console.log(parentPath, fileName, fileType)
// const splittedPath = filePath.split("/")
// const fileName = splittedPath[splittedPath.length - 1]
const fileExtension = fileName.split(".")[fileName.split(".").length - 1] //FIXME
switch (fileType) {
case "directory":
if (fileExtension == "app"){
WebDesktopEnvironment.Open(`${this.CurPath}/${fileName}`, [])
} else{
WebDesktopEnvironment.Open(`/Applications/Finder.app`, [`${this.CurPath}/${fileName}`])
}
switch (true) {
case fileType == "objectlink":
WebDesktopEnvironment.Alert("Links not supported yet")
break
case "blog":
WebDesktopEnvironment.Open("/Applications/BlogViewer.app", [`${this.CurPath}/${fileName}`])
case fileType == "pathlink":
let res = await WebFS.ReadPathLink(`${parentPath}/${fileName}`)
console.log(res)
this.OpenFile(res.parentPath, res.name, res.filetype)
break
case "jpeg":
case "png":
WebDesktopEnvironment.Open("img-viewer", [this.CurPath + "/" + fileName])
case fileExtension == "app":
WebDesktopEnvironment.Open(`${parentPath}/${fileName}`, [])
break
case fileType == "directory":
WebDesktopEnvironment.Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
WebDesktopEnvironment.Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
WebDesktopEnvironment.Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
// console.log("Unsupported file type")
WebDesktopEnvironment.Alert("Unsupported file type")
break;
}
@ -293,7 +221,7 @@ class FinderWindow{
*/
async CreateContextMenu(target, pos){
let context = ""
const fileName = target.getAttribute("name")
const fileName = target.getAttribute("name") //TODO check for null
const fileType = target.getAttribute("fileType")
if (target.classList.contains("FileTileView"))
{
@ -301,8 +229,14 @@ class FinderWindow{
} else {
context = fileType
}
const params = new URLSearchParams({context: context, path: `${this.CurPath}/${fileName}`})
const response = await fetch(`/app/${Finder.appId}/contextMenu?` + params)
let path = ""
if (fileName === null){
path = this.curPath
} else {
path = `${this.curPath}/${fileName}`
}
const params = new URLSearchParams({context: context, path: path})
const response = await fetch(`/app/Finder/contextMenu?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("ERROR in Context menu TODO"); //TODO
return
@ -331,26 +265,32 @@ class FinderWindow{
if (event.target.classList.contains("Row")){ //TODO add uuid id to rows to more accurate checks??
let res = false
switch (event.target.children[0].getAttribute("action")) {
case "createPathLink":
res = await WebFS.CreatePathLink(`${this.curPath}/${fileName}`, `${this.curPath}/Link to ${fileName}` )
if (res){
this.ReRenderDir()
}
break
case "createDir":
res = await WebFS.CreateDirectory(`${this.CurPath}`)
res = await WebFS.CreateDirectory(`${this.curPath}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "deleteFile":
res = await WebFS.DeleteFile(`${this.CurPath}/${fileName}`)
res = await WebFS.DeleteFile(`${this.curPath}/${fileName}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "getInfo":
res = await Finder.RenderProperites(`${this.CurPath}/${fileName}`)
Finder.RenderProperites(path)
break
case "openAsDir":
WebDesktopEnvironment.Open(`/Applications/Finder.app`,[`${this.curPath}/${fileName}`])
break
case "openAsDir":
WebDesktopEnvironment.Open(`/Applications/${Finder.appId}.app`,[`${this.CurPath}/${fileName}`])
break
default:
break;
}

View File

@ -0,0 +1,53 @@
.FinderContent {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.FinderContent .ToolBar{
width: 100%;
height: 20px;
border-bottom: 1px solid #555555;
background-color: #EEEEEE;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content:left;
align-items: flex-start;
padding: 0px;
gap: 5px;
}
.ToolBar .AddressBar{
width:100%;
height: 100%;
background-color: white;
}
.Focused .FinderContent .ToolBar{
border-bottom: 1px solid #000000;
background-color: #DDDDDD;
}
.FinderContent .FinderFileView{
width: 100%;
height: 100%;
background-color: #FFFFFF;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}

View File

@ -1,12 +1,12 @@
@font-face{
font-family: "Virtue";
src:url("./virtue.ttf");
src:url("/res/dev-fs/fonts/virtue.ttf");
}
@font-face{
/* @font-face{
font-family: "Virtue";
src:url("./virtue.ttf")
}
src:url("/res/dev-fs/fonts/virtue.ttf")
} */
/* @media screen and (max-device-width: 2048px) and (max-device-height: 2048px) {
html {

54
res/dev-fs/wde/decorat.js Normal file
View File

@ -0,0 +1,54 @@
class WindowsCompositor{
static windowsLayer
constructor(){
this.windowLayer = document.body.querySelector('#windows-layer')
WindowsCompositor.windowsLayer = document.body.querySelector('#windows-layer')
if (!WebDesktopEnvironment.isMobile) {
let startDrag = function(event) {
let window = event.target.closest('.WindowFrame')
WindowsCompositor.bringWindowToFront(window)
if (event.target.classList.contains("DragArea")){
let xPosInit = event.offsetX
let yPosInit = event.offsetY
let dragWindow = function(event){
window.style.left = `${event.clientX - xPosInit}px`
window.style.top = `${event.clientY - yPosInit}px`
}
let stopDrag = function(){
removeEventListener('mousemove', dragWindow)
removeEventListener('mouseup', stopDrag)
}
addEventListener('mousemove', dragWindow)
addEventListener('mouseup', stopDrag)
}
}
WindowsCompositor.windowsLayer.addEventListener('mousedown', startDrag)
}
}
/**
* @param {HTMLElement} window
*/
static bringWindowToFront(window){ //FIXME
let previousWindow = WindowsCompositor.windowsLayer.lastChild
if (window == null || window == undefined){
return
}
if (window != previousWindow){
WindowsCompositor.windowsLayer.insertBefore(window, previousWindow.nextSibling)
previousWindow.classList.remove("Focused")
window.classList.add("Focused")
} else {
window.classList.add("Focused")
}
return
}
static ChangeURL(appWindow){
let appId = appWindow.getAttribute('appid')
window.history.replaceState(null, "", `/${appId}/`);
}
}

239
res/dev-fs/wde/wde.js Normal file
View File

@ -0,0 +1,239 @@
//TODO Scroll to mobile desktop: https://css-tricks.com/scroll-fix-content/
document.addEventListener('DOMContentLoaded', function() {
// console.log(window.screen.width)
wde = new WebDesktopEnvironment()
if (!WebDesktopEnvironment.isMobile){
// WebDesktopEnvironment.Open("finder", ["/home/user"])
// WebDesktopEnvironment.Open("blog-viewer", ["/home/user/blog1.blog"])
// WebDesktopEnvironment.Open("personal-properties", ["/home/user/aboutme.props"])
} else {
// WebDesktopEnvironment.Open("blog-viewer", ["/home/user/blog/test-1.blog"])
}
// WebDesktopEnvironment.Open("personal-properties")
}, false);
// const ErrorObject = {
// message string
// }
class WebDesktopEnvironment{
static Applications = {};
static isMobile = false
static decorat
static webFs
constructor(){
// WebDesktopEnvironment.isMobile = WebDesktopEnvironment.CheckMobile()
document.body.style.setProperty('--zoom', 1)
WebDesktopEnvironment.wc = new WindowsCompositor()
WebDesktopEnvironment.webFs = new WebFS()
this.loadWDE()
}
async loadWDE(){
// await WebDesktopEnvironment.load2('/Applications/Finder.app', [ "desktop", document.querySelector('#desktop-layer')]) //FIXME
// await WebDesktopEnvironment.Open('/Applications/Finder.app', ["/home/user/.desktop", "-desktop", document.querySelector('#desktop-layer')])
await WebDesktopEnvironment.Open('/Applications/Finder.app', ["/home/user/Blogs",])
// await WebDesktopEnvironment.Open('/Applications/Finder.app', ["/home/user",])
// await WebDesktopEnvironment.Open('/Applications/Finder.app', ["/home",])
// WebDesktopEnvironment.Open('/Applications/AboutMe.app', [])
// WebDesktopEnvironment.Open('/Applications/FinderAdmin.app', ["/home/user",])
// await WebDesktopEnvironment.Open('/Applications/BlogViewer.app', ["/home/user/Blogs/blog1.blog",])
}
/**
* @param {string} appPath
* @param {string[]} args
* @param {string} runPath
*/
static async Open(appPath, args, runPath){
const appManifest = await WebDesktopEnvironment.fetchApp(appPath)
if (appManifest === undefined) return //TODO return err
const runContext = {
isMobile: false,
bundlePath: appPath,
runPath: runPath //TODO
}
if (WebDesktopEnvironment.Applications[appManifest.appId] === undefined){
WebDesktopEnvironment.load2(appManifest, () =>{
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext)
})
} else {
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext)
}
}
/**
* @param {string} appManifest
* @param {function} onload callback after script loading
*/
static async load2(appManifest, onload){
let appElem = document.createElement("div")
appElem.setAttribute("appId", appManifest.appId)
//TODO Render scripts nodes on server
//FIXME Not support more than one js now :)
let script = document.createElement("script")
script.setAttribute("src", appManifest.js[0]) //FIXME path by fs read
script.setAttribute("async", "false") //TODO Possible may creates a problems??
appElem.appendChild(script)
document.getElementById("applications").appendChild(appElem)
script.addEventListener('load', (event) => {
let newApp = eval(`new ${appManifest.appId}()`);
//TODO Check if newApp undefined
WebDesktopEnvironment.Applications[appManifest.appId] = newApp;
onload()
})
return //TODO return result
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
static async fetchApp(path){
// console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} appId
* @param {number} width
* @param {number} height
* @returns {HTMLElement}
*/
static CreateNewWindow(appId, width, height) {
let newWindow = document.createElement("div")
newWindow.setAttribute('appid', appId)
if (WebDesktopEnvironment.isMobile){
newWindow.setAttribute("class", "MobileApplicationWindow")
document.body.querySelector('#windows-layer').appendChild(newWindow)
return newWindow
} else {
newWindow.setAttribute("class", "WindowFrame ConvexElement")
newWindow.setAttribute("windowId", WebDesktopEnvironment.makeid(4)) //TODO:
newWindow.style.width = width.toString() + "px"
newWindow.style.height = height.toString() + "px"
document.body.querySelector('#windows-layer').appendChild(newWindow)
return newWindow
}
}
/**
* @param {HTMLElement} window
*/
static CloseWindow(window) {
window.remove()
}
static CloseFocusedWindow() {
if (document.body.querySelector('#windows-layer').childElementCount > 1){
document.body.querySelector('#windows-layer').lastElementChild.remove()
}
}
/**
* @param {string} html
*/
static SetBasicWindow(html){
this.basicWindow = html
}
/**
* @returns {string}
*/
static GetBasicWindow(){
return this.basicWindow
}
/**
* @param {string} alertText
*/
static Alert(alertText){
WebDesktopEnvironment.CreateAlertWindow(alertText)
console.log(alertText)
}
/**
* @param {string} alertText
*/
static CreateAlertWindow(alertText){
let newWindow = document.createElement("div")
newWindow.setAttribute("class", "WindowFrameless")
newWindow.setAttribute("windowId", "SuperUniqUUID") //TODO:
newWindow.style.cssText = "position:absolute;width:450px;height:116px; margin-left: -225px; margin-top:-58px;left: 50%;top: 50%;background-color:#FFFFFF;border: 1px solid #000000;box-shadow: 2px 2px 0px #000000;"
let alertImage = document.createElement("img")
alertImage.setAttribute("src", "/res/sys/wde/icons/ohno.png")
alertImage.style.cssText = "position:absolute; width:64px;height:64px;top:15px;left:25px"
newWindow.appendChild(alertImage)
let errorText = document.createElement("div")
errorText.style.cssText = "position:absolute; width: 300px; left:128px; top:30px;font-family: 'Virtue';"
errorText.innerHTML = alertText
newWindow.appendChild(errorText)
let closeButton = document.createElement("button")
closeButton.style.cssText = "position:absolute; left: 382px; bottom: 10px; background-color:#FFFFFF; width: 55px; height:18px; font-family: 'Virtue'; border-radius:4px;border: 1px solid #000000;"
closeButton.innerHTML = "Close"
closeButton.addEventListener('click', () => { newWindow.remove()})
newWindow.appendChild(closeButton)
document.body.querySelector('#windows-layer').appendChild(newWindow)
}
static CheckMobile(){
var check = false;
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
return check;
}
/**
* @param {num} length
*/
static makeid(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
}
//Deprecated
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status === 200) {
callback(null, xhr.response);
} else {
callback(status, xhr.response);
}
};
xhr.send();
};

131
res/dev-fs/wde/webfs.js Normal file
View File

@ -0,0 +1,131 @@
class WebFS{
/**
* @param {string} path
* @returns {boolean}
*/
static async CreateDirectory(path){
if (path == undefined){
WebDesktopEnvironment.Alert("Path is undefined")
return false
}
const params = new URLSearchParams({
path: `${path}/New Directory`
})
const response = await fetch(`/system/fs/createDir?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("DIRCTORY CREATION ERROR") //TODO
return false
}
return true
}
/**
* @param {string} path
* @returns {boolean}
*/
static async DeleteFile(path){
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/system/fs/delete?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("DELETE ERROR") //TODO
return false
}
return true
}
/**
* @param {string} path
* @returns {boolean}
*/
static async MoveFile(sourcePath, targetPath){
const params = new URLSearchParams({
sourcePath: sourcePath,
targetPath: targetPath
})
const response = await fetch(`/system/fs/move?` + params)
if (response.status != 200){
// WebDesktopEnvironment.Alert("Move ERROR") //TODO
return false
}
return true
}
/**
* @param {string} linkPath
* @returns {string}
*/
static async ReadObjectLink(linkPath){
const params = new URLSearchParams({
linkPath: linkPath,
})
const response = await fetch(`/system/fs/readObjectLink?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("TODO") //TODO
return ""
}
const path = await response.text()
//TODO Validate
return path
}
/**
* @param {string} sourcePath
* @param {string} linkPath
* @returns {string}
*/
static async CreatePathLink(sourcePath, linkPath){
const params = new URLSearchParams({
sourcePath: sourcePath,
linkPath: linkPath,
})
const response = await fetch(`/system/fs/createPathLink?` + params)
return response.status == 200
}
/**
* @param {string} linkPath
* @returns {string}
*/
static async ReadPathLink(linkPath){
const params = new URLSearchParams({
linkPath: linkPath,
})
const response = await fetch(`/system/fs/readPathLink?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("TODO") //TODO
return ""
}
// console.log(response)
const file = await response.json()
//TODO Validate
return file
}
/**
* @param {File} file
* @param {string} parentPath
* @returns {boolean}
*/
static async UploadFile(file, parentPath){
console.log('here')
let formData = new FormData()
formData.append("file", file) //FIXME Conn reset
const params = new URLSearchParams({
parentPath: parentPath,
})
const response = await fetch(`/system/fs/upload?` + params,
{
method: "POST", //TODO Change to PUT?
body: formData
})
console.log(response.status)
if (response.status != 201){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return false
}
return true
}
}

View File

@ -1,5 +0,0 @@
export class Application{
Init(){
}
}

View File

@ -1 +0,0 @@
//

View File

@ -1,8 +0,0 @@
<div id="prop" class="personal-properties-prop">
{{ range $book := .books }}
<h1>{{ .Title }}</h1>
<h3>{{ .Author }}</h3>
<hr/>
{{ end }}
</div>

View File

@ -1,29 +0,0 @@
<div class="Personal-properties-bio">
<img src="res/img/default-avatar-photo-placeholder-profile-picture-vector.jpg" style="width: 48px;height: 48px;">
<div class="Personal-properties-textbio">
<div>{{ .Name }}</div>
<div>{{ .BasicBio }}</div>
</div>
</div>
{{ range $props := .allprops }}
<div id="prop" class="Personal-properties-prop">
<div class="Personal-properties-prop-header">
Test Title:
</div>
<div class="Personal-properties-prop-content">
{{range $prop := $props}}
<div class="Personal-properties-prop-row">
<div class="Personal-properties-prop-key">{{.Key}}:</div>
<div class="Personal-properties-prop-values">
{{ range $value := .Values }}
<div class="Personal-properties-prop-value">
{{ $value }}
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
{{ end }}

View File

@ -1,409 +0,0 @@
//TODO Scroll to mobile desktop: https://css-tricks.com/scroll-fix-content/
document.addEventListener('DOMContentLoaded', function() {
// console.log(window.screen.width)
wde = new WebDesktopEnvironment()
if (!WebDesktopEnvironment.isMobile){
// WebDesktopEnvironment.Open("finder", ["/home/user"])
// WebDesktopEnvironment.Open("blog-viewer", ["/home/user/blog1.blog"])
// WebDesktopEnvironment.Open("personal-properties", ["/home/user/aboutme.props"])
} else {
// WebDesktopEnvironment.Open("blog-viewer", ["/home/user/blog/test-1.blog"])
}
// WebDesktopEnvironment.Open("personal-properties")
}, false);
class WebDesktopEnvironment{
static Applications = {};
static isMobile = false
constructor(){
// WebDesktopEnvironment.isMobile = WebDesktopEnvironment.CheckMobile()
document.body.style.setProperty('--zoom', 1)
this.wc = new WindowsCompositor()
this.loadWDE()
let kek = new WebFS()
return
// let applications = document.createElement("div")
// applications.setAttribute('id', 'applications')
// document.body.appendChild(applications)
if( WebDesktopEnvironment.isMobile){
document.body.style.setProperty('--zoom', 3)
let mobileDesktop = document.createElement("div")
mobileDesktop.setAttribute('id', 'mobile-desktop')
document.body.appendChild(mobileDesktop)
fetch(`${window.location.origin}/system/wde/renderMobileDesktop` )
.then((response) => response.text())
.then((html) => {
mobileDesktop.innerHTML = html
WebDesktopEnvironment.LoadApp("finder", () =>{
new FileView("/kek", mobileDesktop.querySelector(".FileTileView"), Finder.Click)
mobileDesktop.querySelector('#about-me').addEventListener('click', (event) => {
//TODO Do not allow launch second instance
WebDesktopEnvironment.Open("personal-properties", [])
})
mobileDesktop.querySelector('#mobile-desktop-blog').addEventListener('click', (event) => {
//TODO Do not allow launch second instance
WebDesktopEnvironment.Open("blog-viewer", ['main-page'])
})
mobileDesktop.querySelector('#mobile-dekstop-close').addEventListener('click', (event) => {
// console.log('close')
WebDesktopEnvironment.CloseFocusedWindow()
})
})
})
.catch((error) => {
WebDesktopEnvironment.Alert(error);
})
} else{
// let desktopLayer = document.createElement("div")
// desktopLayer.setAttribute('id', 'desktop-layer')
// document.body.appendChild(desktopLayer)
WebDesktopEnvironment.Open("finder", ["/home/user", "desktop", desktopLayer])
// let windowsLayer = document.createElement("div")
// windowsLayer.setAttribute('id', 'windows-layer')
// document.body.appendChild(windowsLayer)
this.Autoload()
}
}
async loadWDE(){
// await WebDesktopEnvironment.load2('/Applications/Finder.app', [ "desktop", document.querySelector('#desktop-layer')])
WebDesktopEnvironment.Open('/Applications/Finder.app', ["/home/user/.Desktop", "-desktop", document.querySelector('#desktop-layer')])
// WebDesktopEnvironment.Open('/Applications/Finder.app', ["/home/user",])
}
/**
* @param {string} appPath
* @param {string[]} args
*/
static async Open(appPath, args){
WebDesktopEnvironment.fetchApp(appPath).then(async appManifest =>{
if (appManifest === undefined) return //TODO return err
if (WebDesktopEnvironment.Applications[appManifest.appId] === undefined){
WebDesktopEnvironment.load2(appManifest, () =>{
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args)
})
} else {
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args)
}
})
}
/**
* @param {string} appManifest
* @param {function} onload callback after script loading
*/
static async load2(appManifest, onload){
let appElem = document.createElement("div")
appElem.setAttribute("appId", appManifest.appId)
//TODO Render scripts nodes on server
//FIXME Not support more than one js now :)
let script = document.createElement("script")
script.setAttribute("src", appManifest.js[0]) //FIXME path by fs read
script.setAttribute("async", "false") //TODO Possible may creates a problems??
appElem.appendChild(script)
document.getElementById("applications").appendChild(appElem)
script.addEventListener('load', (event) => {
let newApp = eval(`new ${appManifest.appId}()`);
//TODO Check if newApp undefined
WebDesktopEnvironment.Applications[appManifest.appId] = newApp;
onload()
})
return //TODO return result
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
static async fetchApp(path){
const params = new URLSearchParams({path: path})
const response = await fetch(`/system/libs/apps/loadApp?` + params)
if (response.status != 200){
return undefined
}
const appManifest = response.json()
return appManifest
}
Autoload(){
// WebDesktopEnvironment.Open(["/home/user/AboutMe.app"])
// WebDesktopEnvironment.load2(["/home/user/AboutMe.app"])
}
/**
* @param {string} appId
* @param {function} func callback after script loading
* @returns {Application | undefined}
*/
static LoadApp(appId, func){
// console.log(`Load application ${appId}`)
let script = document.createElement("script")
script.setAttribute("appId", appId)
script.setAttribute("src", `${window.location.origin}/system/applications/${appId}/app.js`)
script.setAttribute("async", "false")
document.getElementById("applications").appendChild(script)
script.addEventListener('load', (event) =>{
switch (appId) {
case "finder":
let newFinderApp = new Finder()
this.Applications[appId] = newFinderApp
func()
return newFinderApp
case "personal-properties":
let newPersonalPropertiesApp = new PersonalProperties()
this.Applications[appId] = newPersonalPropertiesApp
func()
return newPersonalPropertiesApp
case "img-viewer":
let newImgViewer = new ImgViewer()
this.Applications[appId] = newImgViewer
func()
return newImgViewer
case "blog-viewer":
let newBlogViewer = new BlogViewer()
this.Applications[appId] = newBlogViewer
func()
return newBlogViewer
default:
break;
}
})
}
/**
* @param {string} appId
* @param {number} width
* @param {number} height
* @returns {HTMLElement}
*/
static CreateNewWindow(appId, width, height) {
let newWindow = document.createElement("div")
newWindow.setAttribute('appid', appId)
if (WebDesktopEnvironment.isMobile){
newWindow.setAttribute("class", "MobileApplicationWindow")
document.body.querySelector('#windows-layer').appendChild(newWindow)
return newWindow
} else {
newWindow.setAttribute("class", "WindowFrame ConvexElement")
newWindow.setAttribute("windowId", "SuperUniqUUID") //TODO:
newWindow.style.width = width.toString() + "px"
newWindow.style.height = height.toString() + "px"
document.body.querySelector('#windows-layer').appendChild(newWindow)
// WindowsCompositor.bringWindowToFront(newWindow)
return newWindow
}
}
/**
* @param {HTMLElement} window
*/
static CloseWindow(window) {
window.remove()
}
static CloseFocusedWindow() {
if (document.body.querySelector('#windows-layer').childElementCount > 1){
document.body.querySelector('#windows-layer').lastElementChild.remove()
}
}
/**
* @param {string} html
*/
static SetBasicWindow(html){
this.basicWindow = html
}
/**
* @returns {string}
*/
static GetBasicWindow(){
return this.basicWindow
}
/**
* @param {string} alertText
*/
static Alert(alertText){
WebDesktopEnvironment.CreateAlertWindow(alertText)
console.log(alertText)
}
/**
* @param {string} alertText
*/
static CreateAlertWindow(alertText){
// console.log("alertWinfdo")
let newWindow = document.createElement("div")
newWindow.setAttribute("class", "WindowFrameless")
newWindow.setAttribute("windowId", "SuperUniqUUID") //TODO:
newWindow.style.cssText = "position:absolute;width:450px;height:116px; left: 50%;top: 50%;background-color:#FFFFFF;border: 1px solid #000000;box-shadow: 2px 2px 0px #000000;"
let alertImage = document.createElement("img")
alertImage.setAttribute("src", "/res/sys/wde/icons/ohno.png")
alertImage.style.cssText = "position:absolute; width:64px;height:64px;top:15px;left:25px"
newWindow.appendChild(alertImage)
let errorText = document.createElement("div")
errorText.style.cssText = "position:absolute; width: 300px; left:128px; top:30px;font-family: 'Virtue';"
errorText.innerHTML = alertText
newWindow.appendChild(errorText)
let closeButton = document.createElement("button")
closeButton.style.cssText = "position:absolute; left: 382px; bottom: 10px; background-color:#FFFFFF; width: 55px; height:18px; font-family: 'Virtue'; border-radius:4px;border: 1px solid #000000;"
closeButton.innerHTML = "Close"
closeButton.addEventListener('click', () => { newWindow.remove()})
newWindow.appendChild(closeButton)
document.body.querySelector('#windows-layer').appendChild(newWindow)
}
static CheckMobile(){
var check = false;
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
return check;
}
}
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status === 200) {
callback(null, xhr.response);
} else {
callback(status, xhr.response);
}
};
xhr.send();
};
class WindowsCompositor{
static windowsLayer
constructor(){
this.windowLayer = document.body.querySelector('#windows-layer')
WindowsCompositor.windowsLayer = document.body.querySelector('#windows-layer')
if (!WebDesktopEnvironment.isMobile) {
let startDrag = function(event) {
let window = event.target.closest('.WindowFrame')
WindowsCompositor.bringWindowToFront(window)
if (event.target.classList.contains("DragArea")){
let xPosInit = event.offsetX
let yPosInit = event.offsetY
let dragWindow = function(event){
window.style.left = `${event.clientX - xPosInit}px`
window.style.top = `${event.clientY - yPosInit}px`
}
let stopDrag = function(){
removeEventListener('mousemove', dragWindow)
removeEventListener('mouseup', stopDrag)
}
addEventListener('mousemove', dragWindow)
addEventListener('mouseup', stopDrag)
}
}
WindowsCompositor.windowsLayer.addEventListener('mousedown', startDrag)
}
}
/**
* @param {HTMLElement} window
*/
static bringWindowToFront(window){ //FIXME
if (window == null | window == undefined){
return
}
let previousWindow = WindowsCompositor.windowsLayer.lastChild
if (window != previousWindow){
WindowsCompositor.windowsLayer.insertBefore(previousWindow, window)
}
if (!window.classList.contains("Focused")){
previousWindow.classList.remove("Focused")
window.classList.add("Focused")
}
// WindowsCompositor.ChangeURL(window)
}
static ChangeURL(appWindow){
let appId = appWindow.getAttribute('appid')
window.history.replaceState(null, "", `/${appId}/`);
}
}
class WebFS{
/**
* @param {string} path
* @returns {boolean}
*/
static async CreateDirectory(path){
if (path == undefined){
WebDesktopEnvironment.Alert("Path is undefined")
return false
}
const params = new URLSearchParams({
path: `${path}/New Directory`
})
const response = await fetch(`/fs/createDir?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("DIRCTORY CREATION ERROR") //TODO
return false
}
return true
}
/**
* @param {string} path
* @returns {boolean}
*/
static async DeleteFile(path){
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/fs/delete?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("DELETE ERROR") //TODO
return false
}
return true
}
/**
* @param {string} path
* @returns {boolean}
*/
static async MoveFile(sourcePath, targetPath){
const params = new URLSearchParams({
sourcePath: sourcePath,
targetPath: targetPath
})
const response = await fetch(`/fs/move?` + params)
if (response.status != 200){
// WebDesktopEnvironment.Alert("Move ERROR") //TODO
return false
}
return true
}
}

132
routes/private.go Normal file
View File

@ -0,0 +1,132 @@
package routes
import (
"log"
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/errormessage"
"personalwebsite/libs"
"personalwebsite/routewde"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"time"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
"github.com/thinkerou/favicon"
)
func PrivateRoutes(webfs *webfilesystem.WebFileSystem, webde *wde.WDE, appsStorage *apps.ApplicationsStorage) {
router := gin.New()
router.Use(location.Default())
router.Use(favicon.New("./res/dev-fs/wde/icons/ohno.png"))
router.LoadHTMLGlob("templates/**/*")
router.Static("/res", "res")
// Set a lower memory limit for multipart forms (default is 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{})
})
systemGroup := router.Group("system")
{
libsGroup := systemGroup.Group("libs")
{
imgLibGroup := libsGroup.Group("img")
{
imgLib := libs.NewImgLib(webfs)
imgLib.PublicRoutes(imgLibGroup)
}
catLibGroup := libsGroup.Group("cat")
{
catLib := libs.NewCatLib(webfs)
catLib.PublicRoutes(catLibGroup)
}
appsStorageGroup := libsGroup.Group("apps")
{
appsStorage.PrivateRoute(appsStorageGroup)
}
}
wdeGroup := systemGroup.Group("wde")
{
routewde.PublicRoutes(wdeGroup, webde)
}
fsGroup := systemGroup.Group("fs")
{
webfs.PrivateRoutes(fsGroup)
}
systemGroup.GET("/loadApp", func(ctx *gin.Context) {
appPath := ctx.Query("path")
if appPath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "Path for the App not provided in request",
})
return
}
appBundleData := webfilesystem.DirectoryData{}
appBundle, err := webfs.Read(appPath, &appBundleData)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: "Error in read App bundle",
})
return
}
if appBundle.Type != "directory" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "App bundle file is bad",
})
return
}
appManifestData := apps.ApplicationManifest{}
appManifestHeader, err := webfs.Read(path.Join(appPath, ".appmanifest"), &appManifestData)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: "Error in read App manifest",
})
return
}
if appManifestHeader.Type != "application-manifest" {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: "Error in read App manifest",
})
return
}
ctx.JSON(http.StatusOK, appManifestData)
})
}
appsGroup := router.Group("app")
{
for _, app := range appsStorage.Apps {
appsRoutes := appsGroup.Group(app.GetAppID())
app.PrivateRoutes(appsRoutes)
}
}
router.Use(cors.New(cors.Config{
AllowAllOrigins: true,
// AllowOrigins: []string{"http://localhost:8080", "http://localhost:9090"},
// AllowMethods: []string{"PUT", "PATCH"},
// AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
// AllowOriginFunc: func(origin string) bool {
// return origin == "https://github.com"
// },
MaxAge: 12 * time.Hour,
}))
err := router.Run(":8080")
if err != nil {
log.Panicf("error: %s", err)
}
}

103
routes/public.go Normal file
View File

@ -0,0 +1,103 @@
package routes
import (
"log"
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/libs"
"personalwebsite/routewde"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
"github.com/thinkerou/favicon"
)
func PublicRoutes(webfs *webfilesystem.WebFileSystem, webde *wde.WDE, appsStorage *apps.ApplicationsStorage) {
router := gin.New()
router.Use(location.Default())
router.LoadHTMLGlob("templates/**/*")
router.Use(favicon.New("./res/dev-fs/wde/icons/ohno.png")) // set favicon middleware
router.Static("/res", "res")
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{})
})
systemGroup := router.Group("system")
{
libsGroup := systemGroup.Group("libs")
{
imgLibGroup := libsGroup.Group("img")
{
imgLib := libs.NewImgLib(webfs)
imgLib.PublicRoutes(imgLibGroup)
}
catLibGroup := libsGroup.Group("cat")
{
catLib := libs.NewCatLib(webfs)
catLib.PublicRoutes(catLibGroup)
}
}
wdeGroup := systemGroup.Group("wde")
{
routewde.PublicRoutes(wdeGroup, webde)
}
systemGroup.GET("/loadApp", func(ctx *gin.Context) {
appPath := ctx.Query("path")
if appPath == "" {
ctx.Status(http.StatusBadRequest)
return
}
appBundleData := webfilesystem.DirectoryData{}
appBundle, err := webfs.Read(appPath, &appBundleData)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
if appBundle.Type != "directory" {
ctx.Status(http.StatusBadRequest)
return
}
appManifestData := apps.ApplicationManifest{}
appManifestHeader, err := webfs.Read(path.Join(appPath, ".appmanifest"), &appManifestData)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
if appManifestHeader.Type != "application-manifest" {
ctx.Status(http.StatusBadRequest)
return
}
ctx.JSON(http.StatusOK, appManifestData)
})
fsGroup := systemGroup.Group("fs")
{
webfs.PublicRoutes(fsGroup)
}
}
appGroup := router.Group("app")
{
for _, app := range appsStorage.Apps {
appRoutes := appGroup.Group(app.GetAppID())
app.PublicRoutes(appRoutes)
}
}
err := router.Run(":7070")
if err != nil {
log.Panicf("error: %s", err)
}
}

View File

@ -8,8 +8,8 @@ import (
"github.com/gin-gonic/gin"
)
func Route(route *gin.RouterGroup, wde *wde.WDE) {
route.GET("/getbasicwindow", func(ctx *gin.Context) {
func PublicRoutes(route *gin.RouterGroup, wde *wde.WDE) {
route.GET("/getbasicwindow", func(ctx *gin.Context) { //TODO Rename to renderGenericWindowFrame
ctx.HTML(http.StatusOK, "basic-window.html", nil)
})
@ -21,7 +21,6 @@ func Route(route *gin.RouterGroup, wde *wde.WDE) {
{
widgets.GET("/file-tile-view", func(ctx *gin.Context) {
url := location.Get(ctx)
// _ = url
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "TODO") //TODO json error struct

View File

@ -2,34 +2,29 @@
<html lang="en" dir="ltr">
<title>Greg Brzezinski</title>
<head>
<link rel="stylesheet" type="text/css" href="res/base.css">
<link rel="stylesheet" type="text/css" href="res/wdeUI.css">
<link rel="stylesheet" type="text/css" href="res/sys/wde/basic-widgets.css">
<link rel="stylesheet" type="text/css" href="res/sys/wde/wde-scrollbar.css">
<link rel="stylesheet" type="text/css" href="res/sys/wde/basic-widgets.css">
<link rel="stylesheet" type="text/css" href="res/sys/wde/file-view.css">
<link rel="stylesheet" type="text/css" href="res/sys/libs/fs.js">
<link rel="stylesheet" type="text/css" href="res/mobile-wdeUI.css">
<link rel="stylesheet" href="/res/sys/wde/simple-scrollbar.css">
<link rel="stylesheet" type="text/css" href="res/sys/finder/finder.css">
<link rel="stylesheet" href="/res/sys/personal-properties/personal-properies.css">
<link rel="stylesheet" href="/res/sys/img-viewer/img-viewer.css">
<link rel="stylesheet" href="/res/sys/blog-viewer/blog-viewer.css">
<script src="/res/sys/wde/wde-scrollbar.js"></script>
<script src="/res/sys/wde/file-view.js"></script>
<script src="res/wde.js"></script>
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> -->
<!-- <script src="res/decorat.js"></script> -->
<!-- TODO Load with app -->
<!-- <script src="res/personal-properties.js"></script> -->
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/base.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/wdeUI.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/basic-widgets.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/wde-scrollbar.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/file-view.css">
<!-- TODO: Move css init to js -->
<link rel="stylesheet" href="res/dev-fs/apps/Finder/finder.css">
<link rel="stylesheet" href="/res/dev-fs/apps/AboutMe/about-me.css">
<link rel="stylesheet" href="/res/dev-fs/apps/ImgViewer/img-viewer.css">
<link rel="stylesheet" href="/res/dev-fs/apps/BlogViewer/blog-viewer.css">
<script src="res/dev-fs/wde/wde.js"></script>
<script src="res/dev-fs/wde/decorat.js"></script>
<script src="res/dev-fs/wde/webfs.js"></script>
<script src="/res/dev-fs/wde/wde-scrollbar.js"></script>
<script src="/res/dev-fs/wde/file-view.js"></script>
</head>
<body>
<!-- <div id="WindowsLayer"></div> -->
<div id="applications"></div>
<div id="desktop-layer"></div>
<div id="windows-layer"></div>
<!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" >
<div id="TestWindowHeader" class="VisualDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;">
</div> -->
</body>
</html>

View File

@ -12,13 +12,21 @@
<div class="Content">
<div class="ScrollContent">
{{ range $block := .blocks }}
<div class="{{$block.Type}}" >
{{ range $data := $block.Data }}
<div style="font-size: inherit;">
{{$data}}
</div>
{{ end }}
</div>
{{ if eq $block.Type "image"}}
<div class="{{$block.Type}}" >
{{ range $data := $block.Data }}
<img class="ImageProp" src="/system/libs/img/get?path={{$data}}">
{{ end }}
</div>
{{ else }}
<div class="{{$block.Type}}" >
{{ range $data := $block.Data }}
<div style="font-size: inherit;">
{{$data}}
</div>
{{ end }}
</div>
{{ end }}
{{ end }}
</div>
</div>

View File

@ -13,8 +13,11 @@
<div class="FinderContent">
<!-- TODO Fix ConvexElement -->
<div class="ToolBar ConvexElement">
<button id="BackButton">Back</button>
<button id="UpButton">Up</button>
<button id="RootButton">/</button>
<button id="HomeButton">Home</button>
<div class="AddressBar" contentEditable="true">You Favorite Movie</div>
</div>
<div class="FinderFileView">
<div class="FileTileView">

View File

@ -1,24 +1,27 @@
{{ define "finder/app.tmpl" }}
<div class="TitleBar DragArea">
<button id="closeWindowButton" class="Button" title="Close Window"></button>
<div class="TitleBarTest">
<div id="Drag" class="VisualDragArea"></div>
<div class="Lable">
Files
Finder
</div>
<div id="Drag" class="VisualDragArea"></div>
</div>
</div>
<div class="ToolBar">
<button id="BackButton">Back</button>
<button id="HomeButton">Home</button>
</div>
<div class="ContentBorder ConvexElement">
<div class="FileTileView">
<div id="ContentBorder" class="ContentBorder AdjectiveElement">
<div class="FinderContent">
<!-- TODO Fix ConvexElement -->
<div class="ToolBar ConvexElement">
Folder info
</div>
<div class="FinderFileView">
<div class="FileTileView">
</div>
{{template "wde-widgets/scrollbar.tmpl" .}}
</div>
</div>
{{template "wde-widgets/scrollbar.tmpl" .}}
</div>
{{ end }}

View File

@ -20,6 +20,9 @@
<div>
file id : {{.file.MongoId}}
</div>
<div>
file type : {{.file.Type}}
</div>
<div>
file data id : {{.file.Data}}
</div>

BIN
test-img/myphoto.jpg (Stored with Git LFS)

Binary file not shown.

View File

@ -21,30 +21,6 @@ func NewWDE(webFs *webfilesystem.WebFileSystem) *WDE {
type FilesWidget struct {
}
// Deprecated
func (w *WDE) Render(path string) (gin.H, error) {
// list, err := w.fs.NewListDeprecated(path)
// if err != nil {
// return nil, err
// }
return gin.H{
"Name": "Greg Brzezinski",
// "Files": list,
}, nil
}
// Deprecated
func (w *WDE) RenderContextMenu() (gin.H, error) {
// list, err := w.fs.List(path)
// if err != nil {
// return nil, err
// }
return gin.H{
"Name": "Greg Brzezinski",
// "Files": list,
}, nil
}
func (w *WDE) RenderFileTileView(directory string, host string) (gin.H, error) {
list, err := w.fs.ListDir(directory)
if err != nil {

View File

@ -7,9 +7,9 @@ import (
)
type DirectoryData struct {
MongoId primitive.ObjectID `bson:"_id"`
Parent primitive.ObjectID `bson:"parent_id"`
Children []primitive.ObjectID `bson:"children_id"`
MongoId primitive.ObjectID `bson:"_id" json:"-"`
Parent primitive.ObjectID `bson:"parent_id" json:"parent"` //TODO: Delete
Children []primitive.ObjectID `bson:"children_id" json:"children"`
}
func (fs *WebFileSystem) CreateDirectory(dirPath string) (primitive.ObjectID, primitive.ObjectID, error) {
@ -96,15 +96,37 @@ func (fs *WebFileSystem) ListDir(dirPath string) ([]*FileHeader, error) {
return nil, err
}
children, err := fs.listDirByObjectID(dirId)
// dirData := DirectoryData{}
// _, err = fs.readFSDocs(dirId, &dirData)
// if err != nil {
// return nil, err
// }
// // println(dirId.String())
// // println(dirData.MongoId.String())
// children := []*FileHeader{}
// for _, childID := range dirData.Children {
// childFile, err := fs.readFSDocs(childID, nil)
// if err != nil {
// // println(err.Error())
// continue
// }
// children = append(children, childFile)
// }
return children, nil
}
func (fs *WebFileSystem) listDirByObjectID(dirId primitive.ObjectID) ([]*FileHeader, error) {
dirData := DirectoryData{}
_, err = fs.readFSDocs(dirId, &dirData)
_, err := fs.readFSDocs(dirId, &dirData)
if err != nil {
return nil, err
}
// println(dirId.String())
// println(dirData.MongoId.String())
children := []*FileHeader{}
for _, childID := range dirData.Children {
childFile, err := fs.readFSDocs(childID, nil)

View File

@ -5,13 +5,13 @@ package webfilesystem
import (
"errors"
"os"
"path"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func (fs *WebFileSystem) UploadFile(realFilepath string, parentPath string) error {
func (fs *WebFileSystem) UploadFile(realFilepath string, filePath string) error {
//TODO check is file exists
// parentPath := fs.GetParentPath(filePath)
file, err := os.ReadFile(realFilepath)
if err != nil {
return err
@ -33,7 +33,7 @@ func (fs *WebFileSystem) UploadFile(realFilepath string, parentPath string) erro
Bin: file,
}
filePath := path.Join(parentPath, fileName)
// filePath := path.Join(parentPath, fileName)
switch extension {
case "jpg":

View File

@ -6,6 +6,7 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
//TODO Transparently split to single data and header reading methods
func (fs *WebFileSystem) readFSDocs(fileID primitive.ObjectID, fileData interface{}) (*FileHeader, error) {
fileHeader := &FileHeader{}
filter := primitive.M{
@ -41,7 +42,33 @@ func (fs *WebFileSystem) writeFileToMongo(file *FileHeader, data interface{}) (p
}
func (fs *WebFileSystem) removeFromMongo(fileId primitive.ObjectID) error {
return errors.New("todo not implemented yet")
fileHeader, err := fs.readFSDocs(fileId, nil)
if err != nil {
return err
}
filterHeader := primitive.M{
"_id": fileHeader.MongoId,
}
res, err := fs.webfsFilesTable.DeleteOne(fs.ctx, filterHeader)
if err != nil {
return err
}
if res.DeletedCount < 1 {
return errors.New("no file header deleted")
}
filterData := primitive.M{
"_id": fileHeader.Data,
}
res, err = fs.webfsFilesData.DeleteOne(fs.ctx, filterData)
if err != nil {
return err
}
if res.DeletedCount < 1 {
return errors.New("no file data deleted")
}
return nil
}
//Deprecated

View File

@ -8,7 +8,7 @@ func (fs *WebFileSystem) Read(filePath string, fileData interface{}) (*FileHeade
return nil, err
}
fileHeader, err := fs.readFSDocs(fileId, fileData)
fileHeader, err := fs.ReadByObjectID(fileId, fileData)
if err != nil {
return nil, err
}
@ -22,5 +22,19 @@ func (fs *WebFileSystem) ReadByObjectID(fileID primitive.ObjectID, fileData inte
return nil, err
}
if fileHeader.Type == "objectlink" {
objectLinkData := ObjectLinkFileData{}
_, err := fs.readFSDocs(fileID, &objectLinkData)
if err != nil {
return nil, err
}
fileHeader, err := fs.readFSDocs(objectLinkData.Link_id, fileData)
if err != nil {
return nil, err
}
return fileHeader, nil
}
return fileHeader, nil
}

View File

@ -2,11 +2,14 @@ package webfilesystem
import (
"net/http"
"path"
"personalwebsite/errormessage"
"github.com/gin-gonic/gin"
)
func (fs *WebFileSystem) Route(route *gin.RouterGroup) {
func (fs *WebFileSystem) PrivateRoutes(route *gin.RouterGroup) {
fs.PublicRoutes(route)
route.POST("/upload", func(ctx *gin.Context) { //TODO To PUT request
// fileName := ctx.Query("fileName")
// if fileName == "" {
@ -32,9 +35,11 @@ func (fs *WebFileSystem) Route(route *gin.RouterGroup) {
ctx.SaveUploadedFile(file, dst)
//TODO: Not Save to disk
err := fs.UploadFile(dst, parentPath)
err := fs.UploadFile(dst, path.Join(parentPath, file.Filename))
if err != nil {
ctx.String(http.StatusInternalServerError, "TODO") //TODO
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
@ -45,6 +50,28 @@ func (fs *WebFileSystem) Route(route *gin.RouterGroup) {
ctx.Status(http.StatusCreated)
})
//TODO Support Object links
// route.POST("/createlink", func(ctx *gin.Context) { //TODO To PUT request
// sourcePath := ctx.Query("sourcePath")
// if sourcePath == "" {
// ctx.JSON(http.StatusBadRequest, "TODO") //TODO json error struct
// return
// }
// targetPath := ctx.Query("targetPath")
// if sourcePath == "" {
// ctx.JSON(http.StatusBadRequest, "TODO") //TODO json error struct
// return
// }
// err := fs.CreateObjectLink(sourcePath, targetPath)
// if err != nil {
// ctx.String(http.StatusInternalServerError, err.Error()) //TODO
// return
// }
// ctx.Status(http.StatusCreated)
// })
// route.GET("writeFile", func(ctx *gin.Context) {
// parentPath := ctx.Query("parentPath")
// if parentPath == "" {
@ -166,4 +193,67 @@ func (fs *WebFileSystem) Route(route *gin.RouterGroup) {
ctx.Status(http.StatusOK)
})
route.GET("readObjectLink", func(ctx *gin.Context) {
linkPath := ctx.Query("linkPath")
if linkPath == "" {
ctx.Status(http.StatusBadRequest) //TODO
return
}
// file, err := fs.Read(linkPath, nil)
ctx.Status(http.StatusOK)
})
route.GET("createPathLink", func(ctx *gin.Context) {
sourcePath := ctx.Query("sourcePath")
if sourcePath == "" {
ctx.Status(http.StatusBadRequest) //TODO
return
}
linkPath := ctx.Query("linkPath")
if linkPath == "" {
ctx.Status(http.StatusBadRequest) //TODO
return
}
_, _, err := fs.CreatePathLink(sourcePath, linkPath)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.Status(http.StatusOK)
})
}
func (fs *WebFileSystem) PublicRoutes(route *gin.RouterGroup) {
route.GET("readPathLink", func(ctx *gin.Context) {
linkPath := ctx.Query("linkPath")
if linkPath == "" {
ctx.Status(http.StatusBadRequest) //TODO
return
}
linkData := PathLinkFileData{}
linkHeader, err := fs.Read(linkPath, &linkData)
if err != nil {
ctx.Status(http.StatusBadRequest) //TODO
return
}
if linkHeader.Type != "pathlink" {
ctx.Status(http.StatusBadRequest)
return
}
FileHeader, err := fs.Read(linkData.Path, nil)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.JSON(http.StatusOK, FrontEndFile{
Name: FileHeader.Name,
Type: FileHeader.Type,
ParentPath: fs.GetParentPath(linkData.Path),
})
})
}

View File

@ -1,6 +1,45 @@
package webfilesystem
import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
func (fs *WebFileSystem) validate() error {
filter := primitive.M{
// "type": "directory",
}
cur, err := fs.webfsFilesTable.Find(fs.ctx, filter)
if err != nil {
return err
}
orfanedDir, err := fs.Read("/orfaned", nil)
if err != nil {
return err
}
_ = orfanedDir
for cur.Next(fs.ctx) {
fileHeader := FileHeader{}
cur.Decode(&fileHeader)
if fileHeader.Name == "/" {
continue
}
res, err := fs.checkFileParent(&fileHeader)
if err != nil {
return err
}
if !res {
println(fileHeader.Name)
err := fs.moveByID(fileHeader.MongoId, primitive.NilObjectID, orfanedDir.MongoId, true)
if err != nil {
println(err.Error())
println()
continue
}
}
// println()
}
// rootHeader, rootData, err := fs.GetRootDir()
// if err != nil {
// return err
@ -53,6 +92,35 @@ func (fs *WebFileSystem) validate() error {
return nil
}
func (fs *WebFileSystem) checkFileParent(checkFileHeader *FileHeader) (bool, error) {
filter := primitive.M{
"type": "directory",
}
cur, err := fs.webfsFilesTable.Find(fs.ctx, filter)
if err != nil {
return false, err
}
// parentFounded := false
for cur.Next(fs.ctx) {
dirHeader := FileHeader{}
// dirData := DirectoryData{}
cur.Decode(&dirHeader)
_, err := fs.readFSDocs(dirHeader.MongoId, nil)
if err != nil {
return false, err
}
children, err := fs.listDirByObjectID(dirHeader.MongoId)
for _, child := range children {
if child.MongoId == checkFileHeader.MongoId {
return true, nil
}
// println(child.Name)
}
}
return false, nil
}
// func (fs *WebFileSystem) GetChildrenHeaders(directoryID primitive.ObjectID) ([]FileHeader, error) {
// fs.ReadByObjectID(directoryID, nil)
// }

View File

@ -3,6 +3,8 @@ package webfilesystem
import (
"context"
"errors"
"path"
"personalwebsite/apps/appCtx"
"strings"
"go.mongodb.org/mongo-driver/bson"
@ -46,21 +48,31 @@ type BinaryFileData struct {
type PlainTextFileData struct {
MongoId primitive.ObjectID `bson:"_id" json:"-"`
Data string `bson:"data" json:"data"`
Data string `bson:"data" json:"-"`
}
// Deprecated
func (fs *WebFileSystem) ReadHeader(fileID primitive.ObjectID) (*FileHeader, error) {
file := &FileHeader{}
filter := primitive.M{
"_id": fileID,
}
err := fs.webfsFilesTable.FindOne(fs.ctx, filter).Decode(file)
return file, err
type ObjectLinkFileData struct {
MongoId primitive.ObjectID `bson:"_id" json:"-"`
Link_id primitive.ObjectID `bson:"link_id" json:"-"`
}
//TODO To private, get name from path and set it to file struct, force set newObjectID
type PathLinkFileData struct {
MongoId primitive.ObjectID `bson:"_id" json:"-"`
Path string `bson:"path" json:"path"`
}
type FrontEndFile struct {
Name string `json:"name"`
Type string `json:"filetype"` //TODO: Rename to Type
ParentPath string `json:"parentPath"`
}
//TODO To private, get name from path and set it to file struct; force set newObjectID
func (fs *WebFileSystem) Write(filePath string, file *FileHeader, data interface{}) (primitive.ObjectID, primitive.ObjectID, error) {
if fs.CheckFileExist(filePath) {
return primitive.NilObjectID, primitive.NilObjectID, errors.New("file exists")
}
headerId, dataId, err := fs.writeFileToMongo(file, data)
if err != nil {
return primitive.NilObjectID, primitive.NilObjectID, err
@ -168,7 +180,7 @@ func (fs *WebFileSystem) Move(sourcePath string, targetPath string) error {
if err != nil {
return err
}
//TODO: use moveByID()
if targetParentDirHeader.Type != "directory" {
return errors.New("target parent object is not a directory")
}
@ -183,7 +195,33 @@ func (fs *WebFileSystem) Move(sourcePath string, targetPath string) error {
return err
}
return nil
}
func (fs *WebFileSystem) moveByID(fileID primitive.ObjectID, oldDirID primitive.ObjectID, newDirID primitive.ObjectID, isForced bool) error {
//TODO check, if directory is child for parent-parent dir and other shit
targetDirData := DirectoryData{}
targetDirHeader, err := fs.readFSDocs(newDirID, &targetDirData)
if err != nil {
return err
}
if targetDirHeader.Type != "directory" {
return errors.New("parent directory path is bad")
}
for _, childID := range targetDirData.Children {
if childID == fileID {
return errors.New("file already in this directory")
}
}
err = fs.RemoveChildToDirectory(fileID, oldDirID)
if err != nil && !isForced {
return err
}
err = fs.AppendChildToDirectory(fileID, newDirID)
if err != nil {
return err
}
return nil
}
func (fs *WebFileSystem) Remove(filePath string) error {
@ -215,9 +253,83 @@ func (fs *WebFileSystem) Remove(filePath string) error {
if err != nil {
return err
}
if parentPath == "/orfaned" { //TODO path to struct
err := fs.removeFromMongo(fileId)
if err != nil {
return err
}
}
return nil
}
func (fs *WebFileSystem) CreateObjectLink(sourcePath string, linkPath string) error {
linkSplittedPath := fs.SplitPath(linkPath)
linkFileName := linkSplittedPath[len(linkSplittedPath)-1]
linkParentDirPath := fs.GetParentPath(linkPath)
linkParentDirPathID, err := fs.FindFile(linkParentDirPath)
if err != nil {
return err
}
sourceFileID, err := fs.FindFile(sourcePath)
if err != nil {
return err
}
newLinkHeader := FileHeader{
MongoId: primitive.NewObjectID(),
Name: linkFileName,
Type: "objectlink",
Icon: "",
Data: primitive.NewObjectID(),
}
newLinkData := ObjectLinkFileData{
MongoId: primitive.NewObjectID(),
Link_id: sourceFileID,
}
linkFileID, _, err := fs.Write(sourcePath, &newLinkHeader, newLinkData)
if err != nil {
return err
}
err = fs.AppendChildToDirectory(linkFileID, linkParentDirPathID)
if err != nil {
return err
}
return nil
}
func (fs *WebFileSystem) CreatePathLink(sourcePath string, linkPath string) (primitive.ObjectID, primitive.ObjectID, error) {
sourceFileHeader, err := fs.Read(sourcePath, nil)
if err != nil {
return primitive.NilObjectID, primitive.NilObjectID, err
}
if sourceFileHeader.Type == "pathlink" {
return primitive.NilObjectID, primitive.NilObjectID, errors.New("multiplies pathlinks not supported yet") //TODO
}
splittedPath := strings.Split(linkPath, "/")
newLinkHeader := FileHeader{
MongoId: primitive.NewObjectID(),
Name: splittedPath[len(splittedPath)-1],
Type: "pathlink",
Icon: "",
Data: primitive.NewObjectID(),
}
newLinkData := PathLinkFileData{
MongoId: primitive.NewObjectID(),
Path: sourcePath,
}
headerID, dataID, err := fs.Write(linkPath, &newLinkHeader, newLinkData)
if err != nil {
return primitive.NilObjectID, primitive.NilObjectID, err
}
return headerID, dataID, nil
}
func (fs *WebFileSystem) SplitPath(path string) []string {
resPath := []string{}
splittedPath := strings.Split(path, "/")
@ -243,3 +355,23 @@ func (fs *WebFileSystem) GetParentPath(path string) string {
}
return "/"
}
func (fs *WebFileSystem) CheckFileExist(filePath string) bool {
fileHeader, err := fs.Read(filePath, nil)
if err == nil && fileHeader != nil {
return true
}
return false
}
func (fs *WebFileSystem) RelativeToAbsolute(appCtx appCtx.AppContext, filePath string) string {
switch filePath[0] {
case '.':
return path.Join(appCtx.RunPath, filePath)
case ':':
filePath = strings.ReplaceAll(filePath, ":", "")
return path.Join(appCtx.BundlePath, filePath)
default:
return filePath
}
}