Compare commits

..

7 Commits

Author SHA1 Message Date
Henrique Dias
1527ca0c50 Build assets Fri Aug 4 16:38:35 GMTST 2017
Former-commit-id: 68b8596be01fba8888cbe2986f045a74974b7358 [formerly a9b16a017049aef7cc57a838de93e65bef0b98e2] [formerly ec326398476caa44b89d7afa087612888cde4181 [formerly 26d9fd98ff]]
Former-commit-id: 7abe14b5648fd8a6cbee3fdd5700433cfdde15a4 [formerly 20fe929de14f28e21bf9309c032d3f0758d8ab27]
Former-commit-id: 1640635ad843b9d1e180b6705a697b205562b209
2017-08-04 16:38:35 +01:00
Henrique Dias
0dee98b40a Add aria label; close #131
Former-commit-id: 8fc595933b73d635bbe20e018958343d9dd3e31b [formerly c056d2fa20bec942e89710ff469e12cb07a498a9] [formerly a455096212ba0cb70102a99c714d8ff3e1401f17 [formerly 1861645b04]]
Former-commit-id: 794d333ef3a2788c5e76f7c1a558af8be1137c20 [formerly ab8ca7057862e8919a7d01c3d71ecd70ba7b32f3]
Former-commit-id: 3430567351ec7425e167c4c128bb7316ff631eac
2017-08-04 16:36:27 +01:00
Henrique Dias
412ac9c9d6 Search results slightly prettier
Former-commit-id: 518b86ee61c4816e346824e36ca2b8afc5a887ae [formerly d0e4ab7a725aa0dcf35acc0965e685563d33590e] [formerly 3eeb7807675ab03f3eb3ba9a2fb0f612c1ae742d [formerly 522d50333f]]
Former-commit-id: 311dbbb9e90be32928fdca3087bae73e574610fd [formerly fbf64faddb2a189f675b4652cd170418bbbf48f7]
Former-commit-id: 834138c56639871c32ad7f393440aee6a7281a9a
2017-08-04 16:15:07 +01:00
Henrique Dias
9c2609995a close #186
Former-commit-id: 14c5044db7c81c03f27c4dbf0e7c9ba3a89cb03a [formerly 7d0fe81767e4b33c64ae7da7dd684ca8f30539c4] [formerly 815bd3a5d9770e79527de56e8d6b5d79f34cb291 [formerly 1234ee32e4]]
Former-commit-id: 2330876399f0e325dc554a08de2513b385e39a7a [formerly 638d4627e6418da2d4ebba046735bd39e8e63ae2]
Former-commit-id: d1569f07397e7f31c164080326a3a91724999778
2017-08-04 14:10:23 +01:00
Henrique Dias
68cb4ee980 Update version output
Former-commit-id: 0d8bbcef2b4cdb93fc7c4929b875eb920fc01a64 [formerly 8bf71ac7db4a94d47346bbe382b135f60bc00788] [formerly 1426e8119be5d07f0d2a759f30784a223d76208d [formerly b7887ed162]]
Former-commit-id: 3e0d9dff358868119c6d3b109896259b84a1e565 [formerly e15610b544cb000a0ce88392bd13949a578fd605]
Former-commit-id: 6497b3d602ac78be939abc70d6c337799e9d85d8
2017-08-04 13:35:21 +01:00
Henrique Dias
adc82dd85e Delete README.md
Former-commit-id: c32b7a3c7967a342832c19687420fc53176bdf46 [formerly b0dcce97677ad53314f0318819bca23646fcf770] [formerly 2f642c119a8148aa6b77e08efd0fd1b7e6d3b1a0 [formerly 004f6ef0a2]]
Former-commit-id: 07190b22fb025336b9a7cbc3cdba0f0eac32d301 [formerly b9deeb3285c5ddc978900766677a76d3b2294be5]
Former-commit-id: 97d26cdbe84585dbf3f008d7faa058579f31336f
2017-08-02 15:24:02 +01:00
Henrique Dias
4f3375ee8d NoAuth for Caddy plugins
Former-commit-id: 5b8306eb527c9f21d14736c97e67b8689e69d025 [formerly 42d1b7035277e06aecc9a812ea4d92022a36c2a6] [formerly 31905bebcc8f337bc8f6815425778bfc652f43e4 [formerly b5961b6b63]]
Former-commit-id: 44aa1bc7df6ffa633b333b75a5045c612db44aae [formerly d22761bb6f49156f7889e28f3af8edb439c7e023]
Former-commit-id: 5a8a899a97bb7ec4c9433723c7d53f87163cccac
2017-08-02 14:49:15 +01:00
25 changed files with 154 additions and 103 deletions

View File

