diff --git a/controller/lottery.go b/controller/lottery.go new file mode 100644 index 0000000..ccd4c1f --- /dev/null +++ b/controller/lottery.go @@ -0,0 +1,206 @@ +package controller + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + + model "github.com/stepupgo/stepupgo2-1/model" + repository "github.com/stepupgo/stepupgo2-1/model/db" + temple "github.com/stepupgo/stepupgo2-1/view" +) + +//宝くじの種類を取得 +func LotteriesTypeGet() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/available_lotteries") + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + defer resp.Body.Close() + + var lotteries []*model.Lottery + if err := json.NewDecoder(resp.Body).Decode(&lotteries); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + if err := temple.ListTmpl.Execute(w, lotteries); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + fmt.Println("compleat get lotteries") + } +} + +func PurchasePage() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/lottery?id=" + r.FormValue("id")) + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + defer resp.Body.Close() + + var l model.Lottery + if err := json.NewDecoder(resp.Body).Decode(&l); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + data := struct { + model.Lottery + Remain int64 + }{ + Lottery: l, + Remain: l.Num, // TODO: 残りを計算する + } + + if err := temple.PurchasePageTmpl.Execute(w, data); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + } +} + +func Purchase() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := r.FormValue("id") + num, err := strconv.Atoi(r.FormValue("num")) + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + // TODO: パラメタのバリデーション + + resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/lottery?id=" + id) + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + defer resp.Body.Close() + + var l model.Lottery + if err := json.NewDecoder(resp.Body).Decode(&l); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + var count int + if err := repository.DB.QueryRow("SELECT COUNT(*) FROM purchased WHERE lottery_id = ?", l.ID).Scan(&count); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + for i := 1; i <= num; i++ { + const sql = "INSERT INTO purchased(lottery_id, number) values (?,?)" + format := fmt.Sprintf(`%%0%dd`, len(strconv.FormatInt(l.Num-1, 10))) + n := fmt.Sprintf(format, count+i) + if _, err := repository.DB.Exec(sql, id, n); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + } + + http.Redirect(w, r, "/purchase_page?id="+l.ID, http.StatusFound) + } +} + +func LotteryResult() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + resp1, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/result?id=" + r.FormValue("id")) + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + defer resp1.Body.Close() + + var result model.Result + if err := json.NewDecoder(resp1.Body).Decode(&result); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + resp2, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/lottery?id=" + r.FormValue("id")) + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + defer resp2.Body.Close() + + var l model.Lottery + if err := json.NewDecoder(resp2.Body).Decode(&l); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + type winner struct { + Prize *model.Prize + Numbers []string + } + + data := struct { + model.Lottery + Winners map[string]*winner + }{ + Lottery: l, + Winners: map[string]*winner{}, + } + + rows, err := repository.DB.Query("SELECT number FROM purchased WHERE lottery_id = ?", l.ID) + if err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + for rows.Next() { + var number string + if err := rows.Scan(&number); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + + for i := range result.Winners { + for _, n := range result.Winners[i].Numbers { + if number == n { + prizeID := result.Winners[i].PrizeID + if data.Winners[prizeID] == nil { + for _, p := range l.Prizes { + if p.ID == prizeID { + data.Winners[prizeID] = &winner{ + Prize: p, + } + } + } + } + data.Winners[prizeID].Numbers = append(data.Winners[prizeID].Numbers, n) + } + } + } + } + + if err := temple.ResultTmpl.Execute(w, data); err != nil { + const status = http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + return + } + } +} diff --git a/database.db b/database.db new file mode 100644 index 0000000..75c4fec Binary files /dev/null and b/database.db differ diff --git a/main.go b/main.go index 34194b1..0b581dc 100644 --- a/main.go +++ b/main.go @@ -10,229 +10,32 @@ TODO */ import ( - "database/sql" - "encoding/json" - "fmt" + "log" "net" "net/http" "os" - "strconv" + + controller "github.com/stepupgo/stepupgo2-1/controller" _ "github.com/mattn/go-sqlite3" ) func main() { - db, err := sql.Open("sqlite3", "database.db") - if err != nil { - panic(err) - } - - if err := initDB(db); err != nil { - panic(err) - } - - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/available_lotteries") - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - defer resp.Body.Close() - - var lotteries []*Lottery - if err := json.NewDecoder(resp.Body).Decode(&lotteries); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - if err := listTmpl.Execute(w, lotteries); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - }) - - http.HandleFunc("/purchase_page", func(w http.ResponseWriter, r *http.Request) { - resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/lottery?id=" + r.FormValue("id")) - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - defer resp.Body.Close() - - var l Lottery - if err := json.NewDecoder(resp.Body).Decode(&l); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - data := struct { - Lottery - Remain int64 - }{ - Lottery: l, - Remain: l.Num, // TODO: 残りを計算する - } - if err := purchasePageTmpl.Execute(w, data); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - }) - - http.HandleFunc("/purchase", func(w http.ResponseWriter, r *http.Request) { - id := r.FormValue("id") - num, err := strconv.Atoi(r.FormValue("num")) - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - // TODO: パラメタのバリデーション - - resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/lottery?id=" + id) - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - defer resp.Body.Close() - - var l Lottery - if err := json.NewDecoder(resp.Body).Decode(&l); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - var count int - if err := db.QueryRow("SELECT COUNT(*) FROM purchased WHERE lottery_id = ?", l.ID).Scan(&count); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - for i := 1; i <= num; i++ { - const sql = "INSERT INTO purchased(lottery_id, number) values (?,?)" - format := fmt.Sprintf(`%%0%dd`, len(strconv.FormatInt(l.Num-1, 10))) - n := fmt.Sprintf(format, count+i) - if _, err := db.Exec(sql, id, n); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - } - - http.Redirect(w, r, "/purchase_page?id="+l.ID, http.StatusFound) - }) - - http.HandleFunc("/result", func(w http.ResponseWriter, r *http.Request) { - resp1, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/result?id=" + r.FormValue("id")) - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - defer resp1.Body.Close() - - var result Result - if err := json.NewDecoder(resp1.Body).Decode(&result); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - resp2, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/lottery?id=" + r.FormValue("id")) - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - defer resp2.Body.Close() - - var l Lottery - if err := json.NewDecoder(resp2.Body).Decode(&l); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - type winner struct { - Prize *Prize - Numbers []string - } - - data := struct { - Lottery - Winners map[string]*winner - }{ - Lottery: l, - Winners: map[string]*winner{}, - } - - rows, err := db.Query("SELECT number FROM purchased WHERE lottery_id = ?", l.ID) - if err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - for rows.Next() { - var number string - if err := rows.Scan(&number); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - - for i := range result.Winners { - for _, n := range result.Winners[i].Numbers { - if number == n { - prizeID := result.Winners[i].PrizeID - if data.Winners[prizeID] == nil { - for _, p := range l.Prizes { - if p.ID == prizeID { - data.Winners[prizeID] = &winner{ - Prize: p, - } - } - } - } - data.Winners[prizeID].Numbers = append(data.Winners[prizeID].Numbers, n) - } - } - } - } - - if err := resultTmpl.Execute(w, data); err != nil { - const status = http.StatusInternalServerError - http.Error(w, http.StatusText(status), status) - return - } - }) - port := os.Getenv("PORT") if port == "" { port = "8080" } - addr := net.JoinHostPort("", port) - http.ListenAndServe(addr, nil) -} + http.HandleFunc("/", controller.LotteriesTypeGet()) + http.HandleFunc("/purchase_page", controller.PurchasePage()) + http.HandleFunc("/purchase", controller.Purchase()) + http.HandleFunc("/result", controller.LotteryResult()) -func initDB(db *sql.DB) error { - const sql = ` -CREATE TABLE IF NOT EXISTS purchased ( - lottery_id TEXT NOT NULL, - number TEXT NOT NULL, - PRIMARY KEY(lottery_id, number) -); -` - if _, err := db.Exec(sql); err != nil { - return err + addr := net.JoinHostPort("", port) + log.Println("Server running...") + err := http.ListenAndServe(addr, nil) + if err != nil { + log.Fatalf("Listen and serve failed. %+v", err) } - return nil + } diff --git a/model/db/db.go b/model/db/db.go new file mode 100644 index 0000000..d103e45 --- /dev/null +++ b/model/db/db.go @@ -0,0 +1,36 @@ +package db + +import ( + "database/sql" + "fmt" + + _ "github.com/mattn/go-sqlite3" +) + +var DB *sql.DB + +func init() { + DB, err := sql.Open("sqlite3", "database.db") + if err != nil { + panic(err) + } + + if err := initDB(DB); err != nil { + panic(err) + } + fmt.Println("compleat open sql") +} + +func initDB(db *sql.DB) error { + const sql = ` +CREATE TABLE IF NOT EXISTS purchased ( + lottery_id TEXT NOT NULL, + number TEXT NOT NULL, + PRIMARY KEY(lottery_id, number) +); +` + if _, err := db.Exec(sql); err != nil { + return err + } + return nil +} diff --git a/types.go b/model/types.go similarity index 98% rename from types.go rename to model/types.go index 0f88802..b307a85 100644 --- a/types.go +++ b/model/types.go @@ -1,4 +1,4 @@ -package main +package model import "time" diff --git a/template.go b/view/template.go similarity index 86% rename from template.go rename to view/template.go index 149fe51..a69b99d 100644 --- a/template.go +++ b/view/template.go @@ -1,8 +1,8 @@ -package main +package view import "html/template" -var listTmpl = template.Must(template.New("list").Parse(` +var ListTmpl = template.Must(template.New("list").Parse(`
@@ -20,7 +20,7 @@ var listTmpl = template.Must(template.New("list").Parse(` `)) -var purchasePageTmpl = template.Must(template.New("purchase_page").Parse(` +var PurchasePageTmpl = template.Must(template.New("purchase_page").Parse(` @@ -48,7 +48,7 @@ var purchasePageTmpl = template.Must(template.New("purchase_page").Parse(` `)) -var resultTmpl = template.Must(template.New("result").Parse(` +var ResultTmpl = template.Must(template.New("result").Parse(`