func (h *Handler) handleUpdate(w http.ResponseWriter, r *http.Request) { _, err := session.Parse(r) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } path := config.Get("invoice_data") v, err := invoice.Load(path) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } key := r.FormValue("key") hours, _ := strconv.Atoi(r.FormValue("hours")) v.SetHours(key, hours) err = v.Save(path) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } url := r.FormValue("url") if url == "" { url = config.Get("baseurl") } http.Redirect(w, r, url, http.StatusFound) }
func allowed() bool { if check { ok := strings.ToLower(config.Get("logging")) allow = (ok == "true" || ok == "on" || ok == "1") header = config.Get("response_header") check = false } return allow }
func main() { switch len(os.Args) { case 1: break case 2: err := os.Chdir(os.Args[1]) if err != nil { panic(err) } break default: return } err := config.Load("./data/data.db") if err != nil { panic(err) } allow, _ := strconv.ParseBool(config.Get("archive_migrate")) if allow != true { fmt.Println("Migrate not allowed in this environment") return } config.Dump(os.Stdout) m, err := getData() if err != nil { panic(err) } invoiceData := config.Get("invoice_data") fmt.Printf("=> %s\n", invoiceData) m.Invoice.Save(invoiceData) archivePath := config.Get("archive_path") err = os.RemoveAll(archivePath) if err != nil { panic(err) } err = os.MkdirAll(archivePath, 0755) if err != nil { panic(err) } for _, a := range m.Archive { err = saveFile(a.Url, filepath.Join(archivePath, a.Name)) if err != nil { fmt.Println(err.Error()) } } fmt.Println("OK") }
func (h *Handler) serveNotFound(w http.ResponseWriter, r *http.Request) { m := map[string]interface{}{ "baseurl": config.Get("baseurl"), } w.WriteHeader(http.StatusNotFound) h.Templates.ExecuteTemplate(w, "error404.html", m) }
func (h *Handler) serveServerError(w http.ResponseWriter, r *http.Request) { m := map[string]interface{}{ "baseurl": config.Get("baseurl"), } w.WriteHeader(http.StatusInternalServerError) h.Templates.ExecuteTemplate(w, "error500.html", m) }
func (h *Handler) handleHome(w http.ResponseWriter, r *http.Request) { s, _ := session.Parse(r) if s != nil { s.Save(w, true) } v, err := invoice.Load(config.Get("invoice_data")) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } urlpath := strings.Trim(r.URL.Path, "/") segments := strings.Split(urlpath, "/") if len(segments) == 2 { v.SetSelected(segments[1]) } msg, _ := flashdata.Get(w, r) m := map[string]interface{}{ "Hours": make([]int, 25), "Invoice": v, "LoggedIn": s != nil, "Message": msg, "Url": r.URL.Path, } h.Templates.ExecuteTemplate(w, "home.html", m) }
func Row(q string, params []interface{}, bind []interface{}) error { db, err := sql.Open("sqlite3", config.Get("dbf")) if err != nil { return err } defer db.Close() stmt, err := db.Prepare(q) if err != nil { return err } defer stmt.Close() row := stmt.QueryRow(params...) if err != nil { return err } err = row.Scan(bind...) if err != nil { return err } return nil }
func Parse(r *http.Request) (*Session, error) { c, err := r.Cookie(config.Get("session_cookie_name")) if err != nil { return nil, err } q := ` SELECT id , key FROM user_session s WHERE s.key = ? AND s.valid_until > ?; ` params := []interface{}{ c.Value, time.Now().Unix(), } s := new(Session) bind := []interface{}{ &s.Id, &s.Key, } err = dao.Row(q, params, bind) if err != nil { return nil, err } return s, nil }
func loadTemplates() { if Templates == nil { t, _ := template.ParseGlob( filepath.Join(config.Get("email"), "*.*")) Templates = t } }
func New() (*Handler, error) { h := new(Handler) h.header = config.Get("response_header") h.Rules = []*Rule{ &Rule{"GET:/hightech", nil, h.handleHome}, &Rule{"GET:/hightech/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]", nil, h.handleHome}, &Rule{"GET:/hightech/pull", nil, h.handlePull}, &Rule{"GET:/hightech/purge", nil, h.handlePurge}, &Rule{"GET:/hightech/verify/[A-Za-z0-9][A-Za-z0-9-]*", nil, h.handleVerify}, &Rule{"POST:/hightech/close", nil, h.handleClose}, &Rule{"POST:/hightech/update", nil, h.handleUpdate}, &Rule{"POST:/hightech/verify", nil, h.handleVerifyPost}, } // Compile rules for _, rule := range h.Rules { re, err := regexp.Compile(fmt.Sprintf("^%s$", strings.TrimRight(rule.Pattern, "/"))) if err != nil { panic(err) } rule.Compiled = re } err := h.loadTemplates() if err != nil { return nil, err } return h, nil }
func Set(w http.ResponseWriter, s string) { secure, _ := strconv.ParseBool(config.Get("session_cookie_secure")) c := new(http.Cookie) c.Name = fmt.Sprintf("%s-flash", config.Get("session_cookie_name")) c.Path = config.Get("session_cookie_path") c.Value = base64.URLEncoding.EncodeToString([]byte(strings.TrimSpace(s))) if c.Value != "" { c.MaxAge = 0 } else { c.MaxAge = -1 } c.Secure = secure http.SetCookie(w, c) logger.Log(w, "SET-COOKIE", c.String()) }
func (s *Session) Save(w http.ResponseWriter, keepalive bool) error { q := ` UPDATE user_session SET valid_until = ? , modified_date = ? WHERE id = ?; ` valid := int64(0) if keepalive { valid = time.Now().Unix() + SESSION_OFFSET } params := []interface{}{ valid, time.Now().Unix(), s.Id, } _, err := dao.Exec(q, params) if err != nil { return err } expires := -1 if keepalive { expires, _ = strconv.Atoi(config.Get("session_cookie_expires")) } secure, _ := strconv.ParseBool(config.Get("session_cookie_secure")) c := new(http.Cookie) c.Name = config.Get("session_cookie_name") if keepalive { c.Value = s.Key } c.Path = config.Get("session_cookie_path") c.MaxAge = expires c.Secure = secure http.SetCookie(w, c) logger.Log(w, "SET-COOKIE", c.String()) return nil }
func (h *Handler) loadTemplates() error { t, err := template.ParseGlob(filepath.Join(config.Get("templates"), "*.*")) if err != nil { return err } h.Templates = t return nil }
func (h *Handler) handleVerifyPost(w http.ResponseWriter, r *http.Request) { err := session.SendVerify() if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } flashdata.Set(w, "Verification link sent to your email address") http.Redirect(w, r, config.Get("baseurl"), http.StatusFound) }
func (h *Handler) handlePull(w http.ResponseWriter, r *http.Request) { v, err := invoice.Load(config.Get("invoice_data")) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } m := new(invoice.Migrate) m.Invoice = v match, err := filepath.Glob( filepath.Join(config.Get("archive_path"), "?*.???*")) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } m.Archive = make([]*invoice.MigrateArchive, len(match)) for i, f := range match { f = filepath.Base(f) m.Archive[i] = &invoice.MigrateArchive{ f, fmt.Sprintf("%s%s/%s", config.Get("baseurl"), config.Get("archive_baseurl"), f)} } b, err := json.MarshalIndent(m, "", " ") if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } w.Header().Add("Content-Type", "text/plain") w.Write(b) }
func (h *Handler) handleVerify(w http.ResponseWriter, r *http.Request) { segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/") vkey := segments[2] s, err := session.Verify(vkey) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } s.Save(w, true) http.Redirect(w, r, config.Get("baseurl"), http.StatusFound) }
func Exec(q string, params []interface{}) (sql.Result, error) { db, err := sql.Open("sqlite3", config.Get("dbf")) if err != nil { return nil, err } defer db.Close() stmt, err := db.Prepare(q) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(params...) }
func Get(w http.ResponseWriter, r *http.Request) (string, bool) { c, err := r.Cookie(fmt.Sprintf("%s-flash", config.Get("session_cookie_name"))) if err != nil { return "", false } b, err := base64.URLEncoding.DecodeString(c.Value) if err != nil { return "", false } Set(w, "") return string(b), true }
func SendVerify() error { vkey, err := uuid4.New() if err != nil { return err } q := ` INSERT INTO user_verify VALUES( NULL , ? , ? , ? , ? ); ` params := []interface{}{ vkey, time.Now().Unix() + VERIFY_OFFSET, time.Now().Unix(), time.Now().Unix(), } _, err = dao.Exec(q, params) if err != nil { return err } url := fmt.Sprintf("%s/verify/%s", config.Get("baseurl"), vkey) loadTemplates() tpl := "verify" subject := "Please verify your High Tech account" html := new(bytes.Buffer) Templates.ExecuteTemplate(html, fmt.Sprintf("%s.html", tpl), url) text := new(bytes.Buffer) Templates.ExecuteTemplate(text, fmt.Sprintf("%s.txt", tpl), url) m := awsses.New( config.Get("awsses_sender"), config.Get("verify_email"), subject, html.String(), text.String()) return m.Send( config.Get("awsses_baseurl"), config.Get("awsses_accesskey"), config.Get("awsses_secretkey")) }
func getData() (*invoice.Migrate, error) { url := config.Get("archive_migrate_url") resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } m := new(invoice.Migrate) err = json.Unmarshal(b, m) if err != nil { return nil, err } return m, nil }
func main() { switch len(os.Args) { case 1: break case 2: err := os.Chdir(os.Args[1]) if err != nil { panic(err) } break default: return } err := config.Load("./data/data.db") if err != nil { panic(err) } config.Dump(os.Stdout) h, err := handler.New() if err != nil { panic(err) } err = ioutil.WriteFile("./pid", []byte(strconv.Itoa(os.Getpid())), 0644) if err != nil { panic(err) } http.Handle("/", h) err = http.ListenAndServe(config.Get("bind"), nil) if err != nil { panic(err) } }
func (h *Handler) handleClose(w http.ResponseWriter, r *http.Request) { _, err := session.Parse(r) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } path := config.Get("invoice_data") v, err := invoice.Load(path) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } // HTML htmlName := fmt.Sprintf("%s-%s.html", v.User.Prefix, v.Invoice.Entries[v.Invoice.EndDate].Key) htmlPath := filepath.Join(config.Get("archive_path"), htmlName) var htmlBuf bytes.Buffer err = h.Templates.ExecuteTemplate(&htmlBuf, "invoice.html", v) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } err = ioutil.WriteFile(htmlPath, htmlBuf.Bytes(), 0644) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } // JSON jsonName := fmt.Sprintf("%s-%s.txt", v.User.Prefix, v.Invoice.Entries[v.Invoice.EndDate].Key) jsonPath := filepath.Join(config.Get("archive_path"), jsonName) jsonBytes, err := json.MarshalIndent(v, "", " ") if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } err = ioutil.WriteFile(jsonPath, jsonBytes, 0644) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } // EMAIL m := awsses.New( config.Get("awsses_sender"), config.Get("awsses_sender"), fmt.Sprintf( "High Tech Timesheet %s/%s/%d", v.Invoice.Entries[v.Invoice.EndDate].MM, v.Invoice.Entries[v.Invoice.EndDate].DD, v.Invoice.Entries[v.Invoice.EndDate].YYYY), "", fmt.Sprintf("%d Hours", v.Invoice.Total), &awsses.MessageAttachment{htmlBuf.Bytes(), "text/html", htmlName}, &awsses.MessageAttachment{jsonBytes, "text/plain", jsonName}) err = m.Send( config.Get("awsses_baseurl"), config.Get("awsses_accesskey"), config.Get("awsses_secretkey")) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } v2, err := invoice.New(v.Invoice.Entries[v.Invoice.EndDate].Key, time.Hour*24) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } v2.User = v.User v2.User.LastInvoice = fmt.Sprintf("%s/%s", config.Get("archive_baseurl"), htmlName) err = v2.Save(path) if err != nil { logger.Error(w, err) h.serveServerError(w, r) return } http.Redirect(w, r, config.Get("baseurl"), http.StatusFound) }