apps/blobs/handlers_actions.go 4.6 K raw
1
package main
2
3
import (
4
	"bytes"
5
	"mime"
6
	"net/http"
7
	"net/url"
8
	"path"
9
	"strings"
10
11
	"github.com/stevedylandev/andromeda/pkg/web"
12
)
13
14
func (a *App) upload(w http.ResponseWriter, r *http.Request) {
15
	bucket := r.PathValue("bucket")
16
	r.Body = http.MaxBytesReader(w, r.Body, a.MaxUploadBytes+1<<20)
17
	if err := r.ParseMultipartForm(a.MaxUploadBytes); err != nil {
18
		web.RedirectWithError(w, r, browseHref(bucket, ""), "Upload too large or malformed")
19
		return
20
	}
21
	prefix := strings.TrimSpace(r.FormValue("prefix"))
22
	if prefix != "" && !strings.HasSuffix(prefix, "/") {
23
		prefix += "/"
24
	}
25
	target := browseHref(bucket, prefix)
26
27
	files := r.MultipartForm.File["file"]
28
	if len(files) == 0 {
29
		web.RedirectWithError(w, r, target, "No file provided")
30
		return
31
	}
32
	for _, header := range files {
33
		if header.Size > a.MaxUploadBytes {
34
			web.RedirectWithError(w, r, target, "File exceeds upload limit")
35
			return
36
		}
37
		f, err := header.Open()
38
		if err != nil {
39
			web.RedirectWithError(w, r, target, "Failed to read upload")
40
			return
41
		}
42
		name := path.Base(header.Filename)
43
		if name == "" || name == "." || name == "/" {
44
			f.Close()
45
			web.RedirectWithError(w, r, target, "Invalid filename")
46
			return
47
		}
48
		ct := header.Header.Get("Content-Type")
49
		if ct == "" {
50
			ct = mime.TypeByExtension(path.Ext(name))
51
		}
52
		if ct == "" {
53
			ct = "application/octet-stream"
54
		}
55
		if err := a.S3.Put(r.Context(), bucket, prefix+name, ct, f, header.Size); err != nil {
56
			f.Close()
57
			a.Log.Error("put", "bucket", bucket, "key", prefix+name, "err", err)
58
			web.RedirectWithError(w, r, target, "Upload failed: "+err.Error())
59
			return
60
		}
61
		f.Close()
62
	}
63
	web.RedirectWithSuccess(w, r, target, "Uploaded")
64
}
65
66
func (a *App) replace(w http.ResponseWriter, r *http.Request) {
67
	bucket := r.PathValue("bucket")
68
	r.Body = http.MaxBytesReader(w, r.Body, a.MaxUploadBytes+1<<20)
69
	if err := r.ParseMultipartForm(a.MaxUploadBytes); err != nil {
70
		web.RedirectWithError(w, r, browseHref(bucket, ""), "Upload too large or malformed")
71
		return
72
	}
73
	key := strings.TrimSpace(r.FormValue("key"))
74
	if key == "" {
75
		http.Error(w, "key required", http.StatusBadRequest)
76
		return
77
	}
78
	target := "/b/" + url.PathEscape(bucket) + "/object/" + escapeKeyPath(key)
79
	f, header, err := r.FormFile("file")
80
	if err != nil {
81
		web.RedirectWithError(w, r, target, "No file provided")
82
		return
83
	}
84
	defer f.Close()
85
	if header.Size > a.MaxUploadBytes {
86
		web.RedirectWithError(w, r, target, "File exceeds upload limit")
87
		return
88
	}
89
	ct := header.Header.Get("Content-Type")
90
	if ct == "" {
91
		ct = mime.TypeByExtension(path.Ext(key))
92
	}
93
	if ct == "" {
94
		ct = "application/octet-stream"
95
	}
96
	if err := a.S3.Put(r.Context(), bucket, key, ct, f, header.Size); err != nil {
97
		a.Log.Error("put replace", "bucket", bucket, "key", key, "err", err)
98
		web.RedirectWithError(w, r, target, "Replace failed: "+err.Error())
99
		return
100
	}
101
	web.RedirectWithSuccess(w, r, target, "Replaced")
102
}
103
104
func (a *App) deleteObject(w http.ResponseWriter, r *http.Request) {
105
	bucket := r.PathValue("bucket")
106
	if err := r.ParseForm(); err != nil {
107
		http.Error(w, "bad request", http.StatusBadRequest)
108
		return
109
	}
110
	key := strings.TrimSpace(r.FormValue("key"))
111
	if key == "" {
112
		http.Error(w, "key required", http.StatusBadRequest)
113
		return
114
	}
115
	returnTo := strings.TrimSpace(r.FormValue("returnTo"))
116
	if returnTo == "" {
117
		returnTo = browseHref(bucket, parentOfKey(strings.TrimSuffix(key, "/")))
118
	}
119
	if err := a.S3.Delete(r.Context(), bucket, key); err != nil {
120
		a.Log.Error("delete", "bucket", bucket, "key", key, "err", err)
121
		web.RedirectWithError(w, r, returnTo, "Delete failed: "+err.Error())
122
		return
123
	}
124
	web.RedirectWithSuccess(w, r, returnTo, "Deleted")
125
}
126
127
func (a *App) mkdir(w http.ResponseWriter, r *http.Request) {
128
	bucket := r.PathValue("bucket")
129
	if err := r.ParseForm(); err != nil {
130
		http.Error(w, "bad request", http.StatusBadRequest)
131
		return
132
	}
133
	prefix := strings.TrimSpace(r.FormValue("prefix"))
134
	if prefix != "" && !strings.HasSuffix(prefix, "/") {
135
		prefix += "/"
136
	}
137
	name := strings.TrimSpace(r.FormValue("name"))
138
	name = strings.Trim(name, "/")
139
	if name == "" || strings.HasPrefix(name, ".") || strings.Contains(name, "/") {
140
		web.RedirectWithError(w, r, browseHref(bucket, prefix), "Invalid folder name")
141
		return
142
	}
143
	newPrefix := prefix + name + "/"
144
	if err := a.S3.Put(r.Context(), bucket, newPrefix, "application/x-directory", bytes.NewReader(nil), 0); err != nil {
145
		a.Log.Error("mkdir", "bucket", bucket, "key", newPrefix, "err", err)
146
		web.RedirectWithError(w, r, browseHref(bucket, prefix), "Create folder failed: "+err.Error())
147
		return
148
	}
149
	web.RedirectWithSuccess(w, r, browseHref(bucket, newPrefix), "Folder created")
150
}