@@ -7,7 +7,8 @@ RUN apk add --no-cache git
RUN go get ./...
WORKDIR /go/src/github.com/hacdias/filemanager/cmd/filemanager
RUN go install
RUN go build -ldflags "-X main.version=$(git tag -l --points-at HEAD)"
RUN mv filemanager /go/bin/filemanager
FROM alpine:latest
COPY --from=0 /go/bin/filemanager /usr/local/bin/filemanager

View File

@@ -20,7 +20,11 @@
<span v-if="search.length === 0 && commands.length === 0">{{ text }}</span>
<ul v-else-if="search.length > 0">
<li v-for="s in search">
<router-link @click.native="close" :to="'./' + s">./{{ s }}</router-link>
<router-link @click.native="close" :to="'./' + s.path">
<i v-if="s.dir" class="material-icons">folder</i>
<i v-else class="material-icons">insert_drive_file</i>
<span>./{{ s.path }}</span>
</router-link>
</li>
</ul>
@@ -184,10 +188,12 @@ export default {
// In case of being a search.
api.search(path, this.value,
(event) => {
let url = event.data
if (url[0] === '/') url = url.substring(1)
let response = JSON.parse(event.data)
if (response.path[0] === '/') {
response.path = response.path.substring(1)
}
this.search.push(url)
this.search.push(response)
this.scrollable.scrollTop = this.scrollable.scrollHeight
},
(event) => {

View File

@@ -15,16 +15,31 @@
<div class="item header">
<div></div>
<div>
<p :class="{ active: nameSorted }" class="name" @click="sort('name')">
<p :class="{ active: nameSorted }" class="name"
role="button"
tabindex="0"
@click="sort('name')"
:title="$t('files.sortByName')"
:aria-label="$t('files.sortByName')">
<span>{{ $t('files.name') }}</span>
<i class="material-icons">{{ nameIcon }}</i>
</p>
<p :class="{ active: sizeSorted }" class="size" @click="sort('size')">
<p :class="{ active: sizeSorted }" class="size"
role="button"
tabindex="0"
@click="sort('size')"
:title="$t('files.sortBySize')"
:aria-label="$t('files.sortBySize')">
<span>{{ $t('files.size') }}</span>
<i class="material-icons">{{ sizeIcon }}</i>
</p>
<p :class="{ active: modifiedSorted }" class="modified" @click="sort('modified')">
<p :class="{ active: modifiedSorted }" class="modified"
role="button"
tabindex="0"
@click="sort('modified')"
:title="$t('files.sortByLastModified')"
:aria-label="$t('files.sortByLastModified')">
<span>{{ $t('files.lastModified') }}</span>
<i class="material-icons">{{ modifiedIcon }}</i>
</p>

View File

@@ -1,5 +1,7 @@
<template>
<div class="item"
role="button"
tabindex="0"
draggable="true"
@dragstart="dragStart"
@dragover="dragOver"
@@ -7,6 +9,7 @@
@click="click"
@dblclick="open"
@touchstart="touchstart"
:aria-label="name"
:aria-selected="isSelected">
<div>
<i class="material-icons">{{ icon }}</i>

View File

@@ -6,7 +6,10 @@
<file-list @update:selected="val => dest = val"></file-list>
<div>
<button class="ok" @click="copy">{{ $t('buttons.copy') }}</button>
<button class="ok"
@click="copy"
:aria-label="$t('buttons.copy')"
:title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -4,7 +4,9 @@
<p v-show="req.kind !== 'listing'">{{ $t('prompts.deleteMessageSingle') }}</p>
<p v-show="req.kind === 'listing'">{{ $t('prompts.deleteMessageMultiple', { count: selectedCount}) }}</p>
<div>
<button @click="submit" autofocus>{{ $t('buttons.delete') }}</button>
<button @click="submit"
:aria-label="$t('buttons.delete')"
:title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -4,8 +4,14 @@
<h3>{{ $t('prompts.error') }}</h3>
<pre>{{ $store.state.showMessage }}</pre>
<div>
<button @click="close" autofocus>{{ $t('buttons.close') }}</button>
<button @click="reportIssue" class="cancel">{{ $t('buttons.reportIssue') }}</button>
<button @click="close"
autofocus
:aria-label="$t('buttons.close')"
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
<button @click="reportIssue"
class="cancel"
:aria-label="$t('buttons.reportIssue')"
:title="$t('buttons.reportIssue')">{{ $t('buttons.reportIssue') }}</button>
</div>
</div>
</template>

View File

@@ -4,6 +4,9 @@
<li @click="select"
@touchstart="touchstart"
@dblclick="next"
role="button"
tabindex="0"
:aria-label="item.name"
:aria-selected="selected == item.url"
:key="item.name" v-for="item in items"
:data-url="item.url">{{ item.name }}</li>

View File

@@ -15,7 +15,11 @@
</ul>
<div>
<button type="submit" @click="$store.commit('closeHovers')" class="ok">{{ $t('buttons.ok') }}</button>
<button type="submit"
@click="$store.commit('closeHovers')"
class="ok"
:aria-label="$t('buttons.ok')"
:title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
</div>
</div>
</template>

View File

@@ -21,7 +21,11 @@
</section>
<div>
<button type="submit" @click="$store.commit('closeHovers')" class="ok">{{ $t('buttons.ok') }}</button>
<button type="submit"
@click="$store.commit('closeHovers')"
class="ok"
:aria-label="$t('buttons.ok')"
:title="$t('buttons.ok')">{{ $t('buttons.ok') }}</button>
</div>
</div>
</template>

View File

@@ -6,7 +6,10 @@
<file-list @update:selected="val => dest = val"></file-list>
<div>
<button class="ok" @click="move">{{ $t('buttons.move') }}</button>
<button class="ok"
@click="move"
:aria-label="$t('buttons.move')"
:title="$t('buttons.move')">{{ $t('buttons.move') }}</button>
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -4,7 +4,10 @@
<p>{{ $t('prompts.newDirMessage') }}</p>
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
<div>
<button class="ok" @click="submit">{{ $t('buttons.create') }}</button>
<button class="ok"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')"
@click="submit">{{ $t('buttons.create') }}</button>
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -4,7 +4,10 @@
<p>{{ $t('prompts.newFileMessage') }}</p>
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
<div>
<button class="ok" @click="submit">{{ $t('buttons.create') }}</button>
<button class="ok"
@click="submit"
:aria-label="$t('buttons.create')"
:title="$t('buttons.create')">{{ $t('buttons.create') }}</button>
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -26,7 +26,10 @@
:name="input.name"
:placeholder="input.placeholder">
<div>
<input type="submit" class="ok" :value="prompt.ok">
<input type="submit" class="ok"
:aria-label="prompt.ok"
:title="prompt.ok"
:value="prompt.ok">
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -5,7 +5,10 @@
<input autofocus type="text" @keyup.enter="submit" v-model.trim="name">
<div>
<button @click="submit" type="submit">{{ $t('buttons.rename') }}</button>
<button @click="submit"
type="submit"
:aria-label="$t('buttons.rename')"
:title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
<button class="cancel"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"

View File

@@ -3,7 +3,10 @@
<i class="material-icons">done</i>
<h3>{{ $store.state.showMessage }}</h3>
<div>
<button @click="close" autofocus>{{ $t('buttons.ok') }}</button>
<button @click="close"
:aria-label="$t('buttons.ok')"
:title="$t('buttons.ok')"
autofocus>{{ $t('buttons.ok') }}</button>
</div>
</div>
</template>

View File

@@ -177,11 +177,24 @@ header .search-button {
#search.active #result i {
color: #ccc;
}
#search.active #result > p > i {
text-align: center;
margin: 0 auto;
display: table;
}
#search.active #result ul li a {
display: flex;
align-items: center;
padding: .3em 0;
}
#search.active #result ul li a i {
margin-right: .3em;
}
#search::-webkit-input-placeholder {
color: rgba(255, 255, 255, .5);
}

