Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

3429 lignes
68 KiB

  1. package main
  2. import (
  3. "bytes"
  4. "database/sql"
  5. "encoding/base64"
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. _ "github.com/go-sql-driver/mysql"
  10. "html/template"
  11. "io"
  12. "log"
  13. "math"
  14. "net/http"
  15. "net/http/httputil"
  16. "net/mail"
  17. "net/url"
  18. "os"
  19. "os/exec"
  20. "regexp"
  21. "strconv"
  22. "strings"
  23. "sync"
  24. "time"
  25. // pdf "github.com/SebastiaanKlippert/go-wkhtmltopdf"
  26. "github.com/brianvoe/gofakeit/v6"
  27. "github.com/disintegration/gift"
  28. "github.com/dustin/go-humanize"
  29. "github.com/golang-jwt/jwt/v4"
  30. "github.com/stripe/stripe-go/v76"
  31. "github.com/stripe/stripe-go/v76/customer"
  32. "github.com/stripe/stripe-go/v76/subscription"
  33. // "github.com/stripe/stripe-go/v76/paymentintent"
  34. "image"
  35. _ "image/jpeg"
  36. "image/png"
  37. )
  38. type Config struct {
  39. DBName string
  40. DBUsername string
  41. DBPassword string
  42. }
  43. type Address struct {
  44. Id int `json:"id"`
  45. Full string `json:"full"`
  46. Street string `json:"street"`
  47. City string `json:"city"`
  48. Region string `json:"region"`
  49. Country string `json:"country"`
  50. Zip string `json:"zip"`
  51. }
  52. type Branch struct {
  53. Id int `json:"id"`
  54. Name string `json:"name"`
  55. Type string `json:"type"`
  56. Letterhead []byte `json:"letterhead"`
  57. Num string `json:"num"`
  58. Phone string `json:"phone"`
  59. Address Address `json:"address"`
  60. }
  61. type Subscription struct {
  62. Id int `json:"id"`
  63. UserId int `json:"userId"`
  64. StripeId string `json:"stripeId"`
  65. CustomerId string `json:"customerId"`
  66. Start int `json:"start"`
  67. End int `json:"end"`
  68. ClientSecret string `json:"clientSecret,omitempty"`
  69. }
  70. type User struct {
  71. Id int `json:"id"`
  72. Email string `json:"email"`
  73. FirstName string `json:"firstName"`
  74. LastName string `json:"lastName"`
  75. Phone string `json:"phone"`
  76. Address Address `json:"address"`
  77. Branch Branch `json:"branch"`
  78. License License `json:"license"`
  79. Sub Subscription `json:"sub"`
  80. Status string `json:"status"`
  81. Country string `json:"country"`
  82. Title string `json:"title"`
  83. Verified bool `json:"verified"`
  84. Role string `json:"role"`
  85. Password string `json:"password,omitempty"`
  86. CustomerId string `json:"customerId"`
  87. }
  88. type License struct {
  89. Id int `json:"id"`
  90. UserId int `json:"userId"`
  91. Type string `json:"type"`
  92. Num string `json:"num"`
  93. }
  94. type UserClaims struct {
  95. Id int `json:"id"`
  96. Role string `json:"role"`
  97. Exp string `json:"exp"`
  98. }
  99. type Page struct {
  100. tpl *template.Template
  101. Title string
  102. Name string
  103. }
  104. type Borrower struct {
  105. Id int `json:"id"`
  106. Credit int `json:"credit"`
  107. Income int `json:"income"`
  108. Num int `json:"num"`
  109. }
  110. type FeeTemplate struct {
  111. Id int `json:"id"`
  112. User int `json:"user"`
  113. Branch int `json:"branch"`
  114. Amount int `json:"amount"`
  115. Perc float32 `json:"perc"`
  116. Type string `json:"type"`
  117. Notes string `json:"notes"`
  118. Name string `json:"name"`
  119. Category string `json:"category"`
  120. Auto bool `json:"auto"`
  121. }
  122. type Fee struct {
  123. Id int `json:"id"`
  124. LoanId int `json:"loan_id"`
  125. Amount int `json:"amount"`
  126. Perc float32 `json:"perc"`
  127. Type string `json:"type"`
  128. Notes string `json:"notes"`
  129. Name string `json:"name"`
  130. Category string `json:"category"`
  131. }
  132. type LoanType struct {
  133. Id int `json:"id"`
  134. User int `json:"user"`
  135. Branch int `json:"branch"`
  136. Name string `json:"name"`
  137. }
  138. type Loan struct {
  139. Id int `json:"id"`
  140. EstimateId int `json:"estimateId"`
  141. Type LoanType `json:"type"`
  142. Amount int `json:"amount"`
  143. Amortization string `json:"amortization"`
  144. Term int `json:"term"`
  145. Ltv float32 `json:"ltv"`
  146. Dti float32 `json:"dti"`
  147. Hoi int `json:"hoi"`
  148. Hazard int `json:"hazard"`
  149. Tax int `json:"tax"`
  150. Interest float32 `json:"interest"`
  151. Mi MI `json:"mi"`
  152. Fees []Fee `json:"fees"`
  153. Credits []Fee // Fees with negative amounts for internal use
  154. Name string `json:"title"`
  155. Result Result `json:"result"`
  156. }
  157. type MI struct {
  158. Type string `json:"user"`
  159. Label string `json:"label"`
  160. Lender string `json:"lender"`
  161. Rate float32 `json:"rate"`
  162. Premium int `json:"premium"`
  163. Upfront int `json:"upfront"`
  164. Monthly bool `json:"monthly"`
  165. FiveYearTotal float32 `json:"fiveYearTotal"`
  166. InitialAllInPremium float32 `json:"initialAllInPremium"`
  167. InitialAllInRate float32 `json:"initialAllInRate"`
  168. InitialAmount float32 `json:"initialAmount"`
  169. }
  170. type Result struct {
  171. Id int `json:"id"`
  172. LoanId int `json:"loanId"`
  173. LoanPayment int `json:"loanPayment"`
  174. TotalMonthly int `json:"totalMonthly"`
  175. TotalFees int `json:"totalFees"`
  176. TotalCredits int `json:"totalCredits"`
  177. CashToClose int `json:"cashToClose"`
  178. }
  179. type Estimate struct {
  180. Id int `json:"id"`
  181. User int `json:"user"`
  182. Borrower Borrower `json:"borrower"`
  183. Transaction string `json:"transaction"`
  184. Price int `json:"price"`
  185. Property string `json:"property"`
  186. Occupancy string `json:"occupancy"`
  187. Zip string `json:"zip"`
  188. Pud bool `json:"pud"`
  189. Loans []Loan `json:"loans"`
  190. }
  191. type ETemplate struct {
  192. Id int `json:"id"`
  193. Estimate Estimate `json:"estimate"`
  194. UserId int `json:"userId"`
  195. BranchId int `json:"branchId"`
  196. }
  197. type Report struct {
  198. Title string
  199. Name string
  200. Avatar string
  201. Letterhead string
  202. User User
  203. Estimate Estimate
  204. }
  205. type Password struct {
  206. Old string `json:"old"`
  207. New string `json:"new"`
  208. }
  209. type Endpoint func(http.ResponseWriter, *sql.DB, *http.Request)
  210. var (
  211. regexen = make(map[string]*regexp.Regexp)
  212. relock sync.Mutex
  213. address = "localhost:8001"
  214. mainAddress = "localhost:8002"
  215. )
  216. var paths = map[string]string{
  217. "home": "views/home.tpl",
  218. "terms": "views/terms.tpl",
  219. "app": "views/app.tpl",
  220. "comparison": "views/report/comparison.tpl",
  221. }
  222. var pages = map[string]Page{
  223. "home": cache("home", "Home"),
  224. "terms": cache("terms", "Terms and Conditions"),
  225. "report": cachePdf("comparison"),
  226. "app": cache("app", "App"),
  227. }
  228. var roles = map[string]int{
  229. "User": 1,
  230. "Manager": 2,
  231. "Admin": 3,
  232. }
  233. var propertyTypes = []string{
  234. "Single Detached",
  235. "Single Attached",
  236. "Condo Lo-rise",
  237. "Condo Hi-rise",
  238. }
  239. var feeTypes = []string{
  240. "Government",
  241. "Title",
  242. "Required",
  243. "Lender",
  244. "Other",
  245. }
  246. // Used to validate claim in JWT token body. Checks if user id is greater than
  247. // zero and time format is valid
  248. func (c UserClaims) Valid() error {
  249. if c.Id < 1 {
  250. return errors.New("Invalid id")
  251. }
  252. t, err := time.Parse(time.UnixDate, c.Exp)
  253. if err != nil {
  254. return err
  255. }
  256. if t.Before(time.Now()) {
  257. return errors.New("Token expired.")
  258. }
  259. return err
  260. }
  261. func cache(name string, title string) Page {
  262. var p = []string{"views/master.tpl", paths[name]}
  263. tpl := template.Must(template.ParseFiles(p...))
  264. return Page{tpl: tpl, Title: title, Name: name}
  265. }
  266. func cachePdf(name string) Page {
  267. // Money is stored in cents, so it must be converted to dollars in reports
  268. dollars := func(cents int) string {
  269. return humanize.Commaf(float64(cents) / 100)
  270. }
  271. // For calculating down payments
  272. diff := func(a, b int) string {
  273. return humanize.Commaf(float64(b-a) / 100)
  274. }
  275. sortFees := func(ftype string, fees []Fee) []Fee {
  276. result := make([]Fee, 0)
  277. for i := range fees {
  278. if fees[i].Type != ftype {
  279. continue
  280. }
  281. result = append(result, fees[i])
  282. }
  283. return result
  284. }
  285. fm := template.FuncMap{
  286. "dollars": dollars,
  287. "diff": diff,
  288. "sortFees": sortFees}
  289. var p = []string{"views/report/master.tpl",
  290. "views/report/header.tpl",
  291. "views/report/summary.tpl",
  292. "views/report/comparison.tpl"}
  293. tpl := template.Must(template.New("master.tpl").Funcs(fm).ParseFiles(p...))
  294. return Page{tpl: tpl, Title: "", Name: name}
  295. }
  296. func (page Page) Render(w http.ResponseWriter) {
  297. err := page.tpl.Execute(w, page)
  298. if err != nil {
  299. log.Print(err)
  300. }
  301. }
  302. func match(path, pattern string, args *[]string) bool {
  303. relock.Lock()
  304. defer relock.Unlock()
  305. regex := regexen[pattern]
  306. if regex == nil {
  307. regex = regexp.MustCompile("^" + pattern + "$")
  308. regexen[pattern] = regex
  309. }
  310. matches := regex.FindStringSubmatch(path)
  311. if len(matches) <= 0 {
  312. return false
  313. }
  314. *args = matches[1:]
  315. return true
  316. }
  317. func (estimate *Estimate) makeResults() []Result {
  318. var results []Result
  319. amortize := func(principle float64, rate float64, periods float64) int {
  320. exp := math.Pow(1+rate, periods)
  321. return int(principle * rate * exp / (exp - 1))
  322. }
  323. for i := range estimate.Loans {
  324. var loan = &estimate.Loans[i]
  325. var result Result = Result{}
  326. // Monthly payments use amortized loan payment formula plus monthly MI,
  327. // plus all other recurring fees
  328. result.LoanPayment = amortize(float64(loan.Amount),
  329. float64(loan.Interest/100/12),
  330. float64(loan.Term*12))
  331. result.TotalMonthly = result.LoanPayment + loan.Hoi + loan.Tax + loan.Hazard
  332. if loan.Mi.Monthly {
  333. result.TotalMonthly = result.TotalMonthly +
  334. int(loan.Mi.Rate/100/12*float32(loan.Amount))
  335. } else {
  336. loan.Mi.Upfront = int(loan.Mi.Rate / 100 * float32(loan.Amount))
  337. }
  338. for i := range loan.Fees {
  339. if loan.Fees[i].Amount > 0 {
  340. result.TotalFees = result.TotalFees + loan.Fees[i].Amount
  341. } else {
  342. result.TotalCredits = result.TotalCredits + loan.Fees[i].Amount
  343. }
  344. }
  345. result.CashToClose =
  346. result.TotalFees + result.TotalCredits + (estimate.Price - loan.Amount)
  347. result.LoanId = loan.Id
  348. loan.Result = result
  349. results = append(results, result)
  350. }
  351. return results
  352. }
  353. func summarize(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  354. var estimate Estimate
  355. err := json.NewDecoder(r.Body).Decode(&estimate)
  356. if err != nil {
  357. http.Error(w, "Invalid estimate.", 422)
  358. return
  359. }
  360. estimate.makeResults()
  361. json.NewEncoder(w).Encode(estimate)
  362. }
  363. func getLoanType(db *sql.DB, id int) (LoanType, error) {
  364. types, err := getLoanTypes(db, id, 0, 0)
  365. if err != nil {
  366. return LoanType{Id: id}, err
  367. }
  368. if len(types) == 0 {
  369. return LoanType{Id: id}, errors.New("No type with that id")
  370. }
  371. return types[0], nil
  372. }
  373. func getLoanTypes(db *sql.DB, id int, user int, branch int) (
  374. []LoanType, error) {
  375. var loans []LoanType
  376. var query = `SELECT
  377. id,
  378. coalesce(user_id, 0),
  379. coalesce(branch_id, 0),
  380. name
  381. FROM loan_type WHERE loan_type.id = CASE @e := ? WHEN 0 THEN id ELSE @e END
  382. OR
  383. loan_type.user_id = CASE @e := ? WHEN 0 THEN id ELSE @e END
  384. OR
  385. loan_type.branch_id = CASE @e := ? WHEN 0 THEN id ELSE @e END`
  386. // Should be changed to specify user
  387. rows, err := db.Query(query, id, user, branch)
  388. if err != nil {
  389. return nil, fmt.Errorf("loan_type error: %v", err)
  390. }
  391. defer rows.Close()
  392. for rows.Next() {
  393. var loan LoanType
  394. if err := rows.Scan(
  395. &loan.Id,
  396. &loan.User,
  397. &loan.Branch,
  398. &loan.Name); err != nil {
  399. log.Printf("Error occured fetching loan: %v", err)
  400. return nil, fmt.Errorf("Error occured fetching loan: %v", err)
  401. }
  402. loans = append(loans, loan)
  403. }
  404. return loans, nil
  405. }
  406. func getFees(db *sql.DB, loan int) ([]Fee, error) {
  407. var fees []Fee
  408. query := `SELECT id, loan_id, amount, perc, type, notes, name, category
  409. FROM fee
  410. WHERE loan_id = ?`
  411. rows, err := db.Query(query, loan)
  412. if err != nil {
  413. return nil, fmt.Errorf("Fee query error %v", err)
  414. }
  415. defer rows.Close()
  416. for rows.Next() {
  417. var fee Fee
  418. if err := rows.Scan(
  419. &fee.Id,
  420. &fee.LoanId,
  421. &fee.Amount,
  422. &fee.Perc,
  423. &fee.Type,
  424. &fee.Notes,
  425. &fee.Name,
  426. &fee.Category,
  427. ); err != nil {
  428. return nil, fmt.Errorf("Fees scanning error: %v", err)
  429. }
  430. fees = append(fees, fee)
  431. }
  432. return fees, nil
  433. }
  434. func fetchFeesTemp(db *sql.DB, user int, branch int) ([]FeeTemplate, error) {
  435. var fees []FeeTemplate
  436. query := `SELECT
  437. id, user_id, COALESCE(branch_id, 0), amount, perc, type, notes, name,
  438. category, auto
  439. FROM fee_template
  440. WHERE user_id = ? OR branch_id = ?
  441. `
  442. rows, err := db.Query(query, user, branch)
  443. if err != nil {
  444. return nil, fmt.Errorf("Fee template query error %v", err)
  445. }
  446. defer rows.Close()
  447. for rows.Next() {
  448. var fee FeeTemplate
  449. if err := rows.Scan(
  450. &fee.Id,
  451. &fee.User,
  452. &fee.Branch,
  453. &fee.Amount,
  454. &fee.Perc,
  455. &fee.Type,
  456. &fee.Notes,
  457. &fee.Name,
  458. &fee.Category,
  459. &fee.Auto); err != nil {
  460. return nil, fmt.Errorf("FeesTemplate scanning error: %v", err)
  461. }
  462. fees = append(fees, fee)
  463. }
  464. return fees, nil
  465. }
  466. // Fetch fees from the database
  467. func getFeesTemp(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  468. var fees []FeeTemplate
  469. claims, err := getClaims(r)
  470. if err != nil {
  471. w.WriteHeader(500)
  472. return
  473. }
  474. user, err := queryUser(db, claims.Id)
  475. if err != nil {
  476. w.WriteHeader(422)
  477. return
  478. }
  479. fees, err = fetchFeesTemp(db, claims.Id, user.Branch.Id)
  480. json.NewEncoder(w).Encode(fees)
  481. }
  482. // Fetch fees from the database
  483. func createFeesTemp(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  484. var fee FeeTemplate
  485. var query string
  486. var row *sql.Row
  487. var err error
  488. claims, err := getClaims(r)
  489. // var id int // Inserted estimate's id
  490. err = json.NewDecoder(r.Body).Decode(&fee)
  491. if err != nil {
  492. w.WriteHeader(422)
  493. return
  494. }
  495. query = `INSERT INTO fee_template
  496. (
  497. user_id,
  498. branch_id,
  499. amount,
  500. perc,
  501. type,
  502. notes,
  503. name,
  504. auto
  505. )
  506. VALUES (?, NULL, ?, ?, ?, ?, ?, ?)
  507. RETURNING id
  508. `
  509. row = db.QueryRow(query,
  510. claims.Id,
  511. fee.Amount,
  512. fee.Perc,
  513. fee.Type,
  514. fee.Notes,
  515. fee.Name,
  516. fee.Auto,
  517. )
  518. err = row.Scan(&fee.Id)
  519. if err != nil {
  520. w.WriteHeader(500)
  521. return
  522. }
  523. json.NewEncoder(w).Encode(fee)
  524. }
  525. // Fetch fees from the database
  526. func deleteFeeTemp(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  527. var fee FeeTemplate
  528. var query string
  529. var err error
  530. // claims, err := getClaims(r)
  531. // var id int // Inserted estimate's id
  532. err = json.NewDecoder(r.Body).Decode(&fee)
  533. if err != nil {
  534. w.WriteHeader(422)
  535. return
  536. }
  537. query = `DELETE FROM fee_template WHERE id = ?`
  538. _, err = db.Exec(query, fee.Id)
  539. if err != nil {
  540. w.WriteHeader(500)
  541. return
  542. }
  543. }
  544. func deleteEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  545. var estimate Estimate
  546. var err error
  547. err = json.NewDecoder(r.Body).Decode(&estimate)
  548. if err != nil {
  549. w.WriteHeader(422)
  550. return
  551. }
  552. claims, err := getClaims(r)
  553. err = estimate.del(db, claims.Id)
  554. if err != nil {
  555. http.Error(w, err.Error(), 500)
  556. return
  557. }
  558. }
  559. func deleteET(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  560. var et ETemplate
  561. var err error
  562. err = json.NewDecoder(r.Body).Decode(&et)
  563. if err != nil {
  564. w.WriteHeader(422)
  565. return
  566. }
  567. claims, err := getClaims(r)
  568. err = et.del(db, claims.Id)
  569. if err != nil {
  570. http.Error(w, err.Error(), 500)
  571. return
  572. }
  573. }
  574. func getMi(db *sql.DB, loan int) (MI, error) {
  575. var mi MI
  576. query := `SELECT
  577. type, label, lender, rate, premium, upfront, five_year_total,
  578. initial_premium, initial_rate, initial_amount
  579. FROM mi WHERE loan_id = ?`
  580. rows, err := db.Query(query, loan)
  581. if err != nil {
  582. return mi, err
  583. }
  584. defer rows.Close()
  585. if !rows.Next() {
  586. return mi, nil
  587. }
  588. if err := rows.Scan(
  589. &mi.Type,
  590. &mi.Label,
  591. &mi.Lender,
  592. &mi.Rate,
  593. &mi.Premium,
  594. &mi.Upfront,
  595. &mi.FiveYearTotal,
  596. &mi.InitialAllInPremium,
  597. &mi.InitialAllInRate,
  598. &mi.InitialAmount,
  599. ); err != nil {
  600. return mi, err
  601. }
  602. return mi, nil
  603. }
  604. func (estimate *Estimate) getBorrower(db *sql.DB) error {
  605. query := `SELECT id, credit_score, monthly_income, num FROM borrower
  606. WHERE estimate_id = ? LIMIT 1`
  607. row := db.QueryRow(query, estimate.Id)
  608. if err := row.Scan(
  609. &estimate.Borrower.Id,
  610. &estimate.Borrower.Credit,
  611. &estimate.Borrower.Income,
  612. &estimate.Borrower.Num,
  613. ); err != nil {
  614. return fmt.Errorf("Borrower scanning error: %v", err)
  615. }
  616. return nil
  617. }
  618. // Query Lender APIs and parse responses into MI structs
  619. func fetchMi(db *sql.DB, estimate *Estimate, pos int) []MI {
  620. var loan Loan = estimate.Loans[pos]
  621. var ltv = func(l float32) string {
  622. switch {
  623. case l > 95:
  624. return "LTV97"
  625. case l > 90:
  626. return "LTV95"
  627. case l > 85:
  628. return "LTV90"
  629. default:
  630. return "LTV85"
  631. }
  632. }
  633. var term = func(t int) string {
  634. switch {
  635. case t <= 10:
  636. return "A10"
  637. case t <= 15:
  638. return "A15"
  639. case t <= 20:
  640. return "A20"
  641. case t <= 25:
  642. return "A25"
  643. case t <= 30:
  644. return "A30"
  645. default:
  646. return "A40"
  647. }
  648. }
  649. var propertyCodes = map[string]string{
  650. "Single Attached": "SFO",
  651. "Single Detached": "SFO",
  652. "Condo Lo-rise": "CON",
  653. "Condo Hi-rise": "CON",
  654. }
  655. var purposeCodes = map[string]string{
  656. "Purchase": "PUR",
  657. "Refinance": "RRT",
  658. }
  659. body, err := json.Marshal(map[string]any{
  660. "zipCode": estimate.Zip,
  661. "stateCode": "CA",
  662. "address": "",
  663. "propertyTypeCode": propertyCodes[estimate.Property],
  664. "occupancyTypeCode": "PRS",
  665. "loanPurposeCode": purposeCodes[estimate.Transaction],
  666. "loanAmount": loan.Amount,
  667. "loanToValue": ltv(loan.Ltv),
  668. "amortizationTerm": term(loan.Term),
  669. "loanTypeCode": "FXD",
  670. "duLpDecisionCode": "DAE",
  671. "loanProgramCodes": []any{},
  672. "debtToIncome": loan.Dti,
  673. "wholesaleLoan": 0,
  674. "coveragePercentageCode": "L30",
  675. "productCode": "BPM",
  676. "renewalTypeCode": "CON",
  677. "numberOfBorrowers": 1,
  678. "coBorrowerCreditScores": []any{},
  679. "borrowerCreditScore": strconv.Itoa(estimate.Borrower.Credit),
  680. "masterPolicy": nil,
  681. "selfEmployedIndicator": false,
  682. "armType": "",
  683. "userId": 44504,
  684. })
  685. /*
  686. if err != nil {
  687. log.Printf("Could not marshal NationalMI body: \n%v\n%v\n",
  688. bytes.NewBuffer(body), err)
  689. func queryAddress(db *sql.DB, id int) ( Address, error ) {
  690. var address Address = Address{Id: id}
  691. var err error
  692. row := db.QueryRow(
  693. `SELECT id, full_address, street, city, region, country, zip
  694. FROM address WHERE id = ?`, id)
  695. err = row.Scan(
  696. &address.Id,
  697. &address.Full,
  698. &address.Street,
  699. &address.City,
  700. &address.Region,
  701. &address.Country,
  702. &address.Zip,
  703. )
  704. return address, err
  705. }
  706. }
  707. */
  708. req, err := http.NewRequest("POST",
  709. "https://rate-gps.nationalmi.com/rates/productRateQuote",
  710. bytes.NewBuffer(body))
  711. req.Header.Add("Content-Type", "application/json")
  712. req.AddCookie(&http.Cookie{
  713. Name: "nmirategps_email",
  714. Value: os.Getenv("NationalMIEmail")})
  715. resp, err := http.DefaultClient.Do(req)
  716. var res map[string]interface{}
  717. var result []MI
  718. if resp.StatusCode != 200 {
  719. log.Printf("the status: %v\nthe resp: %v\n the req: %v\n the body: %v\n",
  720. resp.Status, resp, req.Body, bytes.NewBuffer(body))
  721. } else {
  722. json.NewDecoder(resp.Body).Decode(&res)
  723. // estimate.Loans[pos].Mi = res
  724. // Parse res into result here
  725. }
  726. log.Println(err)
  727. return result
  728. }
  729. // Make comparison PDF
  730. func generatePDF(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  731. }
  732. func login(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  733. var id int
  734. var role string
  735. var err error
  736. var user User
  737. json.NewDecoder(r.Body).Decode(&user)
  738. row := db.QueryRow(
  739. `SELECT id, role FROM user WHERE email = ? AND password = sha2(?, 256)`,
  740. user.Email, user.Password,
  741. )
  742. err = row.Scan(&id, &role)
  743. if err != nil {
  744. http.Error(w, "Invalid Credentials.", http.StatusUnauthorized)
  745. return
  746. }
  747. token := jwt.NewWithClaims(jwt.SigningMethodHS256,
  748. UserClaims{Id: id, Role: role,
  749. Exp: time.Now().Add(time.Minute * 30).Format(time.UnixDate)})
  750. tokenStr, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
  751. if err != nil {
  752. log.Println("Token could not be signed: ", err, tokenStr)
  753. http.Error(w, "Token generation error.", http.StatusInternalServerError)
  754. return
  755. }
  756. cookie := http.Cookie{Name: "skouter",
  757. Value: tokenStr,
  758. Path: "/",
  759. Expires: time.Now().Add(time.Hour * 24)}
  760. http.SetCookie(w, &cookie)
  761. _, err = w.Write([]byte(tokenStr))
  762. if err != nil {
  763. http.Error(w,
  764. "Could not complete token write.",
  765. http.StatusInternalServerError)
  766. }
  767. }
  768. func getToken(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  769. claims, err := getClaims(r)
  770. // Will verify existing signature and expiry time
  771. token := jwt.NewWithClaims(jwt.SigningMethodHS256,
  772. UserClaims{Id: claims.Id, Role: claims.Role,
  773. Exp: time.Now().Add(time.Minute * 30).Format(time.UnixDate)})
  774. tokenStr, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
  775. if err != nil {
  776. log.Println("Token could not be signed: ", err, tokenStr)
  777. http.Error(w, "Token generation error.", http.StatusInternalServerError)
  778. return
  779. }
  780. cookie := http.Cookie{Name: "skouter",
  781. Value: tokenStr,
  782. Path: "/",
  783. Expires: time.Now().Add(time.Hour * 24)}
  784. http.SetCookie(w, &cookie)
  785. _, err = w.Write([]byte(tokenStr))
  786. if err != nil {
  787. http.Error(w,
  788. "Could not complete token write.",
  789. http.StatusInternalServerError)
  790. }
  791. }
  792. func getClaims(r *http.Request) (UserClaims, error) {
  793. claims := new(UserClaims)
  794. _, tokenStr, found := strings.Cut(r.Header.Get("Authorization"), " ")
  795. if !found {
  796. return *claims, errors.New("Token not found")
  797. }
  798. // Pull token payload into UserClaims
  799. _, err := jwt.ParseWithClaims(tokenStr, claims,
  800. func(token *jwt.Token) (any, error) {
  801. return []byte(os.Getenv("JWT_SECRET")), nil
  802. })
  803. if err != nil {
  804. return *claims, err
  805. }
  806. if err = claims.Valid(); err != nil {
  807. return *claims, err
  808. }
  809. return *claims, nil
  810. }
  811. func guard(r *http.Request, required int) bool {
  812. claims, err := getClaims(r)
  813. if err != nil {
  814. return false
  815. }
  816. if roles[claims.Role] < required {
  817. return false
  818. }
  819. return true
  820. }
  821. // Inserts an address and returns it's ID along with any errors.
  822. func insertAddress(db *sql.DB, address Address) (int, error) {
  823. var query string
  824. var row *sql.Row
  825. var err error
  826. var id int // Inserted user's id
  827. query = `INSERT INTO address
  828. (
  829. full_address,
  830. street,
  831. city,
  832. region,
  833. country,
  834. zip
  835. )
  836. VALUES (?, ?, ?, ?, ?, ?)
  837. RETURNING id
  838. `
  839. row = db.QueryRow(query,
  840. address.Full,
  841. address.Street,
  842. address.City,
  843. address.Region,
  844. address.Country,
  845. address.Zip,
  846. )
  847. err = row.Scan(&id)
  848. return id, err
  849. }
  850. // Inserts an address and returns it's ID along with any errors.
  851. func insertBranch(db *sql.DB, branch Branch) (int, error) {
  852. var query string
  853. var row *sql.Row
  854. var err error
  855. var id int // Inserted user's id
  856. query = `INSERT INTO branch
  857. (
  858. name,
  859. type,
  860. letterhead,
  861. num,
  862. phone,
  863. address
  864. )
  865. VALUES (?, ?, ?, ?, ?, ?)
  866. RETURNING id
  867. `
  868. row = db.QueryRow(query,
  869. branch.Name,
  870. branch.Type,
  871. branch.Letterhead,
  872. branch.Num,
  873. branch.Phone,
  874. branch.Address.Id,
  875. )
  876. err = row.Scan(&id)
  877. return id, err
  878. }
  879. // Inserts an address and returns it's ID along with any errors.
  880. func insertLicense(db *sql.DB, license License) (int, error) {
  881. var query string
  882. var row *sql.Row
  883. var err error
  884. var id int // Inserted license's id
  885. query = `INSERT INTO license
  886. (
  887. user_id,
  888. type,
  889. num
  890. )
  891. VALUES (?, ?, ?)
  892. RETURNING id
  893. `
  894. row = db.QueryRow(query,
  895. license.UserId,
  896. license.Type,
  897. license.Num,
  898. )
  899. err = row.Scan(&id)
  900. return id, err
  901. }
  902. func queryLicense(db *sql.DB, user int) (License, error) {
  903. var license License = License{UserId: user}
  904. var err error
  905. row := db.QueryRow(
  906. `SELECT id, type, num FROM license WHERE user_id = ?`,
  907. user)
  908. err = row.Scan(
  909. &license.Id,
  910. &license.Type,
  911. &license.Num,
  912. )
  913. return license, err
  914. }
  915. func queryAddress(db *sql.DB, id int) (Address, error) {
  916. var address Address = Address{Id: id}
  917. var err error
  918. row := db.QueryRow(
  919. `SELECT id, full_address, street, city, region, country, zip
  920. FROM address WHERE id = ?`, id)
  921. err = row.Scan(
  922. &address.Id,
  923. &address.Full,
  924. &address.Street,
  925. &address.City,
  926. &address.Region,
  927. &address.Country,
  928. &address.Zip,
  929. )
  930. return address, err
  931. }
  932. func queryBranch(db *sql.DB, id int) (Branch, error) {
  933. var branch Branch = Branch{Id: id}
  934. var err error
  935. row := db.QueryRow(
  936. `SELECT id, name, type, letterhead, num, phone, address
  937. FROM branch WHERE id = ?`, id)
  938. err = row.Scan(
  939. &branch.Id,
  940. &branch.Name,
  941. &branch.Type,
  942. &branch.Letterhead,
  943. &branch.Num,
  944. &branch.Phone,
  945. &branch.Address.Id,
  946. )
  947. return branch, err
  948. }
  949. func queryUser(db *sql.DB, id int) (User, error) {
  950. var user User
  951. var query string
  952. var err error
  953. query = `SELECT
  954. u.id,
  955. u.email,
  956. u.first_name,
  957. u.last_name,
  958. coalesce(u.branch_id, 0),
  959. u.country,
  960. u.title,
  961. coalesce(u.status, ''),
  962. coalesce(u.customer_id, ''),
  963. u.verified,
  964. u.role,
  965. u.address,
  966. u.phone
  967. FROM user u WHERE u.id = ?
  968. `
  969. row := db.QueryRow(query, id)
  970. if err != nil {
  971. return user, err
  972. }
  973. err = row.Scan(
  974. &user.Id,
  975. &user.Email,
  976. &user.FirstName,
  977. &user.LastName,
  978. &user.Branch.Id,
  979. &user.Country,
  980. &user.Title,
  981. &user.Status,
  982. &user.CustomerId,
  983. &user.Verified,
  984. &user.Role,
  985. &user.Address.Id,
  986. &user.Phone,
  987. )
  988. if err != nil {
  989. return user, err
  990. }
  991. user.Address, err = queryAddress(db, user.Address.Id)
  992. if err != nil {
  993. return user, err
  994. }
  995. user.Branch, err = queryBranch(db, user.Branch.Id)
  996. if err != nil {
  997. return user, err
  998. }
  999. return user, nil
  1000. }
  1001. // Can probably be deleted.
  1002. func queryUsers(db *sql.DB, id int) ([]User, error) {
  1003. var users []User
  1004. var query string
  1005. var rows *sql.Rows
  1006. var err error
  1007. query = `SELECT
  1008. u.id,
  1009. u.email,
  1010. u.first_name,
  1011. u.last_name,
  1012. coalesce(u.branch_id, 0),
  1013. u.country,
  1014. u.title,
  1015. coalesce(u.status, ''),
  1016. u.verified,
  1017. u.role,
  1018. u.address,
  1019. u.phone
  1020. FROM user u WHERE u.id = CASE @e := ? WHEN 0 THEN u.id ELSE @e END
  1021. `
  1022. rows, err = db.Query(query, id)
  1023. if err != nil {
  1024. return users, err
  1025. }
  1026. defer rows.Close()
  1027. for rows.Next() {
  1028. var user User
  1029. if err := rows.Scan(
  1030. &user.Id,
  1031. &user.Email,
  1032. &user.FirstName,
  1033. &user.LastName,
  1034. &user.Branch.Id,
  1035. &user.Country,
  1036. &user.Title,
  1037. &user.Status,
  1038. &user.Verified,
  1039. &user.Role,
  1040. &user.Address.Id,
  1041. &user.Phone,
  1042. ); err != nil {
  1043. return users, err
  1044. }
  1045. user.Address, err = queryAddress(db, user.Address.Id)
  1046. if err != nil {
  1047. return users, err
  1048. }
  1049. user.Branch, err = queryBranch(db, user.Branch.Id)
  1050. if err != nil {
  1051. return users, err
  1052. }
  1053. users = append(users, user)
  1054. }
  1055. // Prevents runtime panics
  1056. if len(users) == 0 {
  1057. return users, errors.New("User not found.")
  1058. }
  1059. return users, nil
  1060. }
  1061. func querySub(db *sql.DB, id int) (Subscription, error) {
  1062. var query string
  1063. var err error
  1064. var s Subscription
  1065. query = `SELECT
  1066. id,
  1067. stripe_id,
  1068. user_id,
  1069. customer_id,
  1070. current_period_end,
  1071. current_period_start
  1072. FROM subscription WHERE id = ?
  1073. `
  1074. row := db.QueryRow(query, id)
  1075. err = row.Scan(
  1076. &s.Id,
  1077. &s.StripeId,
  1078. &s.CustomerId,
  1079. &s.End,
  1080. &s.Start,
  1081. )
  1082. return s, err
  1083. }
  1084. func (user *User) querySub(db *sql.DB) error {
  1085. var query string
  1086. var err error
  1087. query = `SELECT
  1088. id,
  1089. stripe_id,
  1090. user_id,
  1091. customer_id,
  1092. current_period_end,
  1093. current_period_start
  1094. FROM subscription WHERE user_id = ?
  1095. `
  1096. row := db.QueryRow(query, user.Id)
  1097. err = row.Scan(
  1098. &user.Sub.Id,
  1099. &user.Sub.StripeId,
  1100. &user.Sub.UserId,
  1101. &user.Sub.CustomerId,
  1102. &user.Sub.End,
  1103. &user.Sub.Start,
  1104. )
  1105. return err
  1106. }
  1107. func (estimate *Estimate) insertResults(db *sql.DB) error {
  1108. var query string
  1109. var row *sql.Row
  1110. var err error
  1111. var id int
  1112. query = `INSERT INTO estimate_result
  1113. (
  1114. loan_id,
  1115. loan_payment,
  1116. total_monthly,
  1117. total_fees,
  1118. total_credits,
  1119. cash_to_close
  1120. )
  1121. VALUES (?, ?, ?, ?, ?, ?)
  1122. RETURNING id
  1123. `
  1124. for i := range estimate.Loans {
  1125. r := estimate.Loans[i].Result
  1126. r.LoanId = estimate.Loans[i].Id
  1127. row = db.QueryRow(query,
  1128. r.LoanId,
  1129. r.LoanPayment,
  1130. r.TotalMonthly,
  1131. r.TotalFees,
  1132. r.TotalCredits,
  1133. r.CashToClose,
  1134. )
  1135. err = row.Scan(&id)
  1136. if err != nil {
  1137. return err
  1138. }
  1139. r.Id = id
  1140. }
  1141. return nil
  1142. }
  1143. // Insert user returning it's ID or any error
  1144. func insertUser(db *sql.DB, user User) (int, error) {
  1145. var query string
  1146. var row *sql.Row
  1147. var err error
  1148. var id int // Inserted user's id
  1149. user.Address.Id, err = insertAddress(db, user.Address)
  1150. if err != nil {
  1151. return 0, err
  1152. }
  1153. query = `INSERT INTO user
  1154. (
  1155. email,
  1156. first_name,
  1157. last_name,
  1158. password,
  1159. role,
  1160. title,
  1161. status,
  1162. verified,
  1163. address,
  1164. country,
  1165. branch_id,
  1166. phone,
  1167. created,
  1168. last_login
  1169. )
  1170. VALUES (?, ?, ?, sha2(?, 256), ?, ?, ?, ?, ?, ?,
  1171. CASE @b := ? WHEN 0 THEN NULL ELSE @b END,
  1172. ?, NOW(), NOW())
  1173. RETURNING id
  1174. `
  1175. row = db.QueryRow(query,
  1176. user.Email,
  1177. user.FirstName,
  1178. user.LastName,
  1179. user.Password,
  1180. user.Role,
  1181. user.Title,
  1182. user.Status,
  1183. user.Verified,
  1184. user.Address.Id,
  1185. user.Country,
  1186. user.Branch.Id,
  1187. user.Phone,
  1188. )
  1189. err = row.Scan(&id)
  1190. if err != nil {
  1191. return 0, err
  1192. }
  1193. user.Id = id
  1194. return id, nil
  1195. }
  1196. // Insert user returning it's ID or any error
  1197. func (sub *Subscription) insertSub(db *sql.DB) (error) {
  1198. var query string
  1199. var err error
  1200. query = `INSERT INTO subscription
  1201. (
  1202. stripe_id,
  1203. user_id,
  1204. customer_id,
  1205. current_period_end,
  1206. current_period_start
  1207. )
  1208. VALUES (?, ?, ?, ?, ?)
  1209. `
  1210. _, err = db.Exec(query,
  1211. sub.StripeId,
  1212. sub.UserId,
  1213. sub.CustomerId,
  1214. sub.End,
  1215. sub.Start,
  1216. )
  1217. return err
  1218. }
  1219. // Updates a user's stripe customer ID.
  1220. func (user *User) updateCustomerId(db *sql.DB, cid string) (error) {
  1221. var query string
  1222. var err error
  1223. query = `UPDATE user SET
  1224. customer_id = ?
  1225. WHERE id = ?
  1226. `
  1227. _, err = db.Exec(query,
  1228. cid,
  1229. user.Id,
  1230. )
  1231. return err
  1232. }
  1233. func updateAddress(address Address, db *sql.DB) error {
  1234. query := `
  1235. UPDATE address
  1236. SET
  1237. full_address = CASE @e := ? WHEN '' THEN full_address ELSE @e END,
  1238. street = CASE @fn := ? WHEN '' THEN street ELSE @fn END,
  1239. city = CASE @ln := ? WHEN '' THEN city ELSE @ln END,
  1240. region = CASE @r := ? WHEN '' THEN region ELSE @r END,
  1241. country = CASE @r := ? WHEN '' THEN country ELSE @r END,
  1242. zip = CASE @r := ? WHEN '' THEN zip ELSE @r END
  1243. WHERE id = ?
  1244. `
  1245. _, err := db.Exec(query,
  1246. address.Full,
  1247. address.Street,
  1248. address.City,
  1249. address.Region,
  1250. address.Country,
  1251. address.Zip,
  1252. address.Id,
  1253. )
  1254. return err
  1255. }
  1256. func updateUser(user User, db *sql.DB) error {
  1257. query := `
  1258. UPDATE user
  1259. SET
  1260. email = CASE @e := ? WHEN '' THEN email ELSE @e END,
  1261. first_name = CASE @fn := ? WHEN '' THEN first_name ELSE @fn END,
  1262. last_name = CASE @ln := ? WHEN '' THEN last_name ELSE @ln END,
  1263. role = CASE @r := ? WHEN '' THEN role ELSE @r END,
  1264. password = CASE @p := ? WHEN '' THEN password ELSE sha2(@p, 256) END
  1265. WHERE id = ?
  1266. `
  1267. _, err := db.Exec(query,
  1268. user.Email,
  1269. user.FirstName,
  1270. user.LastName,
  1271. user.Role,
  1272. user.Password,
  1273. user.Id,
  1274. )
  1275. return err
  1276. }
  1277. func getUser(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1278. claims, err := getClaims(r)
  1279. if err != nil {
  1280. w.WriteHeader(500)
  1281. return
  1282. }
  1283. user, err := queryUser(db, claims.Id)
  1284. if err != nil {
  1285. w.WriteHeader(422)
  1286. log.Println(err)
  1287. return
  1288. }
  1289. json.NewEncoder(w).Encode(user)
  1290. }
  1291. func getUsers(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1292. users, err := queryUsers(db, 0)
  1293. if err != nil {
  1294. w.WriteHeader(http.StatusInternalServerError)
  1295. return
  1296. }
  1297. json.NewEncoder(w).Encode(users)
  1298. }
  1299. // Updates a user using only specified values in the JSON body
  1300. func setUser(user User, db *sql.DB) error {
  1301. _, err := mail.ParseAddress(user.Email)
  1302. if err != nil {
  1303. return err
  1304. }
  1305. if roles[user.Role] == 0 {
  1306. return errors.New("Invalid role")
  1307. }
  1308. err = updateUser(user, db)
  1309. if err != nil {
  1310. return err
  1311. }
  1312. err = updateAddress(user.Address, db)
  1313. if err != nil {
  1314. return err
  1315. }
  1316. return nil
  1317. }
  1318. func patchUser(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1319. var user User
  1320. err := json.NewDecoder(r.Body).Decode(&user)
  1321. if err != nil {
  1322. http.Error(w, "Invalid fields", 422)
  1323. return
  1324. }
  1325. err = setUser(user, db)
  1326. if err != nil {
  1327. http.Error(w, err.Error(), 422)
  1328. return
  1329. }
  1330. }
  1331. // Update specified fields of the user specified in the claim
  1332. func patchSelf(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1333. claim, err := getClaims(r)
  1334. var user User
  1335. json.NewDecoder(r.Body).Decode(&user)
  1336. // First check that the target user to be updated is the same as the claim id, and
  1337. // their role is unchanged.
  1338. if err != nil || claim.Id != user.Id {
  1339. http.Error(w, "Target user's id does not match claim.", 401)
  1340. return
  1341. }
  1342. if claim.Role != user.Role && user.Role != "" {
  1343. http.Error(w, "Administrator required to escalate role.", 401)
  1344. return
  1345. }
  1346. err = setUser(user, db)
  1347. if err != nil {
  1348. http.Error(w, err.Error(), 422)
  1349. return
  1350. }
  1351. }
  1352. func deleteUser(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1353. var user User
  1354. err := json.NewDecoder(r.Body).Decode(&user)
  1355. if err != nil {
  1356. http.Error(w, "Invalid fields.", 422)
  1357. return
  1358. }
  1359. query := `DELETE FROM user WHERE id = ?`
  1360. _, err = db.Exec(query, user.Id)
  1361. if err != nil {
  1362. http.Error(w, "Could not delete.", 500)
  1363. }
  1364. }
  1365. // Checks if a user's entries are reasonable before database insertion.
  1366. // This function is very important because it is the only thing preventing
  1367. // anyone from creating an admin user. These error messages are displayed to
  1368. // the user.
  1369. func (user *User) validate() error {
  1370. _, err := mail.ParseAddress(user.Email)
  1371. if err != nil {
  1372. return errors.New("Invalid email.")
  1373. }
  1374. if roles[user.Role] == 0 {
  1375. return errors.New("Invalid role.")
  1376. }
  1377. if roles[user.Role] == roles["Admin"] {
  1378. return errors.New("New user cannot be an Admin.")
  1379. }
  1380. if user.FirstName == "" {
  1381. return errors.New("Given name cannot be empty.")
  1382. }
  1383. if user.LastName == "" {
  1384. return errors.New("Surname cannot be empty.")
  1385. }
  1386. if user.Password == "" {
  1387. return errors.New("Empty password")
  1388. }
  1389. return nil
  1390. }
  1391. func createUser(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1392. var user User
  1393. err := json.NewDecoder(r.Body).Decode(&user)
  1394. if err != nil {
  1395. http.Error(w, "Invalid fields.", 422)
  1396. return
  1397. }
  1398. user.Role = "User"
  1399. user.Status = "Trial"
  1400. err = user.validate()
  1401. if err != nil {
  1402. http.Error(w, err.Error(), 422)
  1403. return
  1404. }
  1405. user.Id, err = insertUser(db, user)
  1406. if err != nil {
  1407. http.Error(w, err.Error(), 422)
  1408. return
  1409. }
  1410. json.NewEncoder(w).Encode(user)
  1411. }
  1412. func checkPassword(db *sql.DB, id int, pass string) bool {
  1413. var p string
  1414. query := `SELECT
  1415. password
  1416. FROM user WHERE user.id = ? AND password = sha2(?, 256)
  1417. `
  1418. row := db.QueryRow(query, id, pass)
  1419. err := row.Scan(&p)
  1420. if err != nil {
  1421. return false
  1422. }
  1423. return true
  1424. }
  1425. func setPassword(db *sql.DB, id int, pass string) error {
  1426. query := `UPDATE user
  1427. SET password = sha2(?, 256)
  1428. WHERE user.id = ?
  1429. `
  1430. _, err := db.Exec(query, pass, id)
  1431. if err != nil {
  1432. return errors.New("Could not insert password.")
  1433. }
  1434. return nil
  1435. }
  1436. func changePassword(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1437. var pass Password
  1438. claim, err := getClaims(r)
  1439. err = json.NewDecoder(r.Body).Decode(&pass)
  1440. if err != nil {
  1441. http.Error(w, "Bad fields.", 422)
  1442. return
  1443. }
  1444. if checkPassword(db, claim.Id, pass.Old) {
  1445. err = setPassword(db, claim.Id, pass.New)
  1446. } else {
  1447. http.Error(w, "Incorrect old password.", 401)
  1448. return
  1449. }
  1450. if err != nil {
  1451. http.Error(w, err.Error(), 500)
  1452. return
  1453. }
  1454. }
  1455. func fetchAvatar(db *sql.DB, user int) ([]byte, error) {
  1456. var img []byte
  1457. var query string
  1458. var err error
  1459. query = `SELECT
  1460. avatar
  1461. FROM user WHERE user.id = ?
  1462. `
  1463. row := db.QueryRow(query, user)
  1464. err = row.Scan(&img)
  1465. if err != nil {
  1466. return img, err
  1467. }
  1468. return img, nil
  1469. }
  1470. func insertAvatar(db *sql.DB, user int, img []byte) error {
  1471. query := `UPDATE user
  1472. SET avatar = ?
  1473. WHERE id = ?
  1474. `
  1475. _, err := db.Exec(query, img, user)
  1476. if err != nil {
  1477. return err
  1478. }
  1479. return nil
  1480. }
  1481. func fetchLetterhead(db *sql.DB, user int) ([]byte, error) {
  1482. var img []byte
  1483. var query string
  1484. var err error
  1485. query = `SELECT
  1486. letterhead
  1487. FROM user WHERE user.id = ?
  1488. `
  1489. row := db.QueryRow(query, user)
  1490. err = row.Scan(&img)
  1491. if err != nil {
  1492. return img, err
  1493. }
  1494. return img, nil
  1495. }
  1496. func insertLetterhead(db *sql.DB, user int, img []byte) error {
  1497. query := `UPDATE user
  1498. SET letterhead = ?
  1499. WHERE id = ?
  1500. `
  1501. _, err := db.Exec(query, img, user)
  1502. if err != nil {
  1503. return err
  1504. }
  1505. return nil
  1506. }
  1507. func setAvatar(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1508. var validTypes []string = []string{"image/png", "image/jpeg"}
  1509. var isValidType bool
  1510. claims, err := getClaims(r)
  1511. if err != nil {
  1512. http.Error(w, "Invalid token.", 422)
  1513. return
  1514. }
  1515. img, err := io.ReadAll(r.Body)
  1516. if err != nil {
  1517. http.Error(w, "Invalid file.", 422)
  1518. return
  1519. }
  1520. for _, v := range validTypes {
  1521. if v == http.DetectContentType(img) {
  1522. isValidType = true
  1523. }
  1524. }
  1525. if !isValidType {
  1526. http.Error(w, "Invalid file type.", 422)
  1527. return
  1528. }
  1529. err = insertAvatar(db, claims.Id, img)
  1530. if err != nil {
  1531. http.Error(w, "Could not insert.", 500)
  1532. return
  1533. }
  1534. }
  1535. func getAvatar(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1536. claims, err := getClaims(r)
  1537. if err != nil {
  1538. http.Error(w, "Invalid token.", 422)
  1539. return
  1540. }
  1541. img, err := fetchAvatar(db, claims.Id)
  1542. if err != nil {
  1543. http.Error(w, "Could not retrieve.", 500)
  1544. return
  1545. }
  1546. w.Header().Set("Content-Type", http.DetectContentType(img))
  1547. w.Write(img)
  1548. }
  1549. func setLetterhead(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1550. var validTypes []string = []string{"image/png", "image/jpeg"}
  1551. var isValidType bool
  1552. claims, err := getClaims(r)
  1553. if err != nil {
  1554. http.Error(w, "Invalid token.", 422)
  1555. return
  1556. }
  1557. img, err := io.ReadAll(r.Body)
  1558. if err != nil {
  1559. http.Error(w, "Invalid file.", 422)
  1560. return
  1561. }
  1562. for _, v := range validTypes {
  1563. if v == http.DetectContentType(img) {
  1564. isValidType = true
  1565. }
  1566. }
  1567. if !isValidType {
  1568. http.Error(w, "Invalid file type.", 422)
  1569. return
  1570. }
  1571. err = insertLetterhead(db, claims.Id, img)
  1572. if err != nil {
  1573. http.Error(w, "Could not insert.", 500)
  1574. return
  1575. }
  1576. }
  1577. func getLetterhead(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  1578. claims, err := getClaims(r)
  1579. if err != nil {
  1580. http.Error(w, "Invalid token.", 422)
  1581. return
  1582. }
  1583. img, err := fetchLetterhead(db, claims.Id)
  1584. if err != nil {
  1585. http.Error(w, "Could not retrieve.", 500)
  1586. return
  1587. }
  1588. w.Header().Set("Content-Type", http.DetectContentType(img))
  1589. w.Write(img)
  1590. }
  1591. func queryBorrower(db *sql.DB, id int) (Borrower, error) {
  1592. var borrower Borrower
  1593. var query string
  1594. var err error
  1595. query = `SELECT
  1596. l.id,
  1597. l.credit_score,
  1598. l.num,
  1599. l.monthly_income
  1600. FROM borrower l WHERE l.id = ?
  1601. `
  1602. row := db.QueryRow(query, id)
  1603. err = row.Scan(
  1604. borrower.Id,
  1605. borrower.Credit,
  1606. borrower.Num,
  1607. borrower.Income,
  1608. )
  1609. if err != nil {
  1610. return borrower, err
  1611. }
  1612. return borrower, nil
  1613. }
  1614. // Must have an estimate ID 'e', but not necessarily a loan id 'id'
  1615. func getResults(db *sql.DB, e int, id int) ([]Result, error) {
  1616. var results []Result
  1617. var query string
  1618. var rows *sql.Rows
  1619. var err error
  1620. query = `SELECT
  1621. r.id,
  1622. loan_id,
  1623. loan_payment,
  1624. total_monthly,
  1625. total_fees,
  1626. total_credits,
  1627. cash_to_close
  1628. FROM estimate_result r
  1629. INNER JOIN loan
  1630. ON r.loan_id = loan.id
  1631. WHERE r.id = CASE @e := ? WHEN 0 THEN r.id ELSE @e END
  1632. AND loan.estimate_id = ?
  1633. `
  1634. rows, err = db.Query(query, id, e)
  1635. if err != nil {
  1636. return results, err
  1637. }
  1638. defer rows.Close()
  1639. for rows.Next() {
  1640. var result Result
  1641. if err := rows.Scan(
  1642. &result.Id,
  1643. &result.LoanId,
  1644. &result.LoanPayment,
  1645. &result.TotalMonthly,
  1646. &result.TotalFees,
  1647. &result.TotalCredits,
  1648. &result.CashToClose,
  1649. ); err != nil {
  1650. return results, err
  1651. }
  1652. results = append(results, result)
  1653. }
  1654. // Prevents runtime panics
  1655. // if len(results) == 0 { return results, errors.New("Result not found.") }
  1656. return results, nil
  1657. }
  1658. // Retrieve an estimate result with a specified loan id
  1659. func getResult(db *sql.DB, loan int) (Result, error) {
  1660. var result Result
  1661. var query string
  1662. var err error
  1663. query = `SELECT
  1664. r.id,
  1665. loan_id,
  1666. loan_payment,
  1667. total_monthly,
  1668. total_fees,
  1669. total_credits,
  1670. cash_to_close
  1671. FROM estimate_result r
  1672. INNER JOIN loan
  1673. ON r.loan_id = loan.id
  1674. WHERE loan.Id = ?
  1675. `
  1676. row := db.QueryRow(query, loan)
  1677. err = row.Scan(
  1678. &result.Id,
  1679. &result.LoanId,
  1680. &result.LoanPayment,
  1681. &result.TotalMonthly,
  1682. &result.TotalFees,
  1683. &result.TotalCredits,
  1684. &result.CashToClose,
  1685. )
  1686. if err != nil {
  1687. return result, err
  1688. }
  1689. return result, nil
  1690. }
  1691. // Must have an estimate ID 'e', but not necessarily a loan id 'id'
  1692. func getLoans(db *sql.DB, e int, id int) ([]Loan, error) {
  1693. var loans []Loan
  1694. var query string
  1695. var rows *sql.Rows
  1696. var err error
  1697. query = `SELECT
  1698. l.id,
  1699. l.type_id,
  1700. l.estimate_id,
  1701. l.amount,
  1702. l.term,
  1703. l.interest,
  1704. l.ltv,
  1705. l.dti,
  1706. l.hoi,
  1707. l.tax,
  1708. l.name
  1709. FROM loan l WHERE l.id = CASE @e := ? WHEN 0 THEN l.id ELSE @e END AND
  1710. l.estimate_id = ?
  1711. `
  1712. rows, err = db.Query(query, id, e)
  1713. if err != nil {
  1714. return loans, err
  1715. }
  1716. defer rows.Close()
  1717. for rows.Next() {
  1718. var loan Loan
  1719. if err := rows.Scan(
  1720. &loan.Id,
  1721. &loan.Type.Id,
  1722. &loan.EstimateId,
  1723. &loan.Amount,
  1724. &loan.Term,
  1725. &loan.Interest,
  1726. &loan.Ltv,
  1727. &loan.Dti,
  1728. &loan.Hoi,
  1729. &loan.Tax,
  1730. &loan.Name,
  1731. ); err != nil {
  1732. return loans, err
  1733. }
  1734. mi, err := getMi(db, loan.Id)
  1735. if err != nil {
  1736. return loans, err
  1737. }
  1738. loan.Mi = mi
  1739. fees, err := getFees(db, loan.Id)
  1740. if err != nil {
  1741. return loans, err
  1742. }
  1743. loan.Fees = fees
  1744. loan.Result, err = getResult(db, loan.Id)
  1745. if err != nil {
  1746. return loans, err
  1747. }
  1748. loan.Type, err = getLoanType(db, loan.Type.Id)
  1749. if err != nil {
  1750. return loans, err
  1751. }
  1752. loans = append(loans, loan)
  1753. }
  1754. // Prevents runtime panics
  1755. if len(loans) == 0 {
  1756. return loans, errors.New("Loan not found.")
  1757. }
  1758. return loans, nil
  1759. }
  1760. func getEstimate(db *sql.DB, id int) (Estimate, error) {
  1761. estimates, err := getEstimates(db, id, 0)
  1762. if err != nil {
  1763. return Estimate{}, err
  1764. }
  1765. return estimates[0], nil
  1766. }
  1767. func getEstimates(db *sql.DB, id int, user int) ([]Estimate, error) {
  1768. var estimates []Estimate
  1769. var query string
  1770. var rows *sql.Rows
  1771. var err error
  1772. query = `SELECT
  1773. id,
  1774. user_id,
  1775. transaction,
  1776. price,
  1777. property,
  1778. occupancy,
  1779. zip,
  1780. pud
  1781. FROM estimate WHERE id = CASE @e := ? WHEN 0 THEN id ELSE @e END AND
  1782. user_id = CASE @e := ? WHEN 0 THEN user_id ELSE @e END
  1783. `
  1784. rows, err = db.Query(query, id, user)
  1785. if err != nil {
  1786. return estimates, err
  1787. }
  1788. defer rows.Close()
  1789. for rows.Next() {
  1790. var estimate Estimate
  1791. if err := rows.Scan(
  1792. &estimate.Id,
  1793. &estimate.User,
  1794. &estimate.Transaction,
  1795. &estimate.Price,
  1796. &estimate.Property,
  1797. &estimate.Occupancy,
  1798. &estimate.Zip,
  1799. &estimate.Pud,
  1800. ); err != nil {
  1801. return estimates, err
  1802. }
  1803. err := estimate.getBorrower(db)
  1804. if err != nil {
  1805. return estimates, err
  1806. }
  1807. estimates = append(estimates, estimate)
  1808. }
  1809. // Prevents runtime panics
  1810. if len(estimates) == 0 {
  1811. return estimates, errors.New("Estimate not found.")
  1812. }
  1813. for i := range estimates {
  1814. estimates[i].Loans, err = getLoans(db, estimates[i].Id, 0)
  1815. if err != nil {
  1816. return estimates, err
  1817. }
  1818. }
  1819. return estimates, nil
  1820. }
  1821. func queryETemplates(db *sql.DB, id int, user int) ([]ETemplate, error) {
  1822. var eTemplates []ETemplate
  1823. var query string
  1824. var rows *sql.Rows
  1825. var err error
  1826. query = `SELECT
  1827. id,
  1828. estimate_id,
  1829. user_id,
  1830. branch_id
  1831. FROM estimate_template WHERE id = CASE @e := ? WHEN 0 THEN id ELSE @e END AND
  1832. user_id = CASE @e := ? WHEN 0 THEN user_id ELSE @e END
  1833. `
  1834. rows, err = db.Query(query, id, user)
  1835. if err != nil {
  1836. return eTemplates, err
  1837. }
  1838. defer rows.Close()
  1839. for rows.Next() {
  1840. var e ETemplate
  1841. if err := rows.Scan(
  1842. &e.Id,
  1843. &e.Estimate.Id,
  1844. &e.UserId,
  1845. &e.BranchId,
  1846. ); err != nil {
  1847. return eTemplates, err
  1848. }
  1849. e.Estimate, err = getEstimate(db, e.Estimate.Id)
  1850. if err != nil {
  1851. return eTemplates, err
  1852. }
  1853. eTemplates = append(eTemplates, e)
  1854. }
  1855. return eTemplates, nil
  1856. }
  1857. // Accepts a borrower struct and returns the id of the inserted borrower and
  1858. // any related error.
  1859. func (estimate *Estimate) insertETemplate(db *sql.DB, user int, branch int) error {
  1860. var query string
  1861. var err error
  1862. query = `INSERT INTO estimate_template
  1863. (
  1864. estimate_id,
  1865. user_id,
  1866. branch_id
  1867. )
  1868. VALUES (?, ?, ?)
  1869. `
  1870. _, err = db.Exec(query,
  1871. estimate.Id,
  1872. user,
  1873. branch,
  1874. )
  1875. if err != nil {
  1876. return err
  1877. }
  1878. return nil
  1879. }
  1880. // Accepts a borrower struct and returns the id of the inserted borrower and
  1881. // any related error.
  1882. func (estimate *Estimate) insertBorrower(db *sql.DB) error {
  1883. var query string
  1884. var row *sql.Row
  1885. var err error
  1886. query = `INSERT INTO borrower
  1887. (
  1888. estimate_id,
  1889. credit_score,
  1890. monthly_income,
  1891. num
  1892. )
  1893. VALUES (?, ?, ?, ?)
  1894. RETURNING id
  1895. `
  1896. row = db.QueryRow(query,
  1897. estimate.Id,
  1898. estimate.Borrower.Credit,
  1899. estimate.Borrower.Income,
  1900. estimate.Borrower.Num,
  1901. )
  1902. err = row.Scan(&estimate.Borrower.Id)
  1903. if err != nil {
  1904. return err
  1905. }
  1906. return nil
  1907. }
  1908. func insertMi(db *sql.DB, mi MI) (int, error) {
  1909. var id int
  1910. query := `INSERT INTO mi
  1911. (
  1912. type,
  1913. label,
  1914. lender,
  1915. rate,
  1916. premium,
  1917. upfront,
  1918. five_year_total,
  1919. initial_premium,
  1920. initial_rate,
  1921. initial_amount
  1922. )
  1923. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  1924. RETURNING id`
  1925. row := db.QueryRow(query,
  1926. &mi.Type,
  1927. &mi.Label,
  1928. &mi.Lender,
  1929. &mi.Rate,
  1930. &mi.Premium,
  1931. &mi.Upfront,
  1932. &mi.FiveYearTotal,
  1933. &mi.InitialAllInPremium,
  1934. &mi.InitialAllInRate,
  1935. &mi.InitialAmount,
  1936. )
  1937. err := row.Scan(&id)
  1938. if err != nil {
  1939. return 0, err
  1940. }
  1941. return id, nil
  1942. }
  1943. func insertFee(db *sql.DB, fee Fee) (int, error) {
  1944. var id int
  1945. query := `INSERT INTO fee
  1946. (loan_id, amount, perc, type, notes, name, category)
  1947. VALUES (?, ?, ?, ?, ?, ?, ?)
  1948. RETURNING id`
  1949. row := db.QueryRow(query,
  1950. fee.LoanId,
  1951. fee.Amount,
  1952. fee.Perc,
  1953. fee.Type,
  1954. fee.Notes,
  1955. fee.Name,
  1956. fee.Category,
  1957. )
  1958. err := row.Scan(&id)
  1959. if err != nil {
  1960. return 0, err
  1961. }
  1962. return id, nil
  1963. }
  1964. func insertLoanType(db *sql.DB, lt LoanType) (int, error) {
  1965. var id int
  1966. query := `INSERT INTO loan_type (branch_id, user_id, name)
  1967. VALUES (NULLIF(?, 0), NULLIF(?, 0), ?)
  1968. RETURNING id`
  1969. row := db.QueryRow(query,
  1970. lt.Branch,
  1971. lt.User,
  1972. lt.Name,
  1973. )
  1974. err := row.Scan(&id)
  1975. if err != nil {
  1976. return 0, err
  1977. }
  1978. return id, nil
  1979. }
  1980. func (loan *Loan) insertLoan(db *sql.DB) error {
  1981. var query string
  1982. var row *sql.Row
  1983. var err error
  1984. query = `INSERT INTO loan
  1985. (
  1986. estimate_id,
  1987. type_id,
  1988. amount,
  1989. term,
  1990. interest,
  1991. ltv,
  1992. dti,
  1993. hoi,
  1994. tax,
  1995. name
  1996. )
  1997. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  1998. RETURNING id
  1999. `
  2000. row = db.QueryRow(query,
  2001. loan.EstimateId,
  2002. loan.Type.Id,
  2003. loan.Amount,
  2004. loan.Term,
  2005. loan.Interest,
  2006. loan.Ltv,
  2007. loan.Dti,
  2008. loan.Hoi,
  2009. loan.Tax,
  2010. loan.Name,
  2011. )
  2012. err = row.Scan(&loan.Id)
  2013. if err != nil {
  2014. return err
  2015. }
  2016. _, err = insertMi(db, loan.Mi)
  2017. if err != nil {
  2018. return err
  2019. }
  2020. for i := range loan.Fees {
  2021. loan.Fees[i].LoanId = loan.Id
  2022. _, err := insertFee(db, loan.Fees[i])
  2023. if err != nil {
  2024. return err
  2025. }
  2026. }
  2027. return nil
  2028. }
  2029. func (estimate *Estimate) insertEstimate(db *sql.DB) error {
  2030. var query string
  2031. var row *sql.Row
  2032. var err error
  2033. // var id int // Inserted estimate's id
  2034. query = `INSERT INTO estimate
  2035. (
  2036. user_id,
  2037. transaction,
  2038. price,
  2039. property,
  2040. occupancy,
  2041. zip,
  2042. pud
  2043. )
  2044. VALUES (?, ?, ?, ?, ?, ?, ?)
  2045. RETURNING id
  2046. `
  2047. row = db.QueryRow(query,
  2048. estimate.User,
  2049. estimate.Transaction,
  2050. estimate.Price,
  2051. estimate.Property,
  2052. estimate.Occupancy,
  2053. estimate.Zip,
  2054. estimate.Pud,
  2055. )
  2056. err = row.Scan(&estimate.Id)
  2057. if err != nil {
  2058. return err
  2059. }
  2060. err = estimate.insertBorrower(db)
  2061. if err != nil {
  2062. return err
  2063. }
  2064. for i := range estimate.Loans {
  2065. estimate.Loans[i].EstimateId = estimate.Id
  2066. err = estimate.Loans[i].insertLoan(db)
  2067. if err != nil {
  2068. return err
  2069. }
  2070. }
  2071. return nil
  2072. }
  2073. func (estimate *Estimate) del(db *sql.DB, user int) error {
  2074. var query string
  2075. var err error
  2076. query = `DELETE FROM estimate WHERE id = ? AND user_id = ?`
  2077. _, err = db.Exec(query, estimate.Id, user)
  2078. if err != nil {
  2079. return err
  2080. }
  2081. return nil
  2082. }
  2083. func (et *ETemplate) del(db *sql.DB, user int) error {
  2084. var query string
  2085. var err error
  2086. query = `DELETE FROM estimate_template WHERE id = ? AND user_id = ?`
  2087. _, err = db.Exec(query, et.Id, user)
  2088. if err != nil {
  2089. return err
  2090. }
  2091. return nil
  2092. }
  2093. func (eTemplate *ETemplate) insert(db *sql.DB) error {
  2094. var query string
  2095. var row *sql.Row
  2096. var err error
  2097. query = `INSERT INTO estimate_template
  2098. (
  2099. user_id,
  2100. branch_id,
  2101. estimate_id,
  2102. )
  2103. VALUES (?, ?, ?)
  2104. RETURNING id
  2105. `
  2106. row = db.QueryRow(query,
  2107. eTemplate.UserId,
  2108. eTemplate.BranchId,
  2109. eTemplate.Estimate.Id,
  2110. )
  2111. err = row.Scan(&eTemplate.Id)
  2112. if err != nil {
  2113. return err
  2114. }
  2115. return nil
  2116. }
  2117. func createEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2118. var estimate Estimate
  2119. err := json.NewDecoder(r.Body).Decode(&estimate)
  2120. if err != nil {
  2121. http.Error(w, "Invalid fields.", 422)
  2122. return
  2123. }
  2124. claims, err := getClaims(r)
  2125. estimate.User = claims.Id
  2126. err = estimate.insertEstimate(db)
  2127. if err != nil {
  2128. http.Error(w, err.Error(), 422)
  2129. return
  2130. }
  2131. estimate.makeResults()
  2132. err = estimate.insertResults(db)
  2133. if err != nil {
  2134. http.Error(w, err.Error(), 500)
  2135. return
  2136. }
  2137. e, err := getEstimates(db, estimate.Id, 0)
  2138. if err != nil {
  2139. http.Error(w, err.Error(), 500)
  2140. return
  2141. }
  2142. json.NewEncoder(w).Encode(e[0])
  2143. }
  2144. // Query all estimates that belong to the current user
  2145. func fetchEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2146. var estimates []Estimate
  2147. claims, err := getClaims(r)
  2148. estimates, err = getEstimates(db, 0, claims.Id)
  2149. if err != nil {
  2150. http.Error(w, err.Error(), 500)
  2151. return
  2152. }
  2153. json.NewEncoder(w).Encode(estimates)
  2154. }
  2155. func checkConventional(l Loan, b Borrower) error {
  2156. if b.Credit < 620 {
  2157. return errors.New("Credit score too low for conventional loan")
  2158. }
  2159. // Buyer needs to put down 20% to avoid mortgage insurance
  2160. if l.Ltv > 80 && l.Mi.Rate == 0 {
  2161. return errors.New(fmt.Sprintln(
  2162. l.Name,
  2163. "down payment must be 20% to avoid insurance",
  2164. ))
  2165. }
  2166. return nil
  2167. }
  2168. func checkFHA(l Loan, b Borrower) error {
  2169. if b.Credit < 500 {
  2170. return errors.New("Credit score too low for FHA loan")
  2171. }
  2172. if l.Ltv > 96.5 {
  2173. return errors.New("FHA down payment must be at least 3.5%")
  2174. }
  2175. if b.Credit < 580 && l.Ltv > 90 {
  2176. return errors.New("FHA down payment must be at least 10%")
  2177. }
  2178. // Debt-to-income must be below 45% if credit score is below 580.
  2179. if b.Credit < 580 && l.Dti > 45 {
  2180. return errors.New(fmt.Sprintln(
  2181. l.Name, "debt to income is too high for credit score.",
  2182. ))
  2183. }
  2184. return nil
  2185. }
  2186. // Loan option for veterans with no set rules. Mainly placeholder.
  2187. func checkVA(l Loan, b Borrower) error {
  2188. return nil
  2189. }
  2190. // Loan option for residents of rural areas with no set rules.
  2191. // Mainly placeholder.
  2192. func checkUSDA(l Loan, b Borrower) error {
  2193. return nil
  2194. }
  2195. // Should also check loan amount limit maybe with an API.
  2196. func checkEstimate(e Estimate) error {
  2197. if e.Property == "" {
  2198. return errors.New("Empty property type")
  2199. }
  2200. if e.Price == 0 {
  2201. return errors.New("Empty property price")
  2202. }
  2203. if e.Borrower.Num == 0 {
  2204. return errors.New("Missing number of borrowers")
  2205. }
  2206. if e.Borrower.Credit == 0 {
  2207. return errors.New("Missing borrower credit score")
  2208. }
  2209. if e.Borrower.Income == 0 {
  2210. return errors.New("Missing borrower credit income")
  2211. }
  2212. for _, l := range e.Loans {
  2213. if l.Amount == 0 {
  2214. return errors.New(fmt.Sprintln(l.Name, "loan amount cannot be zero"))
  2215. }
  2216. if l.Term == 0 {
  2217. return errors.New(fmt.Sprintln(l.Name, "loan term cannot be zero"))
  2218. }
  2219. if l.Interest == 0 {
  2220. return errors.New(fmt.Sprintln(l.Name, "loan interest cannot be zero"))
  2221. }
  2222. // Can be used to check rules for specific loan types
  2223. var err error
  2224. switch l.Type.Id {
  2225. case 1:
  2226. err = checkConventional(l, e.Borrower)
  2227. case 2:
  2228. err = checkFHA(l, e.Borrower)
  2229. case 3:
  2230. err = checkVA(l, e.Borrower)
  2231. case 4:
  2232. err = checkUSDA(l, e.Borrower)
  2233. default:
  2234. err = errors.New("Invalid loan type")
  2235. }
  2236. if err != nil {
  2237. return err
  2238. }
  2239. }
  2240. return nil
  2241. }
  2242. func validateEstimate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2243. var estimate Estimate
  2244. err := json.NewDecoder(r.Body).Decode(&estimate)
  2245. if err != nil {
  2246. http.Error(w, err.Error(), 422)
  2247. return
  2248. }
  2249. err = checkEstimate(estimate)
  2250. if err != nil {
  2251. http.Error(w, err.Error(), 406)
  2252. return
  2253. }
  2254. }
  2255. func checkPdf(w http.ResponseWriter, r *http.Request) {
  2256. db, err := sql.Open("mysql",
  2257. fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/skouter_dev",
  2258. os.Getenv("DBUser"),
  2259. os.Getenv("DBPass")))
  2260. // w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  2261. err = db.Ping()
  2262. if err != nil {
  2263. fmt.Println("Bad database configuration: %v\n", err)
  2264. panic(err)
  2265. // maybe os.Exit(1) instead
  2266. }
  2267. estimates, err := getEstimates(db, 1, 0)
  2268. if err != nil {
  2269. w.WriteHeader(500)
  2270. return
  2271. }
  2272. // claims, err := getClaims(r)
  2273. if err != nil {
  2274. w.WriteHeader(500)
  2275. return
  2276. }
  2277. user, err := queryUser(db, 1)
  2278. info := Report{
  2279. Title: "test PDF",
  2280. Name: "idk-random-name",
  2281. User: user,
  2282. Estimate: estimates[0],
  2283. }
  2284. avatar, err := fetchAvatar(db, info.User.Id)
  2285. letterhead, err := fetchLetterhead(db, info.User.Id)
  2286. info.Avatar =
  2287. base64.StdEncoding.EncodeToString(avatar)
  2288. info.Letterhead =
  2289. base64.StdEncoding.EncodeToString(letterhead)
  2290. for l := range info.Estimate.Loans {
  2291. loan := info.Estimate.Loans[l]
  2292. for f := range info.Estimate.Loans[l].Fees {
  2293. if info.Estimate.Loans[l].Fees[f].Amount < 0 {
  2294. loan.Credits = append(loan.Credits, loan.Fees[f])
  2295. }
  2296. }
  2297. }
  2298. err = pages["report"].tpl.ExecuteTemplate(w, "master.tpl", info)
  2299. if err != nil {
  2300. fmt.Println(err)
  2301. }
  2302. }
  2303. func getETemplates(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2304. claims, err := getClaims(r)
  2305. et, err := queryETemplates(db, 0, claims.Id)
  2306. if err != nil {
  2307. http.Error(w, err.Error(), 500)
  2308. return
  2309. }
  2310. json.NewEncoder(w).Encode(et)
  2311. }
  2312. func createETemplate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2313. var estimate Estimate
  2314. err := json.NewDecoder(r.Body).Decode(&estimate)
  2315. if err != nil {
  2316. http.Error(w, err.Error(), 422)
  2317. return
  2318. }
  2319. claims, err := getClaims(r)
  2320. if err != nil {
  2321. http.Error(w, err.Error(), 422)
  2322. return
  2323. }
  2324. err = estimate.insertETemplate(db, claims.Id, 0)
  2325. if err != nil {
  2326. http.Error(w, err.Error(), 500)
  2327. return
  2328. }
  2329. }
  2330. func getPdf(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2331. var estimate Estimate
  2332. err := json.NewDecoder(r.Body).Decode(&estimate)
  2333. cmd := exec.Command("wkhtmltopdf", "-", "-")
  2334. stdout, err := cmd.StdoutPipe()
  2335. if err != nil {
  2336. w.WriteHeader(500)
  2337. log.Println(err)
  2338. return
  2339. }
  2340. stdin, err := cmd.StdinPipe()
  2341. if err != nil {
  2342. w.WriteHeader(500)
  2343. log.Println(err)
  2344. return
  2345. }
  2346. if err := cmd.Start(); err != nil {
  2347. log.Fatal(err)
  2348. }
  2349. claims, err := getClaims(r)
  2350. if err != nil {
  2351. w.WriteHeader(500)
  2352. log.Println(err)
  2353. return
  2354. }
  2355. user, err := queryUser(db, claims.Id)
  2356. info := Report{
  2357. Title: "test PDF",
  2358. Name: "idk-random-name",
  2359. User: user,
  2360. Estimate: estimate,
  2361. }
  2362. avatar, err := fetchAvatar(db, info.User.Id)
  2363. letterhead, err := fetchLetterhead(db, info.User.Id)
  2364. if len(avatar) > 1 {
  2365. info.Avatar =
  2366. base64.StdEncoding.EncodeToString(avatar)
  2367. }
  2368. if len(letterhead) > 1 {
  2369. info.Letterhead =
  2370. base64.StdEncoding.EncodeToString(letterhead)
  2371. }
  2372. err = pages["report"].tpl.ExecuteTemplate(stdin, "master.tpl", info)
  2373. if err != nil {
  2374. w.WriteHeader(500)
  2375. log.Println(err)
  2376. return
  2377. }
  2378. stdin.Close()
  2379. buf, err := io.ReadAll(stdout)
  2380. if _, err := w.Write(buf); err != nil {
  2381. w.WriteHeader(500)
  2382. log.Println(err)
  2383. return
  2384. }
  2385. if err := cmd.Wait(); err != nil {
  2386. log.Println(err)
  2387. return
  2388. }
  2389. }
  2390. func clipLetterhead(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2391. var validTypes []string = []string{"image/png", "image/jpeg"}
  2392. var isValidType bool
  2393. var err error
  2394. // claims, err := getClaims(r)
  2395. if err != nil {
  2396. http.Error(w, "Invalid token.", 422)
  2397. return
  2398. }
  2399. img, t, err := image.Decode(r.Body)
  2400. if err != nil {
  2401. http.Error(w, "Invalid file, JPEG and PNG only.", 422)
  2402. return
  2403. }
  2404. for _, v := range validTypes {
  2405. if v == "image/"+t {
  2406. isValidType = true
  2407. }
  2408. }
  2409. if !isValidType {
  2410. http.Error(w, "Invalid file type.", 422)
  2411. return
  2412. }
  2413. g := gift.New(
  2414. gift.ResizeToFit(400, 200, gift.LanczosResampling),
  2415. )
  2416. dst := image.NewRGBA(g.Bounds(img.Bounds()))
  2417. g.Draw(dst, img)
  2418. w.Header().Set("Content-Type", "image/png")
  2419. err = png.Encode(w, dst)
  2420. if err != nil {
  2421. http.Error(w, "Error encoding.", 500)
  2422. return
  2423. }
  2424. }
  2425. func createCustomer(name string, email string, address Address) (
  2426. stripe.Customer, error) {
  2427. params := &stripe.CustomerParams{
  2428. Email: stripe.String(email),
  2429. Name: stripe.String(name),
  2430. Address: &stripe.AddressParams{
  2431. City: stripe.String(address.City),
  2432. Country: stripe.String(address.Country),
  2433. Line1: stripe.String(address.Street),
  2434. PostalCode: stripe.String(address.Zip),
  2435. State: stripe.String(address.Region),
  2436. },
  2437. };
  2438. result, err := customer.New(params)
  2439. return *result, err
  2440. }
  2441. func createSubscription(w http.ResponseWriter, db *sql.DB, r *http.Request) {
  2442. claims, err := getClaims(r)
  2443. user, err := queryUser(db, claims.Id)
  2444. if err != nil {
  2445. w.WriteHeader(422)
  2446. return
  2447. }
  2448. var name string = user.FirstName + " " + user.LastName
  2449. c, err := createCustomer(name, user.Email, user.Address)
  2450. if err != nil {
  2451. http.Error(w, err.Error(), 422)
  2452. return
  2453. }
  2454. err = user.updateCustomerId(db, c.ID)
  2455. // Automatically save the payment method to the subscription
  2456. // when the first payment is successful.
  2457. paymentSettings := &stripe.SubscriptionPaymentSettingsParams{
  2458. SaveDefaultPaymentMethod: stripe.String("on_subscription"),
  2459. }
  2460. // Create the subscription. Note we're expanding the Subscription's
  2461. // latest invoice and that invoice's payment_intent
  2462. // so we can pass it to the front end to confirm the payment
  2463. subscriptionParams := &stripe.SubscriptionParams{
  2464. Customer: stripe.String(c.ID),
  2465. Items: []*stripe.SubscriptionItemsParams{
  2466. {
  2467. Price: stripe.String("price_1OZLK9BPMoXn2pf9kuTAf8rs"),
  2468. },
  2469. },
  2470. PaymentSettings: paymentSettings,
  2471. PaymentBehavior: stripe.String("default_incomplete"),
  2472. }
  2473. subscriptionParams.AddExpand("latest_invoice.payment_intent")
  2474. s, err := subscription.New(subscriptionParams)
  2475. if err != nil {
  2476. http.Error(w, err.Error(), 500)
  2477. return
  2478. }
  2479. json.NewEncoder(w).Encode(s)
  2480. }
  2481. func api(w http.ResponseWriter, r *http.Request) {
  2482. var args []string
  2483. p := r.URL.Path
  2484. db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s",
  2485. os.Getenv("DBUser"),
  2486. os.Getenv("DBPass"),
  2487. os.Getenv("DBName"),
  2488. ))
  2489. w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  2490. err = db.Ping()
  2491. if err != nil {
  2492. fmt.Println("Bad database configuration: %v\n", err)
  2493. panic(err)
  2494. // maybe os.Exit(1) instead
  2495. }
  2496. switch {
  2497. case match(p, "/api/login", &args) &&
  2498. r.Method == http.MethodPost:
  2499. login(w, db, r)
  2500. case match(p, "/api/token", &args) &&
  2501. r.Method == http.MethodGet && guard(r, 1):
  2502. getToken(w, db, r)
  2503. case match(p, "/api/letterhead", &args) &&
  2504. r.Method == http.MethodPost && guard(r, 1):
  2505. clipLetterhead(w, db, r)
  2506. case match(p, "/api/users", &args) && // Array of all users
  2507. r.Method == http.MethodGet && guard(r, 3):
  2508. getUsers(w, db, r)
  2509. case match(p, "/api/user", &args) &&
  2510. r.Method == http.MethodGet && guard(r, 1):
  2511. getUser(w, db, r)
  2512. case match(p, "/api/user", &args) &&
  2513. r.Method == http.MethodPost:
  2514. createUser(w, db, r)
  2515. case match(p, "/api/user", &args) &&
  2516. r.Method == http.MethodPatch &&
  2517. guard(r, 3): // For admin to modify any user
  2518. patchUser(w, db, r)
  2519. case match(p, "/api/user", &args) &&
  2520. r.Method == http.MethodPatch &&
  2521. guard(r, 1): // For employees to modify own accounts
  2522. patchSelf(w, db, r)
  2523. case match(p, "/api/user", &args) &&
  2524. r.Method == http.MethodDelete &&
  2525. guard(r, 3):
  2526. deleteUser(w, db, r)
  2527. case match(p, "/api/user/avatar", &args) &&
  2528. r.Method == http.MethodGet &&
  2529. guard(r, 1):
  2530. getAvatar(w, db, r)
  2531. case match(p, "/api/user/avatar", &args) &&
  2532. r.Method == http.MethodPost &&
  2533. guard(r, 1):
  2534. setAvatar(w, db, r)
  2535. case match(p, "/api/user/letterhead", &args) &&
  2536. r.Method == http.MethodGet &&
  2537. guard(r, 1):
  2538. getLetterhead(w, db, r)
  2539. case match(p, "/api/user/letterhead", &args) &&
  2540. r.Method == http.MethodPost &&
  2541. guard(r, 1):
  2542. setLetterhead(w, db, r)
  2543. case match(p, "/api/user/password", &args) &&
  2544. r.Method == http.MethodPost &&
  2545. guard(r, 1):
  2546. changePassword(w, db, r)
  2547. case match(p, "/api/user/subscribe", &args) &&
  2548. r.Method == http.MethodPost &&
  2549. guard(r, 1):
  2550. createSubscription(w, db, r)
  2551. case match(p, "/api/fees", &args) &&
  2552. r.Method == http.MethodGet &&
  2553. guard(r, 1):
  2554. getFeesTemp(w, db, r)
  2555. case match(p, "/api/fee", &args) &&
  2556. r.Method == http.MethodPost &&
  2557. guard(r, 1):
  2558. createFeesTemp(w, db, r)
  2559. case match(p, "/api/fee", &args) &&
  2560. r.Method == http.MethodDelete &&
  2561. guard(r, 1):
  2562. deleteFeeTemp(w, db, r)
  2563. case match(p, "/api/estimates", &args) &&
  2564. r.Method == http.MethodGet &&
  2565. guard(r, 1):
  2566. fetchEstimate(w, db, r)
  2567. case match(p, "/api/estimate", &args) &&
  2568. r.Method == http.MethodPost &&
  2569. guard(r, 1):
  2570. createEstimate(w, db, r)
  2571. case match(p, "/api/estimate", &args) &&
  2572. r.Method == http.MethodDelete &&
  2573. guard(r, 1):
  2574. deleteEstimate(w, db, r)
  2575. case match(p, "/api/estimate/validate", &args) &&
  2576. r.Method == http.MethodPost &&
  2577. guard(r, 1):
  2578. validateEstimate(w, db, r)
  2579. case match(p, "/api/estimate/summarize", &args) &&
  2580. r.Method == http.MethodPost &&
  2581. guard(r, 1):
  2582. summarize(w, db, r)
  2583. case match(p, "/api/templates", &args) &&
  2584. r.Method == http.MethodGet &&
  2585. guard(r, 1):
  2586. getETemplates(w, db, r)
  2587. case match(p, "/api/templates", &args) &&
  2588. r.Method == http.MethodPost &&
  2589. guard(r, 1):
  2590. createETemplate(w, db, r)
  2591. case match(p, "/api/templates", &args) &&
  2592. r.Method == http.MethodDelete &&
  2593. guard(r, 1):
  2594. deleteET(w, db, r)
  2595. case match(p, "/api/pdf", &args) &&
  2596. r.Method == http.MethodPost &&
  2597. guard(r, 1):
  2598. getPdf(w, db, r)
  2599. default:
  2600. http.Error(w, "Invalid route or token", 404)
  2601. }
  2602. db.Close()
  2603. }
  2604. func route(w http.ResponseWriter, r *http.Request) {
  2605. var page Page
  2606. var args []string
  2607. p := r.URL.Path
  2608. switch {
  2609. case r.Method == "GET" && match(p, "/", &args):
  2610. page = pages["home"]
  2611. case match(p, "/terms", &args):
  2612. page = pages["terms"]
  2613. case match(p, "/app", &args):
  2614. page = pages["app"]
  2615. default:
  2616. http.NotFound(w, r)
  2617. return
  2618. }
  2619. page.Render(w)
  2620. }
  2621. func serve() {
  2622. files := http.FileServer(http.Dir(""))
  2623. proxy, err := url.Parse("http://localhost:8002")
  2624. if err != nil {
  2625. log.Fatal("invalid origin server URL")
  2626. }
  2627. http.Handle("/assets/", files)
  2628. http.HandleFunc("/api/", api)
  2629. http.HandleFunc("/app", route)
  2630. http.Handle("/", httputil.NewSingleHostReverseProxy(proxy))
  2631. log.Fatal(http.ListenAndServe(address, nil))
  2632. }
  2633. func dbReset(db *sql.DB) {
  2634. b, err := os.ReadFile("migrations/reset.sql")
  2635. if err != nil {
  2636. log.Fatal(err)
  2637. }
  2638. _, err = db.Exec(string(b))
  2639. if err != nil {
  2640. log.Fatal(err)
  2641. }
  2642. b, err = os.ReadFile("migrations/0_29092022_setup_tables.sql")
  2643. if err != nil {
  2644. log.Fatal(err)
  2645. }
  2646. _, err = db.Exec(string(b))
  2647. if err != nil {
  2648. log.Fatal(err)
  2649. }
  2650. }
  2651. func generateFees(loan Loan) []Fee {
  2652. var fees []Fee
  2653. var fee Fee
  2654. p := gofakeit.Float32Range(0.5, 10)
  2655. size := gofakeit.Number(1, 10)
  2656. for f := 0; f < size; f++ {
  2657. fee = Fee{
  2658. Amount: int(float32(loan.Amount) * p / 100),
  2659. Perc: p,
  2660. Name: gofakeit.BuzzWord(),
  2661. Type: feeTypes[gofakeit.Number(0, len(feeTypes)-1)],
  2662. }
  2663. fees = append(fees, fee)
  2664. }
  2665. return fees
  2666. }
  2667. func generateCredits(loan Loan) []Fee {
  2668. var fees []Fee
  2669. var fee Fee
  2670. p := gofakeit.Float32Range(-10, -0.5)
  2671. size := gofakeit.Number(1, 10)
  2672. for f := 0; f < size; f++ {
  2673. fee = Fee{
  2674. Amount: int(float32(loan.Amount) * p / 100),
  2675. Perc: p,
  2676. Name: gofakeit.BuzzWord(),
  2677. Type: feeTypes[gofakeit.Number(0, len(feeTypes)-1)],
  2678. }
  2679. fees = append(fees, fee)
  2680. }
  2681. return fees
  2682. }
  2683. func seedAddresses(db *sql.DB) []Address {
  2684. addresses := make([]Address, 10)
  2685. for i, a := range addresses {
  2686. a.Street = gofakeit.Street()
  2687. a.City = gofakeit.City()
  2688. a.Region = gofakeit.State()
  2689. a.Country = "Canada"
  2690. a.Full = fmt.Sprintf("%s, %s %s", a.Street, a.City, a.Region)
  2691. id, err := insertAddress(db, a)
  2692. if err != nil {
  2693. log.Println(err)
  2694. break
  2695. }
  2696. addresses[i].Id = id
  2697. }
  2698. return addresses
  2699. }
  2700. func seedBranches(db *sql.DB, addresses []Address) []Branch {
  2701. branches := make([]Branch, 4)
  2702. for i := range branches {
  2703. branches[i].Name = gofakeit.Company()
  2704. branches[i].Type = "NMLS"
  2705. branches[i].Letterhead = gofakeit.ImagePng(400, 200)
  2706. branches[i].Num = gofakeit.HexUint8()
  2707. branches[i].Phone = gofakeit.Phone()
  2708. branches[i].Address.Id = gofakeit.Number(1, 5)
  2709. id, err := insertBranch(db, branches[i])
  2710. if err != nil {
  2711. log.Println(err)
  2712. break
  2713. }
  2714. branches[i].Id = id
  2715. }
  2716. return branches
  2717. }
  2718. func seedUsers(db *sql.DB, addresses []Address, branches []Branch) []User {
  2719. users := make([]User, 10)
  2720. for i := range users {
  2721. p := gofakeit.Person()
  2722. users[i].FirstName = p.FirstName
  2723. users[i].LastName = p.LastName
  2724. users[i].Email = p.Contact.Email
  2725. users[i].Phone = p.Contact.Phone
  2726. users[i].Branch = branches[gofakeit.Number(0, 3)]
  2727. users[i].Address = addresses[gofakeit.Number(1, 9)]
  2728. // users[i].Letterhead = gofakeit.ImagePng(400, 200)
  2729. // users[i].Avatar = gofakeit.ImagePng(200, 200)
  2730. users[i].Country = []string{"Canada", "USA"}[gofakeit.Number(0, 1)]
  2731. users[i].Password = "test123"
  2732. users[i].Verified = true
  2733. users[i].Title = "Loan Officer"
  2734. users[i].Status = "Subscribed"
  2735. users[i].Role = "User"
  2736. }
  2737. users[0].Email = "test@example.com"
  2738. users[0].Email = "test@example.com"
  2739. users[1].Email = "test2@example.com"
  2740. users[1].Status = "Branch"
  2741. users[1].Role = "Manager"
  2742. users[2].Email = "test3@example.com"
  2743. users[2].Status = "Free"
  2744. users[2].Role = "Admin"
  2745. for i := range users {
  2746. var err error
  2747. users[i].Id, err = insertUser(db, users[i])
  2748. if err != nil {
  2749. log.Println(err)
  2750. break
  2751. }
  2752. }
  2753. return users
  2754. }
  2755. func seedLicenses(db *sql.DB, users []User) []License {
  2756. licenses := make([]License, len(users))
  2757. for i := range licenses {
  2758. licenses[i].UserId = users[i].Id
  2759. licenses[i].Type = []string{"NMLS", "FSRA"}[gofakeit.Number(0, 1)]
  2760. licenses[i].Num = gofakeit.UUID()
  2761. id, err := insertLicense(db, licenses[i])
  2762. if err != nil {
  2763. log.Println(err)
  2764. break
  2765. }
  2766. licenses[i].Id = id
  2767. }
  2768. return licenses
  2769. }
  2770. func seedLoanTypes(db *sql.DB) []LoanType {
  2771. var loantypes []LoanType
  2772. var loantype LoanType
  2773. var err error
  2774. loantype = LoanType{Branch: 0, User: 0, Name: "Conventional"}
  2775. loantype.Id, err = insertLoanType(db, loantype)
  2776. if err != nil {
  2777. panic(err)
  2778. }
  2779. loantypes = append(loantypes, loantype)
  2780. loantype = LoanType{Branch: 0, User: 0, Name: "FHA"}
  2781. loantype.Id, err = insertLoanType(db, loantype)
  2782. if err != nil {
  2783. panic(err)
  2784. }
  2785. loantypes = append(loantypes, loantype)
  2786. loantype = LoanType{Branch: 0, User: 0, Name: "USDA"}
  2787. loantype.Id, err = insertLoanType(db, loantype)
  2788. if err != nil {
  2789. panic(err)
  2790. }
  2791. loantypes = append(loantypes, loantype)
  2792. loantype = LoanType{Branch: 0, User: 0, Name: "VA"}
  2793. loantype.Id, err = insertLoanType(db, loantype)
  2794. if err != nil {
  2795. panic(err)
  2796. }
  2797. loantypes = append(loantypes, loantype)
  2798. return loantypes
  2799. }
  2800. func seedEstimates(db *sql.DB, users []User, ltypes []LoanType) []Estimate {
  2801. var estimates []Estimate
  2802. var estimate Estimate
  2803. var l Loan
  2804. var err error
  2805. for i := 0; i < 15; i++ {
  2806. estimate = Estimate{}
  2807. estimate.User = users[gofakeit.Number(0, len(users)-1)].Id
  2808. estimate.Borrower = Borrower{
  2809. Credit: gofakeit.Number(600, 800),
  2810. Income: gofakeit.Number(1000000, 15000000),
  2811. Num: gofakeit.Number(1, 20),
  2812. }
  2813. estimate.Transaction = []string{"Purchase", "Refinance"}[gofakeit.Number(0, 1)]
  2814. estimate.Price = gofakeit.Number(50000, 200000000)
  2815. estimate.Property =
  2816. propertyTypes[gofakeit.Number(0, len(propertyTypes)-1)]
  2817. estimate.Occupancy =
  2818. []string{"Primary", "Secondary", "Investment"}[gofakeit.Number(0, 2)]
  2819. estimate.Zip = gofakeit.Zip()
  2820. lsize := gofakeit.Number(1, 6)
  2821. for j := 0; j < lsize; j++ {
  2822. l.Type = ltypes[gofakeit.Number(0, len(ltypes)-1)]
  2823. l.Amount = gofakeit.Number(
  2824. int(float32(estimate.Price)*0.5),
  2825. int(float32(estimate.Price)*0.93))
  2826. l.Term = gofakeit.Number(4, 30)
  2827. l.Hoi = gofakeit.Number(50000, 700000)
  2828. l.Hazard = gofakeit.Number(5000, 200000)
  2829. l.Tax = gofakeit.Number(5000, 200000)
  2830. l.Interest = gofakeit.Float32Range(0.5, 8)
  2831. l.Fees = generateFees(l)
  2832. l.Credits = generateCredits(l)
  2833. l.Name = gofakeit.AdjectiveDescriptive()
  2834. estimate.Loans = append(estimate.Loans, l)
  2835. }
  2836. estimates = append(estimates, estimate)
  2837. }
  2838. estimates[0].User = users[0].Id
  2839. estimates[1].User = users[0].Id
  2840. for i := range estimates {
  2841. err = estimates[i].insertEstimate(db)
  2842. if err != nil {
  2843. log.Println(err)
  2844. return estimates
  2845. }
  2846. }
  2847. return estimates
  2848. }
  2849. func seedResults(db *sql.DB, estimates []Estimate) error {
  2850. var err error
  2851. for i := range estimates {
  2852. estimates[i].makeResults()
  2853. err = estimates[i].insertResults(db)
  2854. if err != nil {
  2855. log.Println(err)
  2856. return err
  2857. }
  2858. }
  2859. return nil
  2860. }
  2861. func dbSeed(db *sql.DB) {
  2862. addresses := seedAddresses(db)
  2863. branches := seedBranches(db, addresses)
  2864. users := seedUsers(db, addresses, branches)
  2865. _ = seedLicenses(db, users)
  2866. loantypes := seedLoanTypes(db)
  2867. estimates := seedEstimates(db, users, loantypes)
  2868. _ = seedResults(db, estimates)
  2869. }
  2870. func dev(args []string) {
  2871. os.Setenv("DBName", "skouter_dev")
  2872. os.Setenv("DBUser", "tester")
  2873. os.Setenv("DBPass", "test123")
  2874. stripe.Key = os.Getenv("STRIPE_SECRET_KEY")
  2875. db, err := sql.Open("mysql",
  2876. fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s?multiStatements=true",
  2877. os.Getenv("DBUser"),
  2878. os.Getenv("DBPass"),
  2879. os.Getenv("DBName"),
  2880. ))
  2881. err = db.Ping()
  2882. if err != nil {
  2883. log.Println("Bad database configuration: %v", err)
  2884. panic(err)
  2885. // maybe os.Exit(1) instead
  2886. }
  2887. if len(args) == 0 {
  2888. serve()
  2889. return
  2890. }
  2891. switch args[0] {
  2892. case "seed":
  2893. dbSeed(db)
  2894. case "reset":
  2895. dbReset(db)
  2896. default:
  2897. return
  2898. }
  2899. db.Close()
  2900. }
  2901. func check(args []string) {
  2902. os.Setenv("DBName", "skouter_dev")
  2903. os.Setenv("DBUser", "tester")
  2904. os.Setenv("DBPass", "test123")
  2905. files := http.FileServer(http.Dir(""))
  2906. http.Handle("/assets/", files)
  2907. http.HandleFunc("/", checkPdf)
  2908. log.Fatal(http.ListenAndServe(address, nil))
  2909. }
  2910. func main() {
  2911. if len(os.Args) <= 1 {
  2912. serve()
  2913. return
  2914. }
  2915. switch os.Args[1] {
  2916. case "dev":
  2917. dev(os.Args[2:])
  2918. case "checkpdf":
  2919. check(os.Args[2:])
  2920. default:
  2921. return
  2922. }
  2923. }