Commit a7bf420dd5ec74285bfd220c02a4a99e8bc2e7ce
1 parent
9ede5c7a90
Exists in
master
added document utility
Showing
1 changed file
with
219 additions
and
0 deletions
Show diff stats
document/document.go
... | ... | @@ -0,0 +1,219 @@ |
1 | +package document | |
2 | + | |
3 | +import ( | |
4 | + "errors" | |
5 | + "fmt" | |
6 | + "io" | |
7 | + "mime" | |
8 | + "net/http" | |
9 | + "os" | |
10 | + "strings" | |
11 | + "time" | |
12 | + | |
13 | + web "git.to-net.rs/marko.tikvic/webutility" | |
14 | +) | |
15 | + | |
16 | +// Document ... | |
17 | +type Document struct { | |
18 | + ID int64 `json:"id"` | |
19 | + FileName string `json:"fileName"` | |
20 | + Extension string `json:"extension"` | |
21 | + ContentType string `json:"contentType"` | |
22 | + Size int64 `json:"fileSize"` | |
23 | + UploadedBy string `json:"uploadedBy"` | |
24 | + LastModifiedBy string `json:"lastModifiedBy"` | |
25 | + TimeUploaded int64 `json:"timeUploaded"` | |
26 | + TimeLastModified int64 `json:"timeLastModified"` | |
27 | + RoleAccessLevel int64 `json:"accessLevel"` | |
28 | + Description string `json:"description"` | |
29 | + Download *DownloadLink `json:"download"` | |
30 | + Path string `json:"-"` | |
31 | + directory string | |
32 | + data []byte | |
33 | +} | |
34 | + | |
35 | +// OpenFileAsDocument ... | |
36 | +func OpenFileAsDocument(path string) (*Document, error) { | |
37 | + d := &Document{Path: path} | |
38 | + | |
39 | + f, err := os.Open(d.Path) | |
40 | + if err != nil { | |
41 | + return nil, err | |
42 | + } | |
43 | + defer f.Close() | |
44 | + | |
45 | + stats, err := f.Stat() | |
46 | + if err != nil { | |
47 | + return nil, err | |
48 | + } | |
49 | + | |
50 | + d.FileName = stats.Name() | |
51 | + d.Size = stats.Size() | |
52 | + d.Extension = FileExtension(d.FileName) | |
53 | + | |
54 | + d.data = make([]byte, d.Size) | |
55 | + if _, err = f.Read(d.data); err != nil { | |
56 | + return nil, err | |
57 | + } | |
58 | + | |
59 | + return d, err | |
60 | +} | |
61 | + | |
62 | +// DownloadLink ... | |
63 | +type DownloadLink struct { | |
64 | + Method string `json:"method"` | |
65 | + URL string `json:"url"` | |
66 | +} | |
67 | + | |
68 | +// SetDownloadInfo ... | |
69 | +func (d *Document) SetDownloadInfo(method, url string) { | |
70 | + d.Download = &DownloadLink{ | |
71 | + Method: method, | |
72 | + URL: url, | |
73 | + } | |
74 | +} | |
75 | + | |
76 | +// ServeDocument writes d's buffer to w and sets appropriate headers according to d's content type | |
77 | +// and downloadPrompt. | |
78 | +func ServeDocument(w http.ResponseWriter, d *Document, downloadPrompt bool) error { | |
79 | + f, err := os.Open(d.Path) | |
80 | + if err != nil { | |
81 | + return err | |
82 | + } | |
83 | + defer f.Close() | |
84 | + | |
85 | + web.SetContentType(w, mime.TypeByExtension(d.Extension)) | |
86 | + web.SetResponseStatus(w, http.StatusOK) | |
87 | + if downloadPrompt { | |
88 | + w.Header().Set("Content-Disposition", "attachment; filename="+d.FileName) | |
89 | + } | |
90 | + | |
91 | + buf := make([]byte, d.Size) | |
92 | + if _, err := f.Read(buf); err != nil { | |
93 | + return err | |
94 | + } | |
95 | + | |
96 | + w.Header().Set("Content-Length", fmt.Sprintf("%d", d.Size)) | |
97 | + web.WriteResponse(w, buf) | |
98 | + | |
99 | + return nil | |
100 | +} | |
101 | + | |
102 | +// FileExists ... | |
103 | +func FileExists(path string) bool { | |
104 | + temp, err := os.Open(path) | |
105 | + defer temp.Close() | |
106 | + | |
107 | + if err != nil { | |
108 | + return false | |
109 | + } | |
110 | + | |
111 | + return true | |
112 | +} | |
113 | + | |
114 | +// ParseDocument ... | |
115 | +func ParseDocument(req *http.Request) (doc *Document, err error) { | |
116 | + req.ParseMultipartForm(32 << 20) | |
117 | + file, fheader, err := req.FormFile("document") | |
118 | + if err != nil { | |
119 | + return doc, err | |
120 | + } | |
121 | + | |
122 | + claims, _ := web.GetTokenClaims(req) | |
123 | + owner := claims.Username | |
124 | + | |
125 | + fname := fheader.Filename | |
126 | + | |
127 | + fsize := fheader.Size | |
128 | + ftype := fmt.Sprintf("%v", fheader.Header["Content-Type"][0]) | |
129 | + | |
130 | + fextn := FileExtension(fname) | |
131 | + if fextn == "" { | |
132 | + return doc, errors.New("invalid extension") | |
133 | + } | |
134 | + | |
135 | + doc = new(Document) | |
136 | + | |
137 | + doc.FileName = fname | |
138 | + doc.Size = fsize | |
139 | + doc.ContentType = ftype | |
140 | + doc.Extension = "." + fextn | |
141 | + | |
142 | + t := time.Now().Unix() | |
143 | + doc.TimeUploaded = t | |
144 | + doc.TimeLastModified = t | |
145 | + | |
146 | + doc.UploadedBy = owner | |
147 | + doc.LastModifiedBy = owner | |
148 | + doc.RoleAccessLevel = 0 | |
149 | + | |
150 | + doc.data = make([]byte, doc.Size) | |
151 | + if _, err = io.ReadFull(file, doc.data); err != nil { | |
152 | + return doc, err | |
153 | + } | |
154 | + | |
155 | + return doc, nil | |
156 | +} | |
157 | + | |
158 | +// DirectoryFromPath ... | |
159 | +func DirectoryFromPath(path string) (dir string) { | |
160 | + parts := strings.Split(path, "/") | |
161 | + if len(parts) == 1 { | |
162 | + return "" | |
163 | + } | |
164 | + | |
165 | + dir = parts[0] | |
166 | + for _, p := range parts[1 : len(parts)-1] { | |
167 | + dir += "/" + p | |
168 | + } | |
169 | + | |
170 | + return dir | |
171 | +} | |
172 | + | |
173 | +// SaveToFile ... | |
174 | +func (d *Document) SaveToFile(path string) (f *os.File, err error) { | |
175 | + d.Path = path | |
176 | + | |
177 | + if FileExists(path) { | |
178 | + err = fmt.Errorf("file %s alredy exists", path) | |
179 | + return nil, err | |
180 | + } | |
181 | + | |
182 | + if parentDir := DirectoryFromPath(path); parentDir != "" { | |
183 | + if err = os.MkdirAll(parentDir, os.ModePerm); err != nil { | |
184 | + if !os.IsExist(err) { | |
185 | + return nil, err | |
186 | + } | |
187 | + } | |
188 | + } | |
189 | + | |
190 | + if f, err = os.Create(path); err != nil { | |
191 | + return nil, err | |
192 | + } | |
193 | + | |
194 | + if _, err = f.Write(d.data); err != nil { | |
195 | + f.Close() | |
196 | + d.DeleteFile() | |
197 | + return nil, err | |
198 | + } | |
199 | + f.Close() | |
200 | + | |
201 | + return f, nil | |
202 | +} | |
203 | + | |
204 | +func DeleteFile(path string) error { | |
205 | + return os.Remove(path) | |
206 | +} | |
207 | + | |
208 | +// DeleteFile ... | |
209 | +func (d *Document) DeleteFile() error { | |
210 | + return os.Remove(d.Path) | |
211 | +} | |
212 | + | |
213 | +func FileExtension(path string) string { | |
214 | + parts := strings.Split(path, ".") // because name can contain dots | |
215 | + if len(parts) < 2 { | |
216 | + return "" | |
217 | + } | |
218 | + return "." + parts[len(parts)-1] | |
219 | +} | ... | ... |