Commit 62a0d7a8a772705b98713e3be1dde7af2e928856

Authored by Marko Tikvić
1 parent 0c71c54873
Exists in master

minor changes

Showing 3 changed files with 14 additions and 17 deletions   Show diff stats
document/document.go
1 package document 1 package document
2 2
3 import ( 3 import (
4 "errors" 4 "errors"
5 "fmt" 5 "fmt"
6 "io" 6 "io"
7 "mime" 7 "mime"
8 "net/http" 8 "net/http"
9 "os" 9 "os"
10 "time" 10 "time"
11 11
12 web "git.to-net.rs/marko.tikvic/webutility" 12 web "git.to-net.rs/marko.tikvic/webutility"
13 ) 13 )
14 14
15 // Document ... 15 // Document ...
16 type Document struct { 16 type Document struct {
17 ID int64 `json:"id"` 17 ID int64 `json:"id"`
18 FileName string `json:"fileName"` 18 FileName string `json:"fileName"`
19 Extension string `json:"extension"` 19 Extension string `json:"extension"`
20 ContentType string `json:"contentType"` 20 ContentType string `json:"contentType"`
21 Size int64 `json:"fileSize"` 21 Size int64 `json:"fileSize"`
22 UploadedBy string `json:"uploadedBy"` 22 UploadedBy string `json:"uploadedBy"`
23 LastModifiedBy string `json:"lastModifiedBy"` 23 LastModifiedBy string `json:"lastModifiedBy"`
24 TimeUploaded int64 `json:"timeUploaded"` 24 TimeUploaded int64 `json:"timeUploaded"`
25 TimeLastModified int64 `json:"timeLastModified"` 25 TimeLastModified int64 `json:"timeLastModified"`
26 RoleAccessLevel int64 `json:"accessLevel"` 26 RoleAccessLevel int64 `json:"accessLevel"`
27 Description string `json:"description"` 27 Description string `json:"description"`
28 Download *DownloadLink `json:"download"` 28 Download *DownloadLink `json:"download"`
29 Path string `json:"-"` 29 Path string `json:"-"`
30 directory string 30 directory string
31 data []byte 31 data []byte
32 } 32 }
33 33
34 // OpenFileAsDocument ... 34 // OpenFileAsDocument ...
35 func OpenFileAsDocument(path string) (*Document, error) { 35 func OpenFileAsDocument(path string) (*Document, error) {
36 d := &Document{Path: path} 36 d := &Document{Path: path}
37 37
38 f, err := os.Open(d.Path) 38 f, err := os.Open(d.Path)
39 if err != nil { 39 if err != nil {
40 return nil, err 40 return nil, err
41 } 41 }
42 defer f.Close() 42 defer f.Close()
43 43
44 stats, err := f.Stat() 44 stats, err := f.Stat()
45 if err != nil { 45 if err != nil {
46 return nil, err 46 return nil, err
47 } 47 }
48 48
49 d.FileName = stats.Name() 49 d.FileName = stats.Name()
50 d.Size = stats.Size() 50 d.Size = stats.Size()
51 d.Extension = web.FileExtension(d.FileName) 51 d.Extension = web.FileExtension(d.FileName)
52 52
53 d.data = make([]byte, d.Size) 53 d.data = make([]byte, d.Size)
54 if _, err = f.Read(d.data); err != nil { 54 if _, err = f.Read(d.data); err != nil {
55 return nil, err 55 return nil, err
56 } 56 }
57 57
58 return d, err 58 return d, err
59 } 59 }
60 60
61 // DownloadLink ... 61 // DownloadLink ...
62 type DownloadLink struct { 62 type DownloadLink struct {
63 Method string `json:"method"` 63 Method string `json:"method"`
64 URL string `json:"url"` 64 URL string `json:"url"`
65 } 65 }
66 66
67 // SetDownloadInfo ... 67 // SetDownloadInfo ...
68 func (d *Document) SetDownloadInfo(method, url string) { 68 func (d *Document) SetDownloadInfo(method, url string) {
69 d.Download = &DownloadLink{ 69 d.Download = &DownloadLink{
70 Method: method, 70 Method: method,
71 URL: url, 71 URL: url,
72 } 72 }
73 } 73 }
74 74
75 // ServeDocument writes d's buffer to w and sets appropriate headers according to d's content type 75 // ServeDocument writes d's buffer to w and sets appropriate headers according to d's content type
76 // and downloadPrompt. 76 // and downloadPrompt.
77 func ServeDocument(w http.ResponseWriter, d *Document, downloadPrompt bool) error { 77 func ServeDocument(w http.ResponseWriter, d *Document, downloadPrompt bool) error {
78 f, err := os.Open(d.Path) 78 f, err := os.Open(d.Path)
79 if err != nil { 79 if err != nil {
80 return err 80 return err
81 } 81 }
82 defer f.Close() 82 defer f.Close()
83 83
84 web.SetContentType(w, mime.TypeByExtension(d.Extension)) 84 web.SetContentType(w, mime.TypeByExtension(d.Extension))
85 web.SetResponseStatus(w, http.StatusOK) 85 web.SetResponseStatus(w, http.StatusOK)
86 if downloadPrompt { 86 if downloadPrompt {
87 w.Header().Set("Content-Disposition", "attachment; filename="+d.FileName) 87 w.Header().Set("Content-Disposition", "attachment; filename="+d.FileName)
88 } 88 }
89 89
90 buf := make([]byte, d.Size) 90 buf := make([]byte, d.Size)
91 if _, err := f.Read(buf); err != nil { 91 if _, err := f.Read(buf); err != nil {
92 return err 92 return err
93 } 93 }
94 94
95 w.Header().Set("Content-Length", fmt.Sprintf("%d", d.Size)) 95 w.Header().Set("Content-Length", fmt.Sprintf("%d", d.Size))
96 web.WriteResponse(w, buf) 96 web.WriteResponse(w, buf)
97 97
98 return nil 98 return nil
99 } 99 }
100 100
101 // ParseDocument ... 101 // ParseDocument ...
102 func ParseDocument(req *http.Request) (doc *Document, err error) { 102 func ParseDocument(req *http.Request) (doc *Document, err error) {
103 req.ParseMultipartForm(32 << 20) 103 req.ParseMultipartForm(32 << 20)
104 file, fheader, err := req.FormFile("document") 104 file, fheader, err := req.FormFile("document")
105 if err != nil { 105 if err != nil {
106 return doc, err 106 return doc, err
107 } 107 }
108 108
109 claims, _ := web.GetTokenClaims(req) 109 claims, _ := web.GetTokenClaims(req)
110 owner := claims.Username 110 owner := claims.Username
111 111
112 fname := fheader.Filename 112 fname := fheader.Filename
113 113
114 fsize := fheader.Size 114 fsize := fheader.Size
115 ftype := fmt.Sprintf("%v", fheader.Header["Content-Type"][0]) 115 ftype := fmt.Sprintf("%v", fheader.Header["Content-Type"][0])
116 116
117 fextn := web.FileExtension(fname) 117 fextn := web.FileExtension(fname)
118 if fextn == "" { 118 if fextn == "" {
119 return doc, errors.New("invalid extension") 119 return doc, errors.New("invalid extension")
120 } 120 }
121 121
122 doc = new(Document) 122 doc = new(Document)
123 123
124 doc.FileName = fname 124 doc.FileName = fname
125 doc.Size = fsize 125 doc.Size = fsize
126 doc.ContentType = ftype 126 doc.ContentType = ftype
127 doc.Extension = "." + fextn 127 doc.Extension = "." + fextn
128 128
129 t := time.Now().Unix() 129 t := time.Now().Unix()
130 doc.TimeUploaded = t 130 doc.TimeUploaded = t
131 doc.TimeLastModified = t 131 doc.TimeLastModified = t
132 132
133 doc.UploadedBy = owner 133 doc.UploadedBy = owner
134 doc.LastModifiedBy = owner 134 doc.LastModifiedBy = owner
135 doc.RoleAccessLevel = 0 135 doc.RoleAccessLevel = 0
136 136
137 doc.data = make([]byte, doc.Size) 137 doc.data = make([]byte, doc.Size)
138 if _, err = io.ReadFull(file, doc.data); err != nil { 138 if _, err = io.ReadFull(file, doc.data); err != nil {
139 return doc, err 139 return doc, err
140 } 140 }
141 141
142 return doc, nil 142 return doc, nil
143 } 143 }
144 144
145 // SaveToFile ... 145 // SaveToFile ...
146 func (d *Document) SaveToFile(path string) (f *os.File, err error) { 146 func (d *Document) SaveToFile(path string) (f *os.File, err error) {
147 d.Path = path 147 d.Path = path
148 148
149 if web.FileExists(path) { 149 if web.FileExists(path) {
150 err = fmt.Errorf("file %s alredy exists", path) 150 err = fmt.Errorf("file %s alredy exists", path)
151 return nil, err 151 return nil, err
152 } 152 }
153 153
154 if parentDir := web.DirectoryFromPath(path); parentDir != "" { 154 if parentDir := web.DirectoryFromPath(path); parentDir != "" {
155 if err = os.MkdirAll(parentDir, os.ModePerm); err != nil { 155 if err = os.MkdirAll(parentDir, os.ModePerm); err != nil {
156 if !os.IsExist(err) { 156 if !os.IsExist(err) {
157 return nil, err 157 return nil, err
158 } 158 }
159 } 159 }
160 } 160 }
161 161
162 if f, err = os.Create(path); err != nil { 162 if f, err = os.Create(path); err != nil {
163 return nil, err 163 return nil, err
164 } 164 }
165 165
166 if _, err = f.Write(d.data); err != nil { 166 if _, err = f.Write(d.data); err != nil {
167 f.Close() 167 f.Close()
168 d.DeleteFile() 168 d.DeleteFile()
169 return nil, err 169 return nil, err
170 } 170 }
171 f.Close() 171 f.Close()
172 172
173 return f, nil 173 return f, nil
174 } 174 }
175 175
176 func DeleteDocuments(docs []*Document) error { 176 func DeleteDocuments(docs []*Document) error {
177 for _, d := range docs { 177 for _, d := range docs {
178 if d == nil {
179 continue
180 }
178 if err := d.DeleteFile(); err != nil { 181 if err := d.DeleteFile(); err != nil {
179 return err 182 return err
180 } 183 }
181 } 184 }
182 return nil 185 return nil
183 } 186 }
184 187
185 // DeleteFile ... 188 // DeleteFile ...
186 func (d *Document) DeleteFile() error { 189 func (d *Document) DeleteFile() error {
187 return os.Remove(d.Path) 190 return os.Remove(d.Path)
188 } 191 }
189 192
1 package webutility 1 package webutility
2 2
3 type QSortDirection int 3 type QSortDirection int
4 4
5 const ( 5 const (
6 QSortAscending QSortDirection = iota 6 QSortAscending QSortDirection = iota
7 QSortDescending 7 QSortDescending
8 ) 8 )
9 9
10 // QuickSortable is an interface for quicksorting slices. 10 // QuickSortable is an interface for quicksorting slices.
11 type QuickSortable interface { 11 type QuickSortable interface {
12 Swap(i, j int) 12 Swap(i, j int)
13 Compare(i, j int) int 13 Compare(i, j int) int
14 Len() int 14 Len() int
15 } 15 }
16 16
17 // Quicksort quicksorts que. 17 // Quicksort quicksorts que.
18 func Quicksort(que QuickSortable, low, high int, dir QSortDirection) { 18 func Quicksort(que QuickSortable, low, high int, dir QSortDirection) {
19 if low >= high { 19 if low >= high {
20 return 20 return
21 } 21 }
22 22
23 if dir != QSortAscending && dir != QSortDescending { 23 if dir != QSortAscending && dir != QSortDescending {
24 return 24 return
25 } 25 }
26 26
27 index := partition(que, low, high, dir) 27 index := partition(que, low, high, dir)
28 Quicksort(que, low, index-1, dir) 28 Quicksort(que, low, index-1, dir)
29 Quicksort(que, index+1, high, dir) 29 Quicksort(que, index+1, high, dir)
30 } 30 }
31 31
32 func partition(que QuickSortable, low, high int, dir QSortDirection) int { 32 func partition(que QuickSortable, low, high int, dir QSortDirection) int {
33 swap := 0 33 swap := 0
34 // -1 -> i > j 34 // -1 -> i > j
35 // 1 -> i < j 35 // 1 -> i < j
36 if dir == QSortDescending { 36 if dir == QSortDescending {
37 swap = -1 37 swap = -1
38 } else { 38 } else {
39 swap = 1 39 swap = 1
40 } 40 }
41 41
42 i := low - 1 42 i := low - 1
43 for j := low; j <= high-1; j++ { 43 for j := low; j <= high-1; j++ {
44 if que.Compare(j, high) == swap { 44 if que.Compare(j, high) == swap {
45 i++ 45 i++
46 que.Swap(i, j) 46 que.Swap(i, j)
47 } 47 }
48 continue 48 continue
49 } 49 }
50 que.Swap(i+1, high) 50 que.Swap(i+1, high)
51 return i + 1 51 return i + 1
52 } 52 }
53
54 func BubbleSort(arr []int64) {
55 for i := 0; i < len(arr)-1; i++ {
56 for j := i; j < len(arr); j++ {
57 if arr[i] > arr[j] {
58 arr[i], arr[j] = arr[j], arr[i]
59 }
60 }
61 }
62 }
53 63
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "fmt" 5 "fmt"
6 "net/http" 6 "net/http"
7 "time"
8 7
9 "git.to-net.rs/marko.tikvic/gologger" 8 "git.to-net.rs/marko.tikvic/gologger"
10 "github.com/gorilla/mux" 9 "github.com/gorilla/mux"
11 ) 10 )
12 11
13 type Server struct { 12 type Server struct {
14 DB *sql.DB 13 DB *sql.DB
15 Router *mux.Router 14 Router *mux.Router
16 Logger *gologger.Logger 15 Logger *gologger.Logger
17 Port string 16 Port string
18 DBs map[string]*sql.DB 17 DBs map[string]*sql.DB
19 dsn map[string]string 18 dsn map[string]string
20 } 19 }
21 20
22 func NewODBCServer(dsn, port, logDir string) (s *Server, err error) { 21 func NewODBCServer(dsn, port, logDir string) (s *Server, err error) {
23 s = new(Server) 22 s = new(Server)
24 23
25 s.Port = port 24 s.Port = port
26 25
27 if s.DB, err = sql.Open("odbc", fmt.Sprintf("DSN=%s;", dsn)); err != nil { 26 if s.DB, err = sql.Open("odbc", fmt.Sprintf("DSN=%s;", dsn)); err != nil {
28 return nil, err 27 return nil, err
29 } 28 }
30 29
31 s.Router = mux.NewRouter() 30 s.Router = mux.NewRouter()
32 31
33 if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil { 32 if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil {
34 return nil, fmt.Errorf("can't create logger: %s", err.Error()) 33 return nil, fmt.Errorf("can't create logger: %s", err.Error())
35 } 34 }
36 35
37 s.DBs = make(map[string]*sql.DB) 36 s.DBs = make(map[string]*sql.DB)
38 s.DBs["default"] = s.DB 37 s.DBs["default"] = s.DB
39 38
40 s.dsn = make(map[string]string) 39 s.dsn = make(map[string]string)
41 s.DBs["default"] = s.DB 40 s.dsn["default"] = dsn
42 41
43 return s, nil 42 return s, nil
44 } 43 }
45 44
46 func (s *Server) Run() { 45 func (s *Server) Run() {
47 s.Logger.Print("Server listening on %s", s.Port) 46 s.Logger.Print("Server listening on %s", s.Port)
48 s.Logger.PrintAndTrace(http.ListenAndServe(s.Port, s.Router).Error()) 47 s.Logger.PrintAndTrace(http.ListenAndServe(s.Port, s.Router).Error())
49 } 48 }
50 49
51 func (s *Server) Cleanup() { 50 func (s *Server) Cleanup() {
52 if s.DB != nil { 51 if s.DB != nil {
53 s.DB.Close() 52 s.DB.Close()
54 } 53 }
55 54
56 if s.Logger != nil { 55 if s.Logger != nil {
57 s.Logger.Close() 56 s.Logger.Close()
58 } 57 }
59 } 58 }
60 59
61 func (s *Server) StartTransaction() (*sql.Tx, error) { 60 func (s *Server) StartTransaction() (*sql.Tx, error) {
62 return s.DB.Begin() 61 return s.DB.Begin()
63 } 62 }
64 63
65 func CommitChanges(tx *sql.Tx, err *error, opt ...error) { 64 func CommitChanges(tx *sql.Tx, err *error, opt ...error) {
66 if *err != nil { 65 if *err != nil {
67 tx.Rollback() 66 tx.Rollback()
68 return 67 return
69 } 68 }
70 69
71 for _, e := range opt { 70 for _, e := range opt {
72 if e != nil { 71 if e != nil {
73 tx.Rollback() 72 tx.Rollback()
74 return 73 return
75 } 74 }
76 } 75 }
77 76
78 if *err = tx.Commit(); *err != nil { 77 if *err = tx.Commit(); *err != nil {
79 tx.Rollback() 78 tx.Rollback()
80 } 79 }
81 } 80 }
82
83 func (s *Server) RefreshDatabaseConnections(period time.Duration) {
84 for {
85 for k, db := range s.DBs {
86 if err := db.Ping(); err != nil {
87 if s.Logger != nil {
88 s.Logger.PrintAndTrace("failed to ping database (%s): %s", s.dsn[k], err.Error())
89 } else {
90 fmt.Println("failed to ping database (%s): %s", s.dsn[k], err.Error())
91 }
92 }
93 }
94 time.Sleep(period)
95 }
96 }
97 81