-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathapi_file.go
129 lines (114 loc) · 3.19 KB
/
api_file.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package shortpaste
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path"
"strings"
"text/template"
)
func (app *App) handleFile(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
app.handleGetFile(w, r)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
func (app *App) handleGetFiles(w http.ResponseWriter, r *http.Request) {
var files []File
app.db.Find(&files)
json.NewEncoder(w).Encode(map[string][]File{"files": files})
}
func (app *App) handleGetFile(w http.ResponseWriter, r *http.Request) {
id := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/f/"), "/")
if id == "" {
onNotFound(w, "No ID found in request")
return
}
var file File
if err := app.db.First(&file, "id = ?", id).Error; err != nil {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "Link for `%s` not found!\n", id)
return
}
filePath := path.Join(app.storagePath, "data", "files", file.ID, file.Name)
if _, ok := r.URL.Query()["download"]; ok {
w.Header().Set("Content-Disposition", "attachment; filename="+file.Name)
http.ServeFile(w, r, filePath)
file.DownloadCount += 1
app.db.Save(&file)
return
}
t, err := template.ParseFS(templateFS, "templates/file.html")
if err != nil {
onServerError(w, err, "failed to parse template")
return
}
fi, err := os.Stat(filePath)
if err != nil {
onServerError(w, err, "failed to get file size")
return
}
data := struct {
Name string
Src string
Image bool
Size string
}{
Name: file.Name,
Src: "/f/" + id + "?download",
Image: strings.HasPrefix(file.MIME, "image/"),
Size: IECFormat(fi.Size()),
}
t.Execute(w, data)
file.HitCount += 1
app.db.Save(&file)
}
func (app *App) handleCreateFile(w http.ResponseWriter, r *http.Request) {
file := File{}
file.ID = strings.TrimPrefix(r.URL.Path, "/f/")
if err := file.validate(); err != nil {
onClientError(w, err, "check the input and try again")
return
}
// Maximum upload of 10 MB files
r.ParseMultipartForm(10 << 20)
// Get handler for filename, size and headers
uploadedFile, handler, err := r.FormFile("file")
if err != nil {
onClientError(w, err, "failed to retrieve file, check if the upload completed")
return
}
defer uploadedFile.Close()
file.Name = handler.Filename
file.MIME = handler.Header["Content-Type"][0]
fmt.Printf("Uploaded File: %+v\n", handler.Filename)
fmt.Printf("File Size: %+v\n", handler.Size)
fmt.Printf("MIME Header: %+v\n", handler.Header)
filePath := path.Join(app.storagePath, "data", "files", file.ID, file.Name)
// Create folder and file
if err := os.MkdirAll(path.Dir(filePath), 0700); err != nil {
onServerError(w, err, "failed to create folder")
return
}
dst, err := os.Create(filePath)
if err != nil {
onServerError(w, err, "failed to create file handler")
return
}
defer dst.Close()
// Copy the uploaded file to the created file on the filesystem
if _, err := io.Copy(dst, uploadedFile); err != nil {
onServerError(w, err, "failed to copy contents to disk")
return
}
if err = app.db.Create(&file).Error; err != nil {
onServerError(w, err, "failed to create DB entry")
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]string{"message": "created"})
}