Compare View
Commits (2)
Showing
2 changed files
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 | +} | ... | ... |
pdfhelper/pdf.go
... | ... | @@ -29,6 +29,17 @@ const ( |
29 | 29 | latinEncoding = "cp1250" |
30 | 30 | ) |
31 | 31 | |
32 | +const threeDots = "\u2056\u2056\u2056" | |
33 | + | |
34 | +type TableCell struct { | |
35 | + W, H float64 | |
36 | + Text string | |
37 | + Font, FontStyle string | |
38 | + FontSize float64 | |
39 | + Border string | |
40 | + Alignment string | |
41 | +} | |
42 | + | |
32 | 43 | // Helper ... |
33 | 44 | type Helper struct { |
34 | 45 | *gofpdf.Fpdf |
... | ... | @@ -50,106 +61,31 @@ func (pdf *Helper) LoadTranslators() { |
50 | 61 | pdf.translators[cyrillicEncoding] = pdf.UnicodeTranslatorFromDescriptor(cyrillicEncoding) |
51 | 62 | } |
52 | 63 | |
53 | -// InsertTab ... | |
54 | -func (pdf *Helper) InsertTab(count int, w, h float64) { | |
55 | - for i := 0; i < count; i++ { | |
56 | - pdf.Cell(w, h, "") | |
57 | - } | |
58 | -} | |
59 | - | |
60 | -// CellWithBox ... | |
61 | -func (pdf *Helper) CellWithBox(w, h float64, text, align string) { | |
62 | - //pdf.drawCellMargins(w, h) | |
63 | - //pdf.Cell(w, h, text) | |
64 | - pdf.CellFormat(w, h, pdf.ToUTF8(text), FULL, CONTINUE, align, false, 0, "") | |
65 | -} | |
66 | - | |
67 | -func (pdf *Helper) CellWithMargins(w, h float64, text, align string, index, of int) { | |
68 | - len := of - 1 | |
69 | - border := "" | |
70 | - | |
71 | - // if top cell | |
72 | - if index == 0 { | |
73 | - border += "T" | |
74 | - } | |
75 | - | |
76 | - border += "LR" // always draw these | |
77 | - | |
78 | - // if bottom cell | |
79 | - if index == len { | |
80 | - border += "B" | |
81 | - } | |
82 | - | |
83 | - pdf.CellFormat(w, h, pdf.ToUTF8(text), border, CONTINUE, align, false, 0, "") | |
84 | -} | |
85 | - | |
86 | -// MultiRowCellWithBox ... | |
87 | -func (pdf *Helper) MultiRowCellWithBox(w, h float64, text []string, align string) { | |
88 | - pdf.drawCellMargins(w, h*float64(len(text))) | |
89 | - for i := range text { | |
90 | - pdf.CellFormat(w, h, pdf.ToUTF8(text[i]), "", BELLOW, align, false, 0, "") | |
91 | - } | |
92 | -} | |
93 | - | |
94 | -// CellFormat(w, h, text, borders, newLine, fill) | |
95 | - | |
96 | -type FormatedCell struct { | |
97 | - W, H float64 | |
98 | - Text string | |
99 | - Font, FontStyle string | |
100 | - FontSize float64 | |
101 | - Border string | |
102 | - Alignment string | |
103 | -} | |
104 | - | |
105 | -func (pdf *Helper) FCell(x, y float64, c FormatedCell) { | |
64 | +func (pdf *Helper) DrawCell(x, y float64, c TableCell) { | |
106 | 65 | pdf.SetXY(x, y) |
107 | 66 | pdf.SetFont(c.Font, c.FontStyle, c.FontSize) |
108 | - pdf.CellFormat(c.W, c.H, pdf.ToUTF8(c.Text), c.Border, BELLOW, c.Alignment, false, 0, "") | |
67 | + pdf.CellFormat(c.W, c.H, pdf.toUTF8(c.Text), c.Border, BELLOW, c.Alignment, false, 0, "") | |
109 | 68 | } |
110 | 69 | |
111 | -func (pdf *Helper) Column(x, y float64, cells []FormatedCell) { | |
70 | +func (pdf *Helper) DrawColumn(x, y float64, cells []TableCell) { | |
112 | 71 | pdf.SetXY(x, y) |
113 | 72 | for _, c := range cells { |
114 | 73 | pdf.SetFont(c.Font, c.FontStyle, c.FontSize) |
115 | - pdf.CellFormat(c.W, c.H, pdf.ToUTF8(c.Text), c.Border, BELLOW, c.Alignment, false, 0, "") | |
116 | - //pdf.CellFormat(c.w, c.h, c.text, c.border, BELLOW, align, false, 0, "") | |
74 | + pdf.CellFormat(c.W, c.H, pdf.toUTF8(c.Text), c.Border, BELLOW, c.Alignment, false, 0, "") | |
117 | 75 | } |
118 | 76 | } |
119 | 77 | |
120 | -// NewLine ... | |
121 | -func (pdf *Helper) NewLine(h float64) { | |
122 | - pdf.Ln(h) | |
123 | -} | |
124 | - | |
125 | -// WriteColumns ... | |
126 | -func (pdf *Helper) WriteColumns(align string, cols []PDFCell) { | |
127 | - for _, c := range cols { | |
128 | - pdf.CellFormat(c.width, c.height, pdf.ToUTF8(c.data), "", CONTINUE, align, false, 0, "") | |
129 | - } | |
130 | -} | |
131 | - | |
132 | -func (pdf *Helper) Row(x, y float64, cells []FormatedCell) { | |
78 | +func (pdf *Helper) DrawRow(x, y float64, cells []TableCell) { | |
133 | 79 | pdf.SetXY(x, y) |
134 | 80 | for _, c := range cells { |
135 | 81 | pdf.SetFont(c.Font, c.FontStyle, c.FontSize) |
136 | - pdf.CellFormat(c.W, c.H, pdf.ToUTF8(c.Text), c.Border, CONTINUE, c.Alignment, false, 0, "") | |
82 | + pdf.CellFormat(c.W, c.H, pdf.toUTF8(c.Text), c.Border, CONTINUE, c.Alignment, false, 0, "") | |
137 | 83 | } |
138 | 84 | } |
139 | 85 | |
140 | -const threeDots = "\u2056\u2056\u2056" | |
141 | - | |
142 | -// WriteColumnsWithAlignment ... | |
143 | -func (pdf *Helper) WriteColumnsWithAlignment(cols []PDFCellAligned) { | |
144 | - for _, c := range cols { | |
145 | - lines := pdf.SplitText(c.data, c.width) | |
146 | - if len(lines) == 1 { | |
147 | - pdf.CellFormat(c.width, c.height, pdf.ToUTF8(lines[0]), "", CONTINUE, c.alignment, false, 0, "") | |
148 | - } else { | |
149 | - pdf.CellFormat(c.width, c.height, pdf.ToUTF8(lines[0]+threeDots), "", CONTINUE, c.alignment, false, 0, "") | |
150 | - } | |
151 | - } | |
152 | - | |
86 | +func (pdf *Helper) TextLength(txt, family, style string, size float64) float64 { | |
87 | + family, _, _, _ = pdf.setCorrectFontFamily(textEncoding(txt)) | |
88 | + return pdf.Fpdf.TextLength(txt, family, style, size) | |
153 | 89 | } |
154 | 90 | |
155 | 91 | func (pdf *Helper) LimitText(text, limiter string, maxWidth float64) string { |
... | ... | @@ -176,22 +112,45 @@ func (pdf *Helper) InsertImage(img string, x, y, w, h float64) { |
176 | 112 | pdf.ImageOptions(img, x, y, w, h, autoBreak, opt, 0, "") |
177 | 113 | } |
178 | 114 | |
179 | -// PDFCell ... | |
180 | -type PDFCell struct { | |
181 | - data string | |
182 | - height, width float64 | |
115 | +func (pdf *Helper) PageHasSpace(requiredHeight float64) bool { | |
116 | + _, h := pdf.GetPageSize() | |
117 | + _, _, _, bot := pdf.GetMargins() | |
118 | + return (h - bot - pdf.GetY()) > requiredHeight | |
183 | 119 | } |
184 | 120 | |
185 | -// PDFCellAligned ... | |
186 | -type PDFCellAligned struct { | |
187 | - alignment string | |
188 | - data string | |
189 | - height, width float64 | |
121 | +// DrawBox ... | |
122 | +func (pdf Helper) DrawBox(x0, y0, w, h float64) { | |
123 | + pdf.Line(x0, y0, x0+w, y0) | |
124 | + pdf.Line(x0+w, y0, x0+w, y0+h) | |
125 | + pdf.Line(x0+w, y0+h, x0, y0+h) | |
126 | + pdf.Line(x0, y0+h, x0, y0) | |
190 | 127 | } |
191 | 128 | |
192 | -func (pdf *Helper) TextLength(txt, family, style string, size float64) float64 { | |
193 | - family, _, _, _ = pdf.setCorrectFontFamily(textEncoding(txt)) | |
194 | - return pdf.Fpdf.TextLength(txt, family, style, size) | |
129 | +// Strana %d/{TotalPages} | |
130 | +func (pdf *Helper) InsertPageNumber(x, y float64, format string) { | |
131 | + num := fmt.Sprintf(format, pdf.PageNo()) | |
132 | + pdf.DrawColumn(x, y, []TableCell{{10, 1, num, "DejaVuSans", "", 8, NOBORDER, LEFT}}) | |
133 | +} | |
134 | + | |
135 | +func (pdf *Helper) SuperscriptText(x, y, cw, ch float64, text, script string) { | |
136 | + family, style, size, sizeU := pdf.setCorrectFontFamily(textEncoding(text)) | |
137 | + | |
138 | + pdf.DrawCell(x, y, TableCell{cw, ch, text, family, style, size, NOBORDER, LEFT}) | |
139 | + | |
140 | + sx := x + pdf.TextLength(text, family, style, size) | |
141 | + sy := y - sizeU*0.2 | |
142 | + pdf.DrawCell(sx, sy, TableCell{cw, ch, script, family, style, size - 2, NOBORDER, LEFT}) | |
143 | +} | |
144 | + | |
145 | +// toUTF8 ... | |
146 | +func (pdf *Helper) toUTF8(s string) string { | |
147 | + encoding := textEncoding(s) | |
148 | + pdf.setCorrectFontFamily(encoding) | |
149 | + translator, ok := pdf.translators[encoding] | |
150 | + if !ok { | |
151 | + return "" | |
152 | + } | |
153 | + return translator(s) | |
195 | 154 | } |
196 | 155 | |
197 | 156 | func textEncoding(s string) string { |
... | ... | @@ -206,17 +165,6 @@ func textEncoding(s string) string { |
206 | 165 | return encoding |
207 | 166 | } |
208 | 167 | |
209 | -// ToUTF8 ... | |
210 | -func (pdf *Helper) ToUTF8(s string) string { | |
211 | - encoding := textEncoding(s) | |
212 | - pdf.setCorrectFontFamily(encoding) | |
213 | - translator, ok := pdf.translators[encoding] | |
214 | - if !ok { | |
215 | - return "" | |
216 | - } | |
217 | - return translator(s) | |
218 | -} | |
219 | - | |
220 | 168 | func (pdf *Helper) setCorrectFontFamily(enc string) (family, style string, ptSize, unitSize float64) { |
221 | 169 | family, style, ptSize, unitSize = pdf.GetFontInfo() |
222 | 170 | if enc == cyrillicEncoding { |
... | ... | @@ -231,46 +179,3 @@ func (pdf *Helper) setCorrectFontFamily(enc string) (family, style string, ptSiz |
231 | 179 | pdf.SetFont(family, style, ptSize) |
232 | 180 | return family, style, ptSize, unitSize |
233 | 181 | } |
234 | - | |
235 | -func (pdf *Helper) PageHasSpace(requiredHeight float64) bool { | |
236 | - _, h := pdf.GetPageSize() | |
237 | - _, _, _, bot := pdf.GetMargins() | |
238 | - return (h - bot - pdf.GetY()) > requiredHeight | |
239 | -} | |
240 | - | |
241 | -func (pdf *Helper) imageCenterOffset(w, h float64) (x, y float64) { | |
242 | - pageW, pageH := pdf.GetPageSize() | |
243 | - x = pageW/2.0 - w/2.0 | |
244 | - y = pageH/2.0 - h/2.0 | |
245 | - return x, y | |
246 | -} | |
247 | - | |
248 | -// call before drawing the cell | |
249 | -func (pdf *Helper) drawCellMargins(cw, ch float64) { | |
250 | - x0, y0 := pdf.GetX(), pdf.GetY() | |
251 | - pdf.DrawBox(x0, y0, cw, ch) | |
252 | -} | |
253 | - | |
254 | -// DrawBox ... | |
255 | -func (pdf Helper) DrawBox(x0, y0, w, h float64) { | |
256 | - pdf.Line(x0, y0, x0+w, y0) | |
257 | - pdf.Line(x0+w, y0, x0+w, y0+h) | |
258 | - pdf.Line(x0+w, y0+h, x0, y0+h) | |
259 | - pdf.Line(x0, y0+h, x0, y0) | |
260 | -} | |
261 | - | |
262 | -// Strana %d/{TotalPages} | |
263 | -func (pdf *Helper) InsertPageNumber(x, y float64, format string) { | |
264 | - num := fmt.Sprintf(format, pdf.PageNo()) | |
265 | - pdf.Column(x, y, []FormatedCell{{10, 1, num, "DejaVuSans", "", 8, NOBORDER, LEFT}}) | |
266 | -} | |
267 | - | |
268 | -func (pdf *Helper) SuperscriptText(x, y, cw, ch float64, text, script string) { | |
269 | - family, style, size, sizeU := pdf.setCorrectFontFamily(textEncoding(text)) | |
270 | - | |
271 | - pdf.FCell(x, y, FormatedCell{cw, ch, text, family, style, size, NOBORDER, LEFT}) | |
272 | - | |
273 | - sx := x + pdf.TextLength(text, family, style, size) | |
274 | - sy := y - sizeU*0.2 | |
275 | - pdf.FCell(sx, sy, FormatedCell{cw, ch, script, family, style, size - 2, NOBORDER, LEFT}) | |
276 | -} | ... | ... |