188 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
package hugo
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/md5"
 | 
						|
	"encoding/hex"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/hacdias/filemanager"
 | 
						|
	"github.com/mholt/caddy"
 | 
						|
	"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
						|
	"golang.org/x/net/webdav"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	errHugoNotFound        = errors.New("It seems that tou don't have 'hugo' on your PATH")
 | 
						|
	errUnsupportedFileType = errors.New("The type of the provided file isn't supported for this action")
 | 
						|
)
 | 
						|
 | 
						|
// setup configures a new FileManager middleware instance.
 | 
						|
func setup(c *caddy.Controller) error {
 | 
						|
	configs, err := parse(c)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
 | 
						|
		return plugin{Configs: configs, Next: next}
 | 
						|
	})
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
						|
	var (
 | 
						|
		configs []*filemanager.FileManager
 | 
						|
	)
 | 
						|
 | 
						|
	for c.Next() {
 | 
						|
		// hugo [directory] [admin] {
 | 
						|
		// 		database path
 | 
						|
		// }
 | 
						|
		directory := "."
 | 
						|
		admin := "/admin"
 | 
						|
		database := ""
 | 
						|
 | 
						|
		// Get the baseURL and baseScope
 | 
						|
		args := c.RemainingArgs()
 | 
						|
 | 
						|
		if len(args) == 1 {
 | 
						|
			directory = args[0]
 | 
						|
		}
 | 
						|
 | 
						|
		if len(args) > 1 {
 | 
						|
			admin = args[1]
 | 
						|
		}
 | 
						|
 | 
						|
		for c.NextBlock() {
 | 
						|
			switch c.Val() {
 | 
						|
			case "database":
 | 
						|
				if !c.NextArg() {
 | 
						|
					return nil, c.ArgErr()
 | 
						|
				}
 | 
						|
 | 
						|
				database = c.Val()
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		caddyConf := httpserver.GetConfig(c)
 | 
						|
 | 
						|
		path := filepath.Join(caddy.AssetsPath(), "hugo")
 | 
						|
		err := os.MkdirAll(path, 0700)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		// if there is a database path and it is not absolute,
 | 
						|
		// it will be relative to ".caddy" folder.
 | 
						|
		if !filepath.IsAbs(database) && database != "" {
 | 
						|
			database = filepath.Join(path, database)
 | 
						|
		}
 | 
						|
 | 
						|
		// If there is no database path on the settings,
 | 
						|
		// store one in .caddy/hugo/{name}.db.
 | 
						|
		if database == "" {
 | 
						|
			// The name of the database is the hashed value of a string composed
 | 
						|
			// by the host, address path and the baseurl of this File Manager
 | 
						|
			// instance.
 | 
						|
			hasher := md5.New()
 | 
						|
			hasher.Write([]byte(caddyConf.Addr.Host + caddyConf.Addr.Path + admin))
 | 
						|
			sha := hex.EncodeToString(hasher.Sum(nil))
 | 
						|
			database = filepath.Join(path, sha+".db")
 | 
						|
 | 
						|
			fmt.Println("[WARNING] A database is going to be created for your Hugo instace at " + database +
 | 
						|
				". It is highly recommended that you set the 'database' option to '" + sha + ".db'\n")
 | 
						|
		}
 | 
						|
 | 
						|
		m, err := filemanager.New(database, filemanager.User{
 | 
						|
			AllowCommands: true,
 | 
						|
			AllowEdit:     true,
 | 
						|
			AllowNew:      true,
 | 
						|
			Permissions:   map[string]bool{},
 | 
						|
			Commands:      []string{"git", "svn", "hg"},
 | 
						|
			Rules: []*filemanager.Rule{{
 | 
						|
				Regex:  true,
 | 
						|
				Allow:  false,
 | 
						|
				Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
 | 
						|
			}},
 | 
						|
			CSS:        "",
 | 
						|
			FileSystem: webdav.Dir(directory),
 | 
						|
		})
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		// Initialize the default settings for Hugo.
 | 
						|
		hugo := &hugo{
 | 
						|
			Root:        directory,
 | 
						|
			Public:      filepath.Join(directory, "public"),
 | 
						|
			Args:        []string{},
 | 
						|
			CleanPublic: true,
 | 
						|
		}
 | 
						|
 | 
						|
		// Try to find the Hugo executable path.
 | 
						|
		if hugo.Exe, err = exec.LookPath("hugo"); err != nil {
 | 
						|
			return nil, errHugoNotFound
 | 
						|
		}
 | 
						|
 | 
						|
		err = m.RegisterPlugin("hugo", hugo)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		err = m.RegisterEventType("before_publish")
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		err = m.RegisterEventType("after_publish")
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		err = m.RegisterPermission("allowPublish", true)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		m.SetBaseURL(admin)
 | 
						|
		m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/"))
 | 
						|
		configs = append(configs, m)
 | 
						|
	}
 | 
						|
 | 
						|
	return configs, nil
 | 
						|
}
 | 
						|
 | 
						|
// ServeHTTP determines if the request is for this plugin, and if all prerequisites are met.
 | 
						|
func (p plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
 | 
						|
	for i := range p.Configs {
 | 
						|
		// Checks if this Path should be handled by File Manager.
 | 
						|
		if !httpserver.Path(r.URL.Path).Matches(p.Configs[i].BaseURL) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		return p.Configs[i].ServeWithErrorHTTP(w, r)
 | 
						|
	}
 | 
						|
 | 
						|
	return p.Next.ServeHTTP(w, r)
 | 
						|
}
 | 
						|
 | 
						|
func init() {
 | 
						|
	caddy.RegisterPlugin("hugo", caddy.Plugin{
 | 
						|
		ServerType: "http",
 | 
						|
		Action:     setup,
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
type plugin struct {
 | 
						|
	Next    httpserver.Handler
 | 
						|
	Configs []*filemanager.FileManager
 | 
						|
}
 |