Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miyajima workspace #38

Open
wants to merge 31 commits into
base: miyajima-master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c03d477
Create Makefile for Run and Build Golang-code.
shadowlink0122 Oct 27, 2019
dd4d345
Database module
shadowlink0122 Oct 27, 2019
8829cdd
Package module definition.
shadowlink0122 Oct 27, 2019
dca7bca
Main program source code.
shadowlink0122 Oct 27, 2019
86ee3de
View
shadowlink0122 Oct 27, 2019
73fd810
Handler
shadowlink0122 Oct 27, 2019
4f8d563
Model for Response body.
shadowlink0122 Oct 27, 2019
75d5520
Routing and Serve.
shadowlink0122 Oct 27, 2019
11f752e
Remove or Move to other directory.
shadowlink0122 Oct 27, 2019
5e163af
Separate SQL Query.
shadowlink0122 Oct 27, 2019
7eae6ee
Separate in detail.
shadowlink0122 Oct 27, 2019
153e2ce
Add Initialization.
shadowlink0122 Oct 27, 2019
1fffa22
Separate in detail.
shadowlink0122 Oct 27, 2019
ae3033c
Dipendency Injection.
shadowlink0122 Oct 27, 2019
2e9017b
Git Ignore.
shadowlink0122 Oct 27, 2019
e9c9633
Separate in detail.
shadowlink0122 Oct 27, 2019
685c45a
Separate in detail.
shadowlink0122 Oct 27, 2019
8660a63
Makefile
shadowlink0122 Oct 27, 2019
a0013d4
.gitignore
shadowlink0122 Oct 27, 2019
dcda074
Package module definition.
shadowlink0122 Oct 27, 2019
77dc4ab
Main source code.
shadowlink0122 Oct 27, 2019
9a0b62a
Add detail for application structure.
shadowlink0122 Oct 27, 2019
b3f3530
Move to other derectory.
shadowlink0122 Oct 27, 2019
556f848
Change import path.
shadowlink0122 Oct 27, 2019
0e432f7
Change import path.
shadowlink0122 Oct 27, 2019
4cade3f
README
shadowlink0122 Oct 27, 2019
6535c7e
Infra Structure.
shadowlink0122 Oct 27, 2019
16bb4a1
Buisines Logic.
shadowlink0122 Oct 27, 2019
34b19f9
A bit change.
shadowlink0122 Oct 27, 2019
f17fef2
Add Initialization for Top-Page.
shadowlink0122 Oct 27, 2019
b72a226
Add resiever.
shadowlink0122 Oct 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
database.db
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
default:
go run main.go

12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# Step up Go for students 2-1

see: http://bit.ly/devlopwithgo

## Structure
```
├── pkg:
│ ├── application: サービスロジック
│ ├── di: 依存性の注入
│ ├── infra: 外部との通信(API)
│ └── server
│ ├── handler: ハンドラ
│ └── server.go: ルーティング
└── main.go:
```
223 changes: 2 additions & 221 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,229 +10,10 @@ TODO
*/

import (
"database/sql"
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"strconv"

_ "github.com/mattn/go-sqlite3"
"github.com/stepupgo/stepupgo2-1/pkg/server"
)

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)
}

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
server.Run()
}
24 changes: 24 additions & 0 deletions pkg/application/top.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package application

import (
"net/http"

"github.com/stepupgo/stepupgo2-1/pkg/infra/api"
)

type top struct {
api api.ITop
}

type ATop interface {
GetAvailable() (*http.Response, error)
}

func NewTopApp(t api.ITop) ATop {
return &top{t}
}

func (t *top) GetAvailable() (*http.Response, error) {
resp, err := t.api.GetAvailableLotteries()
return resp, err
}
43 changes: 43 additions & 0 deletions pkg/db/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package db

import (
"database/sql"
"log"
)

var (
DB *sql.DB
)

func createTableSQL() string {
const sql = `
CREATE TABLE IF NOT EXISTS purchased (
lottery_id TEXT NOT NULL,
number TEXT NOT NULL,
PRIMARY KEY(lottery_id, number)
);
`

return sql
}

func initDB() error {
sql := createTableSQL()
if _, err := DB.Exec(sql); err != nil {
return err
}
return nil
}

func Init() {
db, err := sql.Open("sqlite3", "database.db")
if err != nil {
log.Println(err)
}

DB = db

if err := initDB(); err != nil {
log.Println(err)
}
}
19 changes: 19 additions & 0 deletions pkg/di/di.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package di

import (
app "github.com/stepupgo/stepupgo2-1/pkg/application"
"github.com/stepupgo/stepupgo2-1/pkg/infra/api"
)

var (
Top app.ATop
)

func Init() {
initTop()
}

func initTop() {
t := api.NewITop()
Top = app.NewTopApp(t)
}
18 changes: 18 additions & 0 deletions pkg/infra/api/top.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package api

import "net/http"

type top struct{}

type ITop interface {
GetAvailableLotteries() (*http.Response, error)
}

func NewITop() ITop {
return &top{}
}

func (t *top) GetAvailableLotteries() (*http.Response, error) {
resp, err := http.Get("https://lottery-dot-tenntenn-samples.appspot.com/available_lotteries")
return resp, err
}
Loading