383 lines
10 KiB
Go
383 lines
10 KiB
Go
package webfilesystem
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"path"
|
|
"personalwebsite/apps/appCtx"
|
|
"strings"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
)
|
|
|
|
type WebFileSystem struct {
|
|
webfsCollection *mongo.Collection
|
|
webfsFilesTable *mongo.Collection
|
|
webfsFilesData *mongo.Collection
|
|
ctx context.Context
|
|
}
|
|
|
|
func NewWebFileSystem(mongoClient *mongo.Client, dBName string, fsCollectionName string) *WebFileSystem {
|
|
return &WebFileSystem{
|
|
webfsCollection: mongoClient.Database(dBName).Collection(fsCollectionName), // TODO Check collection is exist
|
|
webfsFilesTable: mongoClient.Database(dBName).Collection("webfs-table"), // TODO Check collection is exist, //FIXME
|
|
webfsFilesData: mongoClient.Database(dBName).Collection("webfs-data"), // TODO Check collection is exist, //FIXME
|
|
ctx: context.Background(),
|
|
}
|
|
}
|
|
|
|
type FileHeader struct {
|
|
MongoId primitive.ObjectID `bson:"_id" json:"-"`
|
|
Name string `bson:"name" json:"name"`
|
|
Type string `bson:"type" json:"type"`
|
|
Icon string `bson:"icon" json:"icon"`
|
|
Data primitive.ObjectID `bson:"data_id" json:"-"` //TODO rename to DataId
|
|
}
|
|
|
|
func (fh *FileHeader) GetType() string {
|
|
//TODO return by extension and etc
|
|
return fh.Type
|
|
}
|
|
|
|
func (fh *FileHeader) GetExtension() string {
|
|
|
|
return strings.Split(fh.Name, ".")[len(strings.Split(fh.Name, "."))-1]
|
|
}
|
|
|
|
type BinaryFileData struct {
|
|
MongoId primitive.ObjectID `bson:"_id" json:"-"`
|
|
Bin []byte `bson:"bin" json:"-"`
|
|
}
|
|
|
|
type PlainTextFileData struct {
|
|
MongoId primitive.ObjectID `bson:"_id" json:"-"`
|
|
Data string `bson:"data" json:"-"`
|
|
}
|
|
|
|
type ObjectLinkFileData struct {
|
|
MongoId primitive.ObjectID `bson:"_id" json:"-"`
|
|
Link_id primitive.ObjectID `bson:"link_id" json:"-"`
|
|
}
|
|
|
|
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
|
|
}
|
|
parentPath := fs.GetParentPath(filePath)
|
|
parentDir, err := fs.FindFile(parentPath)
|
|
if err != nil {
|
|
return primitive.NilObjectID, primitive.NilObjectID, err
|
|
}
|
|
|
|
if parentDir.IsZero() {
|
|
return primitive.NilObjectID, primitive.NilObjectID, errors.New("parent dir not found")
|
|
}
|
|
err = fs.AppendChildToDirectory(headerId, parentDir)
|
|
if err != nil {
|
|
return primitive.NilObjectID, primitive.NilObjectID, err
|
|
}
|
|
return headerId, dataId, nil
|
|
}
|
|
|
|
func (fs *WebFileSystem) UpdateFileData(file *FileHeader, data interface{}) error {
|
|
update := bson.M{"$set": data}
|
|
// println("updating data file: " + file.MongoId.String())
|
|
res, err := fs.webfsFilesData.UpdateByID(fs.ctx, file.Data, update)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res.ModifiedCount < 1 {
|
|
return errors.New("no data updated")
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (fs *WebFileSystem) InitFS() error { //FIXME Can't set parent_id to itself
|
|
rootData := DirectoryData{
|
|
MongoId: primitive.NewObjectID(),
|
|
Parent: primitive.NewObjectID(),
|
|
Children: []primitive.ObjectID{},
|
|
}
|
|
rootHeader := FileHeader{
|
|
MongoId: primitive.NewObjectID(),
|
|
Name: "/",
|
|
Type: "directory",
|
|
Icon: "",
|
|
}
|
|
_, _, err := fs.writeFileToMongo(&rootHeader, &rootData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//TODO get on boot and safe to struct
|
|
func (fs *WebFileSystem) GetRootDir() (*FileHeader, *DirectoryData, error) {
|
|
filter := primitive.M{
|
|
"name": "/",
|
|
}
|
|
res := fs.webfsFilesTable.FindOne(fs.ctx, filter)
|
|
if res == nil {
|
|
return nil, nil, errors.New("TODO") //TODO
|
|
}
|
|
rootDir := FileHeader{}
|
|
err := res.Decode(&rootDir)
|
|
if res == nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
filterData := primitive.M{
|
|
"_id": rootDir.Data,
|
|
}
|
|
resData := fs.webfsFilesData.FindOne(fs.ctx, filterData)
|
|
if resData.Err() != nil {
|
|
return nil, nil, err
|
|
}
|
|
rootDirData := DirectoryData{}
|
|
err = resData.Decode(&rootDirData)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return &rootDir, &rootDirData, nil
|
|
}
|
|
|
|
func (fs *WebFileSystem) Move(sourcePath string, targetPath string) error {
|
|
//TODO Check about move dir to itself
|
|
//TODO if it a dir fix its parentId
|
|
//TODO Rename file if in path set new name for it
|
|
sourceFileHeader, err := fs.Read(sourcePath, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sourceParentDirPath := fs.GetParentPath(sourcePath)
|
|
sourceParentDirData := DirectoryData{}
|
|
sourceParentDirHeader, err := fs.Read(sourceParentDirPath, &sourceParentDirData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if sourceParentDirHeader.Type != "directory" {
|
|
return errors.New("source parent object is not a directory")
|
|
}
|
|
|
|
targetParentDirPath := fs.GetParentPath(targetPath)
|
|
targetParentDirData := DirectoryData{}
|
|
targetParentDirHeader, err := fs.Read(targetParentDirPath, &targetParentDirData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//TODO: use moveByID()
|
|
if targetParentDirHeader.Type != "directory" {
|
|
return errors.New("target parent object is not a directory")
|
|
}
|
|
|
|
err = fs.RemoveChildToDirectory(sourceFileHeader.MongoId, sourceParentDirHeader.MongoId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = fs.AppendChildToDirectory(sourceFileHeader.MongoId, targetParentDirHeader.MongoId)
|
|
if err != nil {
|
|
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 {
|
|
parentPath := fs.GetParentPath(filePath)
|
|
parentDirId, err := fs.FindFile(parentPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//TODO: Check, if parent file is dir
|
|
parentDirData := DirectoryData{}
|
|
parentDir, err := fs.readFSDocs(parentDirId, &parentDirData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fileId, err := fs.FindFile(filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
newChildren := []primitive.ObjectID{}
|
|
for _, childId := range parentDirData.Children {
|
|
if childId != fileId {
|
|
newChildren = append(newChildren, childId)
|
|
}
|
|
}
|
|
|
|
parentDirData.Children = newChildren
|
|
err = fs.UpdateFileData(parentDir, parentDirData)
|
|
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, "/")
|
|
splittedPath[0] = "/"
|
|
for _, split := range splittedPath {
|
|
if split != "" {
|
|
resPath = append(resPath, split)
|
|
}
|
|
}
|
|
return resPath
|
|
}
|
|
|
|
func (fs *WebFileSystem) GetExtension(filename string) string {
|
|
splittedName := strings.Split(filename, ".")
|
|
|
|
return splittedName[len(splittedName)-1]
|
|
}
|
|
|
|
func (fs *WebFileSystem) GetParentPath(path string) string {
|
|
splittedPath := fs.SplitPath(path)
|
|
if len(splittedPath) > 1 {
|
|
return "/" + strings.Join(splittedPath[1:len(splittedPath)-1], "/")
|
|
}
|
|
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
|
|
}
|
|
}
|