Commit ab548c502b5ecba40003067a6bd6050479efe5ee

Authored by Marko Tikvić
1 parent 2cff4b70cd
Exists in master

added Valid() to filters

Showing 2 changed files with 14 additions and 6 deletions   Show diff stats
1 package webutility 1 package webutility
2 2
3 // TODO(markO): test test test test test (and open source?) 3 // TODO(markO): test test test test test (and open source?)
4 4
5 import ( 5 import (
6 "crypto/tls" 6 "crypto/tls"
7 "errors" 7 "errors"
8 "fmt" 8 "fmt"
9 "net/smtp" 9 "net/smtp"
10 "strings" 10 "strings"
11 ) 11 )
12 12
13 type Email struct { 13 type Email struct {
14 To []string 14 To []string
15 From string 15 From string
16 Subject string 16 Subject string
17 Body string 17 Body string
18 } 18 }
19 19
20 func NewEmail(to []string, from, subject, body string) *Email { 20 func NewEmail(to []string, from, subject, body string) *Email {
21 return &Email{ 21 return &Email{
22 To: to, 22 To: to,
23 From: from, 23 From: from,
24 Subject: subject, 24 Subject: subject,
25 Body: body, 25 Body: body,
26 } 26 }
27 } 27 }
28 28
29 func (e *Email) String() string { 29 func (e *Email) String() string {
30 var str strings.Builder 30 var str strings.Builder
31 31
32 str.WriteString("From:" + e.From + "\r\n") 32 str.WriteString("From:" + e.From + "\r\n")
33 33
34 str.WriteString("To:") 34 str.WriteString("To:")
35 for i, _ := range e.To { 35 for i, _ := range e.To {
36 if i > 0 { 36 if i > 0 {
37 str.WriteString(",") 37 str.WriteString(",")
38 } 38 }
39 str.WriteString(e.To[i]) 39 str.WriteString(e.To[i])
40 } 40 }
41 str.WriteString("\r\n") 41 str.WriteString("\r\n")
42 42
43 str.WriteString("Subject:" + e.Subject + "\r\n") 43 str.WriteString("Subject:" + e.Subject + "\r\n")
44 44
45 // body 45 // body
46 str.WriteString("\r\n" + e.Body + "\r\n") 46 str.WriteString("\r\n" + e.Body + "\r\n")
47 47
48 return str.String() 48 return str.String()
49 } 49 }
50 50
51 func (e *Email) Bytes() []byte { 51 func (e *Email) Bytes() []byte {
52 return []byte(e.String()) 52 return []byte(e.String())
53 } 53 }
54 54
55 func SendEmail(email *Email, conf *EmailConfig) error { 55 func SendEmail(email *Email, conf *EmailConfig) error {
56 if email == nil { 56 if email == nil {
57 return errors.New("no email to send") 57 return errors.New("no email to send")
58 } 58 }
59 59
60 if conf == nil { 60 if conf == nil {
61 return errors.New("email configuration not provided") 61 return errors.New("email configuration not provided")
62 } 62 }
63 63
64 c, err := smtp.Dial(conf.ServerName) 64 c, err := smtp.Dial(conf.ServerName)
65 if err != nil { 65 if err != nil {
66 return err 66 return err
67 } 67 }
68 defer c.Close() 68 defer c.Close()
69 69
70 // not sure if this is needed 70 // not sure if this is needed
71 //if err = c.Hello(conf.ServerName); err != nil { 71 //if err = c.Hello(conf.ServerName); err != nil {
72 // return err 72 // return err
73 //} 73 //}
74 74
75 if ok, _ := c.Extension("STARTTLS"); ok { 75 if ok, _ := c.Extension("STARTTLS"); ok {
76 // disable stupid tls check for self-signed certificates 76 // disable stupid tls check for self-signed certificates
77 config := &tls.Config{ 77 config := &tls.Config{
78 ServerName: conf.ServerName, 78 ServerName: conf.ServerName,
79 InsecureSkipVerify: true, 79 InsecureSkipVerify: true,
80 } 80 }
81 // for golang testing 81 // for golang testing
82 //if testHookStartTLS != nil { 82 //if testHookStartTLS != nil {
83 // testHookStartTLS(config) 83 // testHookStartTLS(config)
84 //} 84 //}
85 if err = c.StartTLS(config); err != nil { 85 if err = c.StartTLS(config); err != nil {
86 return err 86 return err
87 } 87 }
88 } 88 }
89 89
90 /* 90 /*
91 // don't know what to do with this 91 // don't know what to do with this
92 if a != nil && c.ext != nil { 92 if a != nil && c.ext != nil {
93 if _, ok := c.ext["AUTH"]; !ok { 93 if _, ok := c.ext["AUTH"]; !ok {
94 return errors.New("smtp: server doesn't support AUTH") 94 return errors.New("smtp: server doesn't support AUTH")
95 } 95 }
96 if err = c.Auth(a); err != nil { 96 if err = c.Auth(a); err != nil {
97 return err 97 return err
98 } 98 }
99 } 99 }
100 */ 100 */
101 101
102 // Set up authentication information. 102 // Set up authentication information.
103 auth := smtp.PlainAuth(conf.Identity, conf.Username, conf.Password, conf.Host) 103 auth := smtp.PlainAuth(conf.Identity, conf.Username, conf.Password, conf.Host)
104 if err = c.Auth(auth); err != nil { 104 if err = c.Auth(auth); err != nil {
105 return err 105 return err
106 } 106 }
107 107
108 if err = c.Mail(email.From); err != nil { 108 if err = c.Mail(email.From); err != nil {
109 return err 109 return err
110 } 110 }
111 111
112 for _, addr := range email.To { 112 for _, addr := range email.To {
113 if err = c.Rcpt(addr); err != nil { 113 if err = c.Rcpt(addr); err != nil {
114 return err 114 return err
115 } 115 }
116 } 116 }
117 117
118 w, err := c.Data() 118 w, err := c.Data()
119 if err != nil { 119 if err != nil {
120 return err 120 return err
121 } 121 }
122 122
123 _, err = w.Write(email.Bytes()) 123 _, err = w.Write(email.Bytes())
124 if err != nil { 124 if err != nil {
125 return err 125 return err
126 } 126 }
127 127
128 err = w.Close() 128 err = w.Close()
129 if err != nil { 129 if err != nil {
130 return err 130 return err
131 } 131 }
132 132
133 return c.Quit() 133 return c.Quit()
134 } 134 }
135 135
136 type EmailConfig struct { 136 type EmailConfig struct {
137 ServerName string 137 ServerName string `json:"-"`
138 Identity string 138 Identity string `json:"-"`
139 Username string 139 Username string `json:"username"`
140 Password string 140 Password string `json:"password"`
141 Host string 141 Host string `json:"host"`
142 Port int 142 Port int `json:"port"`
143 } 143 }
144 144
145 func NewEmailConfig(ident, uname, pword, host string, port int) *EmailConfig { 145 func NewEmailConfig(ident, uname, pword, host string, port int) *EmailConfig {
146 return &EmailConfig{ 146 return &EmailConfig{
147 ServerName: host + fmt.Sprintf(":%d", port), 147 ServerName: host + fmt.Sprintf(":%d", port),
148 Identity: ident, 148 Identity: ident,
149 Username: uname, 149 Username: uname,
150 Password: pword, 150 Password: pword,
151 Host: host, 151 Host: host,
152 Port: port, 152 Port: port,
153 } 153 }
154 } 154 }
155 155
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "net/http" 5 "net/http"
6 "strings" 6 "strings"
7 ) 7 )
8 8
9 type Filter map[string]string 9 type Filter map[string]string
10 10
11 func (f *Filter) Size() int {
12 return len(*f)
13 }
14
15 func (f *Filter) Valid() bool {
16 return len(*f) > 0
17 }
18
11 func (fs Filter) validate(validFilters []string) (Filter, bool) { 19 func (fs Filter) validate(validFilters []string) (Filter, bool) {
12 goodFilters := make(map[string]string) 20 goodFilters := make(map[string]string)
13 cnt := 0 21 cnt := 0
14 len := 0 22 len := 0
15 for f, _ := range fs { 23 for f, _ := range fs {
16 len++ 24 len++
17 for _, v := range validFilters { 25 for _, v := range validFilters {
18 if f == v { 26 if f == v {
19 cnt++ 27 cnt++
20 goodFilters[f] = fs[f] 28 goodFilters[f] = fs[f]
21 } 29 }
22 } 30 }
23 } 31 }
24 32
25 result := true 33 result := true
26 if len > 0 && cnt == 0 { 34 if len > 0 && cnt == 0 {
27 // if no valid filters are found declare filtering request as invalid 35 // if no valid filters are found declare filtering request as invalid
28 result = false 36 result = false
29 } 37 }
30 38
31 return goodFilters, result 39 return goodFilters, result
32 } 40 }
33 41
34 // requires input in format: "param1::value1|param2::value2..." 42 // requires input in format: "param1::value1|param2::value2..."
35 func ParseFilters(req *http.Request, header string) (filters Filter) { 43 func ParseFilters(req *http.Request, header string) (filters Filter) {
36 q := req.FormValue(header) 44 q := req.FormValue(header)
37 q = strings.Trim(q, "\"") 45 q = strings.Trim(q, "\"")
38 kvp := strings.Split(q, "|") 46 kvp := strings.Split(q, "|")
39 filters = make(map[string]string, len(kvp)) 47 filters = make(map[string]string, len(kvp))
40 48
41 for i, _ := range kvp { 49 for i, _ := range kvp {
42 kv := strings.Split(kvp[i], "::") 50 kv := strings.Split(kvp[i], "::")
43 if len(kv) == 2 { 51 if len(kv) == 2 {
44 key := kv[0] 52 key := kv[0]
45 val := kv[1] 53 val := kv[1]
46 filters[key] = val 54 filters[key] = val
47 } 55 }
48 } 56 }
49 57
50 return filters 58 return filters
51 } 59 }
52 60
53 // TODO(marko): very dodgy, needs more robustness 61 // TODO(marko): very dodgy, needs more robustness
54 func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) { 62 func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) {
55 if prefix != "" { 63 if prefix != "" {
56 prefix += "." 64 prefix += "."
57 } 65 }
58 if len(filters) == 0 { 66 if len(filters) == 0 {
59 return "", true 67 return "", true
60 } 68 }
61 69
62 filters, ok = filters.validate(validFilters) 70 filters, ok = filters.validate(validFilters)
63 if !ok { 71 if !ok {
64 return "", ok 72 return "", ok
65 } 73 }
66 74
67 symbol := "=" 75 symbol := "="
68 for k, v := range filters { 76 for k, v := range filters {
69 if res != "" { 77 if res != "" {
70 res += " and " 78 res += " and "
71 } else { 79 } else {
72 res += " where " 80 res += " where "
73 } 81 }
74 c := string(v[0]) 82 c := string(v[0])
75 if c == "<" || c == ">" { 83 if c == "<" || c == ">" {
76 symbol = "" // examples: >3, >=3 84 symbol = "" // examples: >3, >=3
77 } else { 85 } else {
78 symbol = "=" 86 symbol = "="
79 } 87 }
80 88
81 res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, v) 89 res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, v)
82 } 90 }
83 91
84 return res, ok 92 return res, ok
85 } 93 }
86 94