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