Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

261 lines
5.0 KiB

  1. package main
  2. import (
  3. "net/http"
  4. "log"
  5. "sync"
  6. "regexp"
  7. "html/template"
  8. "database/sql"
  9. _ "github.com/go-sql-driver/mysql"
  10. "fmt"
  11. "encoding/json"
  12. )
  13. type Page struct {
  14. tpl *template.Template
  15. Title string
  16. Name string
  17. }
  18. type LoanType struct {
  19. Id int `json:"id"`
  20. User int `json:"user"`
  21. Branch int `json:"branch"`
  22. Name string `json:"name"`
  23. }
  24. type FeeTemplate struct {
  25. Id int `json:"id"`
  26. User int `json:"user"`
  27. Branch int `json:"branch"`
  28. Amount int `json:"amount"`
  29. Perc int `json:"perc"`
  30. Ftype string `json:"type"`
  31. Notes string `json:"notes"`
  32. Name string `json:"name"`
  33. Category string `json:"category"`
  34. Auto bool `json:"auto"`
  35. }
  36. type Estimate struct {
  37. Id int `json:"id"`
  38. User int `json:"user"`
  39. Borrower int `json:"borrower"`
  40. Comparison int `json:"comparison"`
  41. Transaction int `json:"transaction"`
  42. LoanType LoanType `json:"loanType"`
  43. LoanAmount int `json:"loanAmount"`
  44. Price int `json:"price"`
  45. Property string `json:"property"`
  46. Pud bool `json:"pud"`
  47. Term int `json:"term"`
  48. Interest int `json:"interest"`
  49. Hoi int `json:"hoi"`
  50. MiName string `json:"miName"`
  51. MiAmount int `json:"miAmount"`
  52. }
  53. var (
  54. regexen = make(map[string]*regexp.Regexp)
  55. relock sync.Mutex
  56. address = "127.0.0.1:8001"
  57. )
  58. var paths = map[string]string {
  59. "home": "home.tpl",
  60. "terms": "terms.tpl",
  61. "app": "app.tpl",
  62. }
  63. var pages = map[string]Page {
  64. "home": cache("home", "Home"),
  65. "terms": cache("terms", "Terms and Conditions"),
  66. "app": cache("app", "App"),
  67. }
  68. func cache(name string, title string) Page {
  69. var p = []string{"master.tpl", paths[name]}
  70. tpl := template.Must(template.ParseFiles(p...))
  71. return Page{tpl: tpl,
  72. Title: title,
  73. Name: name,
  74. }
  75. }
  76. func (page Page) Render(w http.ResponseWriter) {
  77. err := page.tpl.Execute(w, page)
  78. if err != nil {
  79. log.Print(err)
  80. }
  81. }
  82. func match(path, pattern string, args *[]string) bool {
  83. relock.Lock()
  84. defer relock.Unlock()
  85. regex := regexen[pattern]
  86. if regex == nil {
  87. regex = regexp.MustCompile("^" + pattern + "$")
  88. regexen[pattern] = regex
  89. }
  90. matches := regex.FindStringSubmatch(path)
  91. if len(matches) <= 0 {
  92. return false
  93. }
  94. *args = matches[1:]
  95. return true
  96. }
  97. func getLoanType(
  98. db *sql.DB,
  99. user int,
  100. branch int,
  101. isUser bool) ([]LoanType, error) {
  102. var loans []LoanType
  103. // Should be changed to specify user
  104. rows, err :=
  105. db.Query(`SELECT * FROM loan_type WHERE user_id = ? AND branch_id = ? ` +
  106. "OR (user_id = 0 AND branch_id = 0)", user, branch)
  107. if err != nil {
  108. return nil, fmt.Errorf("loan_type error: %v", err)
  109. }
  110. defer rows.Close()
  111. for rows.Next() {
  112. var loan LoanType
  113. if err := rows.Scan(
  114. &loan.Id,
  115. &loan.User,
  116. &loan.Branch,
  117. &loan.Name)
  118. err != nil {
  119. log.Printf("Error occured fetching loan: %v", err)
  120. return nil, fmt.Errorf("Error occured fetching loan: %v", err)
  121. }
  122. loans = append(loans, loan)
  123. }
  124. log.Printf("The loans: %v", loans)
  125. return loans, nil
  126. }
  127. // Fetch fees from the database
  128. func getFees(db *sql.DB, user int) ([]FeeTemplate, error) {
  129. var fees []FeeTemplate
  130. // Should be changed to specify user
  131. rows, err := db.Query(
  132. "SELECT * FROM fee_template " +
  133. "WHERE user_id = ? OR user_id = 0",
  134. user)
  135. if err != nil {
  136. return nil, fmt.Errorf("Fee error %v", err)
  137. }
  138. defer rows.Close()
  139. for rows.Next() {
  140. var fee FeeTemplate
  141. if err := rows.Scan(
  142. &fee.Id,
  143. &fee.User,
  144. &fee.Branch,
  145. &fee.Amount,
  146. &fee.Perc,
  147. &fee.Ftype,
  148. &fee.Notes,
  149. &fee.Name,
  150. &fee.Category,
  151. &fee.Auto)
  152. err != nil {
  153. return nil, fmt.Errorf("The fees %q: %v", user, err)
  154. }
  155. fees = append(fees, fee)
  156. }
  157. return fees, nil
  158. }
  159. func getMi(db *sql.DB, )
  160. func route(w http.ResponseWriter, r *http.Request) {
  161. var page Page
  162. var args []string
  163. p := r.URL.Path
  164. switch {
  165. case r.Method == "GET" && match(p, "/", &args):
  166. page = pages[ "home" ]
  167. case match(p, "/terms", &args):
  168. page = pages[ "terms" ]
  169. case match(p, "/app", &args):
  170. page = pages[ "app" ]
  171. case match(p, "/assets", &args):
  172. page = pages[ "app" ]
  173. default:
  174. http.NotFound(w, r)
  175. return
  176. }
  177. page.Render(w)
  178. }
  179. func api(w http.ResponseWriter, r *http.Request) {
  180. var args []string
  181. // var response string
  182. p := r.URL.Path
  183. db, err := sql.Open("mysql",
  184. fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/skouter",
  185. config["DBUser"],
  186. config["DBPass"]))
  187. w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  188. err = db.Ping()
  189. if err != nil {
  190. print("Bad database configuration: %v", err)
  191. panic(err)
  192. // maybe os.Exit(1) instead
  193. }
  194. switch {
  195. case match(p, "/api/loans", &args):
  196. resp, err := getLoanType(db, 0, 0, true)
  197. if resp != nil {
  198. json.NewEncoder(w).Encode(resp)
  199. } else {
  200. json.NewEncoder(w).Encode(err)
  201. }
  202. case match(p, "/api/fees", &args):
  203. resp, err := getFees(db, 0)
  204. if resp != nil {
  205. json.NewEncoder(w).Encode(resp)
  206. } else {
  207. json.NewEncoder(w).Encode(err)
  208. }
  209. }
  210. }
  211. func main() {
  212. files := http.FileServer(http.Dir(""))
  213. http.Handle("/assets/", files)
  214. http.HandleFunc("/api/", api)
  215. http.HandleFunc("/", route)
  216. log.Fatal(http.ListenAndServe(address, nil))
  217. }