View File

@@ -42,6 +42,9 @@ files:
multipleSelectionEnabled: Multiple selection enabled
name: Name
size: Size
sortByName: Sort by name
sortBySize: Sort by size
sortByLastModified: Sort by last modified
help:
click: select file or directory
ctrl:

View File

@@ -42,6 +42,9 @@ files:
multipleSelectionEnabled: Seleção múltipla ativada
name: Nome
size: Tamanho
sortByName: Ordenar pelo nome
sortBySize: Ordenar pelo tamanho
sortByLastModified: Ordenar pela última modificação
help:
click: selecionar pasta ou ficheiro
ctrl:

View File

@@ -10,6 +10,7 @@ import (
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
. "github.com/hacdias/filemanager"
@@ -73,6 +74,7 @@ func parse(c *caddy.Controller) ([]*config, error) {
baseURL := "/"
baseScope := "."
database := ""
noAuth := false
// Get the baseURL and baseScope
args := c.RemainingArgs()
@@ -93,6 +95,17 @@ func parse(c *caddy.Controller) ([]*config, error) {
}
database = c.Val()
case "no_auth":
if !c.NextArg() {
noAuth = true
continue
}
var err error
noAuth, err = strconv.ParseBool(c.Val())
if err != nil {
return nil, err
}
}
}
@@ -143,6 +156,7 @@ func parse(c *caddy.Controller) ([]*config, error) {
return nil, err
}
fm.NoAuth = noAuth
m := &config{FileManager: fm}
m.SetBaseURL(baseURL)
m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/"))

View File

