mirror of
				https://github.com/filebrowser/filebrowser.git
				synced 2025-11-04 11:23:02 +00:00 
			
		
		
		
	add vcs command
This commit is contained in:
		
							parent
							
								
									fff716b2b3
								
							
						
					
					
						commit
						0f18f74848
					
				@ -431,6 +431,23 @@ header form input {
 | 
			
		||||
 background-color: rgba(0, 0, 0, .1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.floating {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 1em;
 | 
			
		||||
    right: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.floating .action {
 | 
			
		||||
    background-color: #68EFAD;
 | 
			
		||||
    color: #306e50;
 | 
			
		||||
    box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#newfolder i {
 | 
			
		||||
    transform: rotate(45deg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* LISTING */
 | 
			
		||||
 | 
			
		||||
#listing {
 | 
			
		||||
 | 
			
		||||
@ -1,106 +1,95 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
 <head>
 | 
			
		||||
  <title>{{.Name}}</title>
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
 | 
			
		||||
  <link href='https://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'>
 | 
			
		||||
 | 
			
		||||
  <link rel="stylesheet" href="{{ .Config.BaseURL }}/_filemanagerinternal/css/styles.css">
 | 
			
		||||
 | 
			
		||||
  <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js"></script>
 | 
			
		||||
  <script src="{{ .Config.BaseURL }}/_filemanagerinternal/js/application.js"></script>
 | 
			
		||||
 | 
			
		||||
  {{ if ne .Config.StyleSheet "" }}
 | 
			
		||||
   <style>
 | 
			
		||||
    {{.Config.StyleSheet}}
 | 
			
		||||
   </style>
 | 
			
		||||
  {{ end }}
 | 
			
		||||
 </head>
 | 
			
		||||
 <body>
 | 
			
		||||
 | 
			
		||||
    <header>
 | 
			
		||||
        <div>
 | 
			
		||||
            {{ $lnk := .PreviousLink }}
 | 
			
		||||
            {{ if ne $lnk ""}}
 | 
			
		||||
            <a href="{{ $lnk }}">
 | 
			
		||||
                <div class="action" id="prev">
 | 
			
		||||
                    <i class="material-icons">subdirectory_arrow_left</i>
 | 
			
		||||
                </div>
 | 
			
		||||
            </a>
 | 
			
		||||
            {{ else }}
 | 
			
		||||
            <div class="action disabled" id="prev">
 | 
			
		||||
<head>
 | 
			
		||||
    <title>{{.Name}}</title>
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
 | 
			
		||||
    <link href='https://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'>
 | 
			
		||||
    <link rel="stylesheet" href="{{ .Config.BaseURL }}/_filemanagerinternal/css/styles.css">
 | 
			
		||||
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js"></script>
 | 
			
		||||
    <script src="{{ .Config.BaseURL }}/_filemanagerinternal/js/application.js"></script>
 | 
			
		||||
    {{ if ne .Config.StyleSheet "" }}<style>{{.Config.StyleSheet}}</style>{{ end }}
 | 
			
		||||
    </head>
 | 
			
		||||
<body>
 | 
			
		||||
<header>
 | 
			
		||||
    <div>
 | 
			
		||||
        {{ $lnk := .PreviousLink }}
 | 
			
		||||
        {{ if ne $lnk ""}}<a href="{{ $lnk }}">{{ end }}
 | 
			
		||||
            <div class="action{{ if eq $lnk ""}} disabled{{ end }}" id="prev">
 | 
			
		||||
                <i class="material-icons">subdirectory_arrow_left</i>
 | 
			
		||||
            </div>
 | 
			
		||||
            {{ end }}
 | 
			
		||||
            <p>
 | 
			
		||||
            <a href="{{ if eq .Config.BaseURL " " }}/{{ else }}{{ .Config.BaseURL }}{{ end }}">
 | 
			
		||||
            {{ if .Config.HugoEnabled }}Hugo{{ else }}File Manager{{ end }}
 | 
			
		||||
        {{ if ne $lnk ""}}</a>{{ end }}
 | 
			
		||||
 | 
			
		||||
        <p>
 | 
			
		||||
            <a href="{{ if eq .Config.BaseURL "" }}/{{ else }}{{ .Config.BaseURL }}{{ end }}">
 | 
			
		||||
                {{ if .Config.HugoEnabled }}Hugo{{ else }}File Manager{{ end }}
 | 
			
		||||
            </a>
 | 
			
		||||
            {{ if ne .Name "/"}}
 | 
			
		||||
            <i class="material-icons">chevron_right</i>
 | 
			
		||||
            {{ .Name }}</p>
 | 
			
		||||
            {{ end }}
 | 
			
		||||
            {{ if ne .Name "/"}}<i class="material-icons">chevron_right</i>{{ .Name }}
 | 
			
		||||
        </p>
 | 
			
		||||
        {{ end }}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div>
 | 
			
		||||
        {{ if .IsDir}}
 | 
			
		||||
        <form>
 | 
			
		||||
            <i class="material-icons">search</i>
 | 
			
		||||
            <input type="text" placeholder="Search or command">
 | 
			
		||||
        </form>
 | 
			
		||||
        <div class="action" id="view">
 | 
			
		||||
            <i class="material-icons">view_headline</i>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="action" id="upload">
 | 
			
		||||
            <i class="material-icons">file_upload</i>
 | 
			
		||||
        </div>
 | 
			
		||||
        {{ else }}
 | 
			
		||||
        {{ template "actions" . }}
 | 
			
		||||
        {{ end }}
 | 
			
		||||
 | 
			
		||||
        {{ if .Config.HugoEnabled }}
 | 
			
		||||
        <a href="{{ .Config.BaseURL }}/settings">
 | 
			
		||||
            <div class="action">
 | 
			
		||||
                <i class="material-icons">settings</i>
 | 
			
		||||
            </div>
 | 
			
		||||
        </a>
 | 
			
		||||
        {{ end }}
 | 
			
		||||
 | 
			
		||||
        <div class="action" id="logout">
 | 
			
		||||
            <i class="material-icons">exit_to_app</i>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</header>
 | 
			
		||||
 | 
			
		||||
{{ if .IsDir }}
 | 
			
		||||
<div id="toolbar">
 | 
			
		||||
    <div>
 | 
			
		||||
    {{ if .IsDir}}
 | 
			
		||||
    <form>
 | 
			
		||||
    <i class="material-icons">search</i>
 | 
			
		||||
    <input type="text" placeholder="Search">
 | 
			
		||||
    </form>
 | 
			
		||||
    <div class="action" id="view">
 | 
			
		||||
    <i class="material-icons">view_headline</i>
 | 
			
		||||
        <div class="action" id="back">
 | 
			
		||||
            <i class="material-icons">arrow_back</i>
 | 
			
		||||
        </div>
 | 
			
		||||
        <p><span id="selected-number">0</span> selected.</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="action" id="upload">
 | 
			
		||||
    <i class="material-icons">file_upload</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    {{ else }}
 | 
			
		||||
    <div>
 | 
			
		||||
    {{ template "actions" . }}
 | 
			
		||||
    {{ end }}
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{{ end }}
 | 
			
		||||
 | 
			
		||||
    {{ if .Config.HugoEnabled }}
 | 
			
		||||
    <!-- Hugo plugin stuff -->
 | 
			
		||||
    <a href="{{ .Config.BaseURL }}/settings">
 | 
			
		||||
    <div class="action">
 | 
			
		||||
    <i class="material-icons">settings</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    </a>
 | 
			
		||||
<main>
 | 
			
		||||
{{ template "content" .Data }}
 | 
			
		||||
</main>
 | 
			
		||||
 | 
			
		||||
    {{ end }}
 | 
			
		||||
    <div class="action" id="logout">
 | 
			
		||||
    <i class="material-icons">exit_to_app</i>
 | 
			
		||||
{{ if .IsDir }}
 | 
			
		||||
<div class="floating">
 | 
			
		||||
    <div class="action" id="newfolder">
 | 
			
		||||
        <i class="material-icons">close</i>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    </header>
 | 
			
		||||
</div>
 | 
			
		||||
{{ end }}
 | 
			
		||||
 | 
			
		||||
  {{ if .IsDir }}
 | 
			
		||||
   <div id="toolbar">
 | 
			
		||||
    <div>
 | 
			
		||||
     <div class="action" id="back">
 | 
			
		||||
      <i class="material-icons">arrow_back</i>
 | 
			
		||||
     </div>
 | 
			
		||||
     <p>
 | 
			
		||||
      <span id="selected-number">0</span>
 | 
			
		||||
      selected.</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
     {{ template "actions" . }}
 | 
			
		||||
    </div>
 | 
			
		||||
   </div>
 | 
			
		||||
  {{ end }}
 | 
			
		||||
 | 
			
		||||
  <main>
 | 
			
		||||
      {{ .Path }}
 | 
			
		||||
   {{ template "content" .Data }}
 | 
			
		||||
  </main>
 | 
			
		||||
  <footer>
 | 
			
		||||
   Served with
 | 
			
		||||
   <a rel="noopener noreferrer" href="https://caddyserver.com">Caddy</a>
 | 
			
		||||
   and
 | 
			
		||||
   <a rel="noopener noreferrer" href="https://github.com/hacdias/caddy-filemanager">File Manager</a>.
 | 
			
		||||
   {{ if .Config.HugoEnabled }}With a flavour of
 | 
			
		||||
    <a rel="noopener noreferrer" href="https://github.com/hacdias/caddy-filemanager">Hugo</a>.{{ end }}
 | 
			
		||||
  </footer>
 | 
			
		||||
 </body>
 | 
			
		||||
<footer>
 | 
			
		||||
Served with <a rel="noopener noreferrer" href="https://caddyserver.com">Caddy</a> and
 | 
			
		||||
<a rel="noopener noreferrer" href="https://github.com/hacdias/caddy-filemanager">File Manager</a>.
 | 
			
		||||
{{ if .Config.HugoEnabled }}With a flavour of
 | 
			
		||||
<a rel="noopener noreferrer" href="https://github.com/hacdias/caddy-filemanager">Hugo</a>.{{ end }}
 | 
			
		||||
</footer>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import (
 | 
			
		||||
	a "github.com/hacdias/caddy-filemanager/internal/assets"
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/config"
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/file"
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/vcs"
 | 
			
		||||
	"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -79,7 +80,11 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
 | 
			
		||||
				}
 | 
			
		||||
				// Search and git commands
 | 
			
		||||
				if r.Header.Get("Search") == "true" {
 | 
			
		||||
					// TODO: search and git commands
 | 
			
		||||
					// TODO: search commands
 | 
			
		||||
				}
 | 
			
		||||
				// VCS commands
 | 
			
		||||
				if r.Header.Get("Command") != "" {
 | 
			
		||||
					vcs.Handle(w, r, c)
 | 
			
		||||
				}
 | 
			
		||||
				// Creates a new folder
 | 
			
		||||
				// TODO: not implemented on frontend
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ type Config struct {
 | 
			
		||||
	Root        http.FileSystem
 | 
			
		||||
	BaseURL     string
 | 
			
		||||
	StyleSheet  string // Costum stylesheet
 | 
			
		||||
	HugoEnabled bool   // This must be only used by Hugo plugin
 | 
			
		||||
	HugoEnabled bool   // Enables the Hugo plugin for File Manager
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse parses the configuration set by the user so it can
 | 
			
		||||
 | 
			
		||||
@ -1,55 +0,0 @@
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/config"
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/page"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Handle handles the POST method on GIT page which is only an API.
 | 
			
		||||
func Handle(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
 | 
			
		||||
	// Check if git is installed on the computer
 | 
			
		||||
	if _, err := exec.LookPath("git"); err != nil {
 | 
			
		||||
		return http.StatusNotImplemented, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get the JSON information sent using a buffer
 | 
			
		||||
	buff := new(bytes.Buffer)
 | 
			
		||||
	buff.ReadFrom(r.Body)
 | 
			
		||||
 | 
			
		||||
	// Creates the raw file "map" using the JSON
 | 
			
		||||
	var info map[string]interface{}
 | 
			
		||||
	json.Unmarshal(buff.Bytes(), &info)
 | 
			
		||||
 | 
			
		||||
	// Check if command was sent
 | 
			
		||||
	if _, ok := info["command"]; !ok {
 | 
			
		||||
		return http.StatusBadRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	command := info["command"].(string)
 | 
			
		||||
	args := strings.Split(command, " ")
 | 
			
		||||
 | 
			
		||||
	if len(args) > 0 && args[0] == "git" {
 | 
			
		||||
		args = append(args[:0], args[1:]...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(args) == 0 {
 | 
			
		||||
		return http.StatusBadRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd := exec.Command("git", args...)
 | 
			
		||||
	cmd.Dir = c.PathScope
 | 
			
		||||
	output, err := cmd.CombinedOutput()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := &page.Page{Info: &page.Info{Data: string(output)}}
 | 
			
		||||
	return page.PrintAsJSON(w)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								internal/vcs/vcs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								internal/vcs/vcs.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
package vcs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/config"
 | 
			
		||||
	"github.com/hacdias/caddy-filemanager/internal/page"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Handle handles the POST method on GIT page which is only an API.
 | 
			
		||||
func Handle(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) {
 | 
			
		||||
	command := strings.Split(r.Header.Get("command"), " ")
 | 
			
		||||
 | 
			
		||||
	// Check if the command is for git, mercurial or svn
 | 
			
		||||
	if command[0] != "git" && command[0] != "hg" && command[0] != "svn" {
 | 
			
		||||
		return http.StatusForbidden, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the program is talled is installed on the computer
 | 
			
		||||
	if _, err := exec.LookPath(command[0]); err != nil {
 | 
			
		||||
		return http.StatusNotImplemented, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd := exec.Command(command[0], command[1:len(command)]...)
 | 
			
		||||
	cmd.Dir = c.PathScope
 | 
			
		||||
	output, err := cmd.CombinedOutput()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	page := &page.Page{Info: &page.Info{Data: string(output)}}
 | 
			
		||||
	return page.PrintAsJSON(w)
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user