feat: user trash dir (#8)
parent
8fe3f85d18
commit
1b79b0c166
|
@ -27,13 +27,14 @@ var usersCmd = &cobra.Command{
|
||||||
|
|
||||||
func printUsers(usrs []*users.User) {
|
func printUsers(usrs []*users.User) {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
fmt.Fprintln(w, "ID\tUsername\tScope\tTrash Dir\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||||
|
|
||||||
for _, u := range usrs {
|
for _, u := range usrs {
|
||||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||||
u.ID,
|
u.ID,
|
||||||
u.Username,
|
u.Username,
|
||||||
u.Scope,
|
u.Scope,
|
||||||
|
u.TrashDir,
|
||||||
u.Locale,
|
u.Locale,
|
||||||
u.ViewMode,
|
u.ViewMode,
|
||||||
u.SingleClick,
|
u.SingleClick,
|
||||||
|
@ -74,6 +75,7 @@ func addUserFlags(flags *pflag.FlagSet) {
|
||||||
flags.Bool("lockPassword", false, "lock password")
|
flags.Bool("lockPassword", false, "lock password")
|
||||||
flags.StringSlice("commands", nil, "a list of the commands a user can execute")
|
flags.StringSlice("commands", nil, "a list of the commands a user can execute")
|
||||||
flags.String("scope", ".", "scope for users")
|
flags.String("scope", ".", "scope for users")
|
||||||
|
flags.String("trashDir", "", "trash directory path for users")
|
||||||
flags.String("locale", "en", "locale for users")
|
flags.String("locale", "en", "locale for users")
|
||||||
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
||||||
flags.Bool("singleClick", false, "use single clicks only")
|
flags.Bool("singleClick", false, "use single clicks only")
|
||||||
|
@ -93,6 +95,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
|
||||||
switch flag.Name {
|
switch flag.Name {
|
||||||
case "scope":
|
case "scope":
|
||||||
defaults.Scope = mustGetString(flags, flag.Name)
|
defaults.Scope = mustGetString(flags, flag.Name)
|
||||||
|
case "trashDir":
|
||||||
|
defaults.TrashDir = mustGetString(flags, flag.Name)
|
||||||
case "locale":
|
case "locale":
|
||||||
defaults.Locale = mustGetString(flags, flag.Name)
|
defaults.Locale = mustGetString(flags, flag.Name)
|
||||||
case "viewMode":
|
case "viewMode":
|
||||||
|
|
|
@ -42,6 +42,7 @@ options you want to change.`,
|
||||||
|
|
||||||
defaults := settings.UserDefaults{
|
defaults := settings.UserDefaults{
|
||||||
Scope: user.Scope,
|
Scope: user.Scope,
|
||||||
|
TrashDir: user.TrashDir,
|
||||||
Locale: user.Locale,
|
Locale: user.Locale,
|
||||||
ViewMode: user.ViewMode,
|
ViewMode: user.ViewMode,
|
||||||
SingleClick: user.SingleClick,
|
SingleClick: user.SingleClick,
|
||||||
|
@ -51,6 +52,7 @@ options you want to change.`,
|
||||||
}
|
}
|
||||||
getUserDefaults(flags, &defaults, false)
|
getUserDefaults(flags, &defaults, false)
|
||||||
user.Scope = defaults.Scope
|
user.Scope = defaults.Scope
|
||||||
|
user.TrashDir = defaults.TrashDir
|
||||||
user.Locale = defaults.Locale
|
user.Locale = defaults.Locale
|
||||||
user.ViewMode = defaults.ViewMode
|
user.ViewMode = defaults.ViewMode
|
||||||
user.SingleClick = defaults.SingleClick
|
user.SingleClick = defaults.SingleClick
|
||||||
|
|
|
@ -49,8 +49,8 @@ async function resourceAction(url, method, content) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove(url) {
|
export async function remove(url, skipTrash = true) {
|
||||||
return resourceAction(url, "DELETE");
|
return resourceAction(`${url}?skip_trash=${skipTrash}`, "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function put(url, content = "") {
|
export async function put(url, content = "") {
|
||||||
|
|
|
@ -33,6 +33,18 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="trashDir != ''">
|
||||||
|
<router-link
|
||||||
|
class="action"
|
||||||
|
:to="'/files/' + trashDir"
|
||||||
|
:aria-label="$t('sidebar.trashBin')"
|
||||||
|
:title="$t('sidebar.trashBin')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
<span>{{ $t("sidebar.trashBin") }}</span>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<router-link
|
<router-link
|
||||||
class="action"
|
class="action"
|
||||||
|
@ -109,6 +121,7 @@ import {
|
||||||
version,
|
version,
|
||||||
signup,
|
signup,
|
||||||
disableExternal,
|
disableExternal,
|
||||||
|
trashDir,
|
||||||
noAuth,
|
noAuth,
|
||||||
authMethod,
|
authMethod,
|
||||||
authLogoutURL,
|
authLogoutURL,
|
||||||
|
@ -125,6 +138,7 @@ export default {
|
||||||
signup: () => signup,
|
signup: () => signup,
|
||||||
version: () => version,
|
version: () => version,
|
||||||
disableExternal: () => disableExternal,
|
disableExternal: () => disableExternal,
|
||||||
|
trashDir: () => trashDir,
|
||||||
noAuth: () => noAuth,
|
noAuth: () => noAuth,
|
||||||
authMethod: () => authMethod,
|
authMethod: () => authMethod,
|
||||||
authLogoutURL: () => authLogoutURL,
|
authLogoutURL: () => authLogoutURL,
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
<p v-else>
|
<p v-else>
|
||||||
{{ $t("prompts.deleteMessageMultiple", { count: selectedCount }) }}
|
{{ $t("prompts.deleteMessageMultiple", { count: selectedCount }) }}
|
||||||
</p>
|
</p>
|
||||||
|
<p v-if="trashBinCheckbox">
|
||||||
|
<input type="checkbox" v-model="skipTrash" />
|
||||||
|
{{ $t("prompts.skipTrashMessage") }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button
|
<button
|
||||||
|
@ -33,12 +37,36 @@
|
||||||
import { mapGetters, mapMutations, mapState } from "vuex";
|
import { mapGetters, mapMutations, mapState } from "vuex";
|
||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
import buttons from "@/utils/buttons";
|
import buttons from "@/utils/buttons";
|
||||||
|
import { trashDir } from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "delete",
|
name: "delete",
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
skipTrash: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(["isListing", "selectedCount"]),
|
...mapGetters(["isListing", "selectedCount"]),
|
||||||
...mapState(["req", "selected", "showConfirm"]),
|
...mapState(["req", "selected", "showConfirm"]),
|
||||||
|
trashBinCheckbox() {
|
||||||
|
if (trashDir === "") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.req.path.startsWith(`/${trashDir}/`)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.selectedCount == 1 &&
|
||||||
|
this.req.items[this.selected].name == trashDir
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["closeHovers"]),
|
...mapMutations(["closeHovers"]),
|
||||||
|
@ -47,7 +75,7 @@ export default {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
await api.remove(this.$route.path);
|
await api.remove(this.$route.path, this.skipTrash);
|
||||||
buttons.success("delete");
|
buttons.success("delete");
|
||||||
|
|
||||||
this.showConfirm();
|
this.showConfirm();
|
||||||
|
@ -63,7 +91,7 @@ export default {
|
||||||
|
|
||||||
let promises = [];
|
let promises = [];
|
||||||
for (let index of this.selected) {
|
for (let index of this.selected) {
|
||||||
promises.push(api.remove(this.req.items[index].url));
|
promises.push(api.remove(this.req.items[index].url, this.skipTrash));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
|
@ -138,6 +138,7 @@
|
||||||
"deleteMessageMultiple": "Are you sure you want to delete {count} file(s)?",
|
"deleteMessageMultiple": "Are you sure you want to delete {count} file(s)?",
|
||||||
"deleteMessageSingle": "Are you sure you want to delete this file/folder?",
|
"deleteMessageSingle": "Are you sure you want to delete this file/folder?",
|
||||||
"deleteMessageShare": "Are you sure you want to delete this share({path})?",
|
"deleteMessageShare": "Are you sure you want to delete this share({path})?",
|
||||||
|
"skipTrashMessage": "Skip trash bin and delete immediately",
|
||||||
"deleteTitle": "Delete files",
|
"deleteTitle": "Delete files",
|
||||||
"displayName": "Display Name:",
|
"displayName": "Display Name:",
|
||||||
"download": "Download files",
|
"download": "Download files",
|
||||||
|
@ -262,6 +263,7 @@
|
||||||
"myFiles": "My files",
|
"myFiles": "My files",
|
||||||
"newFile": "New file",
|
"newFile": "New file",
|
||||||
"newFolder": "New folder",
|
"newFolder": "New folder",
|
||||||
|
"trashBin": "Trash bin",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"signup": "Signup",
|
"signup": "Signup",
|
||||||
|
|
|
@ -7,6 +7,7 @@ const recaptchaKey = window.FileBrowser.ReCaptchaKey;
|
||||||
const signup = window.FileBrowser.Signup;
|
const signup = window.FileBrowser.Signup;
|
||||||
const version = window.FileBrowser.Version;
|
const version = window.FileBrowser.Version;
|
||||||
const logoURL = `${staticURL}/img/logo.svg`;
|
const logoURL = `${staticURL}/img/logo.svg`;
|
||||||
|
const trashDir = window.FileBrowser.TrashDir;
|
||||||
const noAuth = window.FileBrowser.NoAuth;
|
const noAuth = window.FileBrowser.NoAuth;
|
||||||
const authMethod = window.FileBrowser.AuthMethod;
|
const authMethod = window.FileBrowser.AuthMethod;
|
||||||
const authLogoutURL = window.FileBrowser.AuthLogoutURL;
|
const authLogoutURL = window.FileBrowser.AuthLogoutURL;
|
||||||
|
@ -25,6 +26,7 @@ export {
|
||||||
recaptchaKey,
|
recaptchaKey,
|
||||||
signup,
|
signup,
|
||||||
version,
|
version,
|
||||||
|
trashDir,
|
||||||
noAuth,
|
noAuth,
|
||||||
authMethod,
|
authMethod,
|
||||||
authLogoutURL,
|
authLogoutURL,
|
||||||
|
|
|
@ -95,9 +95,31 @@ func resourceDeleteHandler(fileCache FileCache) handleFunc {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.RunHook(func() error {
|
skipTrash := r.URL.Query().Get("skip_trash") == "true"
|
||||||
return d.user.Fs.RemoveAll(r.URL.Path)
|
|
||||||
}, "delete", r.URL.Path, "", d.user)
|
if d.user.TrashDir == "" || skipTrash {
|
||||||
|
err = d.RunHook(func() error {
|
||||||
|
return d.user.Fs.RemoveAll(r.URL.Path)
|
||||||
|
}, "delete", r.URL.Path, "", d.user)
|
||||||
|
} else {
|
||||||
|
src := r.URL.Path
|
||||||
|
dst := d.user.TrashDir
|
||||||
|
|
||||||
|
if !d.Check(src) || !d.Check(dst) {
|
||||||
|
return http.StatusForbidden, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
src = path.Clean("/" + src)
|
||||||
|
dst = path.Clean("/" + dst)
|
||||||
|
|
||||||
|
err = d.user.Fs.MkdirAll(dst, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return errToStatus(err), err
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = path.Join(dst, file.Name)
|
||||||
|
err = fileutils.MoveFile(d.user.Fs, src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
|
|
|
@ -33,6 +33,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
|
||||||
"Version": version.Version,
|
"Version": version.Version,
|
||||||
"StaticURL": path.Join(d.server.BaseURL, "/static"),
|
"StaticURL": path.Join(d.server.BaseURL, "/static"),
|
||||||
"Signup": d.settings.Signup,
|
"Signup": d.settings.Signup,
|
||||||
|
"TrashDir": d.settings.Defaults.TrashDir,
|
||||||
"NoAuth": d.settings.AuthMethod == auth.MethodNoAuth,
|
"NoAuth": d.settings.AuthMethod == auth.MethodNoAuth,
|
||||||
"AuthMethod": d.settings.AuthMethod,
|
"AuthMethod": d.settings.AuthMethod,
|
||||||
"AuthLogoutURL": d.settings.AuthLogoutURL,
|
"AuthLogoutURL": d.settings.AuthLogoutURL,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
// for some fields on User.
|
// for some fields on User.
|
||||||
type UserDefaults struct {
|
type UserDefaults struct {
|
||||||
Scope string `json:"scope"`
|
Scope string `json:"scope"`
|
||||||
|
TrashDir string `json:"trashDir"`
|
||||||
Locale string `json:"locale"`
|
Locale string `json:"locale"`
|
||||||
ViewMode users.ViewMode `json:"viewMode"`
|
ViewMode users.ViewMode `json:"viewMode"`
|
||||||
SingleClick bool `json:"singleClick"`
|
SingleClick bool `json:"singleClick"`
|
||||||
|
@ -21,6 +22,7 @@ type UserDefaults struct {
|
||||||
// Apply applies the default options to a user.
|
// Apply applies the default options to a user.
|
||||||
func (d *UserDefaults) Apply(u *users.User) {
|
func (d *UserDefaults) Apply(u *users.User) {
|
||||||
u.Scope = d.Scope
|
u.Scope = d.Scope
|
||||||
|
u.TrashDir = d.TrashDir
|
||||||
u.Locale = d.Locale
|
u.Locale = d.Locale
|
||||||
u.ViewMode = d.ViewMode
|
u.ViewMode = d.ViewMode
|
||||||
u.SingleClick = d.SingleClick
|
u.SingleClick = d.SingleClick
|
||||||
|
|
|
@ -25,6 +25,7 @@ type User struct {
|
||||||
Username string `storm:"unique" json:"username"`
|
Username string `storm:"unique" json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Scope string `json:"scope"`
|
Scope string `json:"scope"`
|
||||||
|
TrashDir string `json:"trashDir"`
|
||||||
Locale string `json:"locale"`
|
Locale string `json:"locale"`
|
||||||
LockPassword bool `json:"lockPassword"`
|
LockPassword bool `json:"lockPassword"`
|
||||||
ViewMode ViewMode `json:"viewMode"`
|
ViewMode ViewMode `json:"viewMode"`
|
||||||
|
|
Loading…
Reference in New Issue