@@ -1,79 +0,0 @@
# hugo - a caddy plugin
[![community](https://img.shields.io/badge/community-forum-ff69b4.svg?style=flat-square)](https://caddy.community)
hugo fills the gap between Hugo and the browser. [Hugo][6] is an easy and fast static website generator. This plugin fills the gap between Hugo and the end-user, providing you a web interface to manage the whole website.
Using this plugin, you won't need to have your own computer to edit posts, neither regenerate your static website, because you can do all of that just through your browser. It is an implementation of [hacdias/filemanager][1] library.
**Requirements:** you need to have the hugo executable in your PATH. You can download it from its [official page][6].
## Get Started
To start using this plugin you just need to go to the [download Caddy page][3] and choose `http.hugo` in the directives section. For further information on how Caddy works refer to [its documentation][4].
The default credentials are `admin` for both the user and the password. It is highy recommended to change them after logging in for the first time and to use HTTPS. You can create more users and define their own permissions using the web interface.
## Syntax
```
hugo [directory] [admin] {
database path
}
```
+ `directory` is the path, relative or absolute to the directory of your Hugo files. Defaults to `./`.
+ `admin` is the URL path where you will access the admin interface. Defaults to `/admin`.
+ `path` is the database path where the settings will be stored. By default, the settings will be stored on [`.caddy`][5] folder.
## Database
By default the database will be stored on [`.caddy`][5] directory, in a sub-directory called `hugo`. Each file name is an hash of the combination of the host and the base URL.
If you don't set a database path, you will receive a warning like this:
> [WARNING] A database is going to be created for your File Manager instace at ~/.caddy/hugo/xxx.db. It is highly recommended that you set the 'database' option to 'xxx.db'
Why? If you don't set a database path and you change the host or the base URL, your settings will be reseted. So it is *highly* recommended to set this option.
When you set a relative path, such as `xxxxxxxxxx.db`, it will always be relative to `.caddy/hugo` directory. Although, you may also use an absolute path if you wish to store the database in other place.
## Examples
Manage the current working directory's Hugo website at `/admin` and display the ```public``` folder to the user.
```
root public
hugo {
database myinstance.db
}
```
Manage the Hugo website located at `/var/www/mysite` at `/admin` and display the ```public``` folder to the user.
```
root /var/www/mysite/public
hugo /var/www/mysite {
database myinstance.db
}
```
Manage the Hugo website located at `/var/www/mysite` at `/private` and display the ```public``` folder to the user.
```
root /var/www/mysite/public
hugo /var/www/mysite /private {
database myinstance.db
}
```
## Known Issues
If you are having troubles **handling large files** you might need to check out the [`timeouts`][2] plugin, which can be used to change the default HTTP Timeouts.
[1]:https://github.com/hacdias/filemanager
[2]:https://caddyserver.com/docs/timeouts
[3]:https://caddyserver.com/download
[4]:https://caddyserver.com/docs
[5]:https://caddyserver.com/docs/automatic-https#dot-caddy
[6]:http://gohugo.io

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/hacdias/filemanager"
@@ -42,6 +43,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
directory := "."
admin := "/admin"
database := ""
noAuth := false
// Get the baseURL and baseScope
args := c.RemainingArgs()
@@ -62,6 +64,17 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
}
database = c.Val()
case "no_auth":
if !c.NextArg() {
noAuth = true
continue
}
var err error
noAuth, err = strconv.ParseBool(c.Val())
if err != nil {
return nil, err
}
}
}
@@ -132,6 +145,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
return nil, err
}
m.NoAuth = noAuth
m.SetBaseURL(admin)
m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/"))
configs = append(configs, m)

View File

@@ -86,13 +86,25 @@ func setupViper() {
viper.AddConfigPath(".")
}
func printVersion() {
version = strings.TrimSpace(version)
if version == "" {
fmt.Println("filemanager is at an untracked version")
} else {
version = strings.TrimPrefix(version, "v")
fmt.Println("filemanager version", version)
}
os.Exit(0)
}
func main() {
setupViper()
flag.Parse()
if showVer {
fmt.Println("filemanager version", version)
os.Exit(0)
printVersion()
}
// Add a configuration file if set.

View File

@@ -1 +1 @@
7327806da8feadd5f82e2286efb2e2dd44109d3e
2678061f4a5fd54d606c3bbaa3aa899a5e55cf37

View File

@@ -2,6 +2,7 @@ package filemanager
import (
"bytes"
"encoding/json"
"mime"
"net/http"
"os"
@@ -321,7 +322,12 @@ func search(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, err
}
}
return conn.WriteMessage(websocket.TextMessage, []byte(path))
response, _ := json.Marshal(map[string]interface{}{
"dir": f.IsDir(),
"path": path,
})
return conn.WriteMessage(websocket.TextMessage, response)
})
if err != nil {