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