This commit is contained in:
Matthieu Lamalle 2019-11-26 09:07:19 +01:00
parent a112fa589f
commit 0deab5858d
8 changed files with 181 additions and 33 deletions

View File

@ -1,27 +1,82 @@
package bdd package bdd
import ( import (
"bytes"
"fmt" "fmt"
"log" "time"
bolt "go.etcd.io/bbolt" "github.com/boltdb/bolt"
) )
// BDD_VOTES est le nom de la base // OpenDB a key-value store.
var BDD_VOTES = "VotesBucket" func OpenDB() (*bolt.DB, error) {
// InitBDD initialise la BDD
func InitBDD() {
db, err := bolt.Open("foods.db", 0600, nil) db, err := bolt.Open("foods.db", 0600, nil)
if err != nil { if err != nil {
log.Fatal(err) return nil, fmt.Errorf("could not open db, %v", err)
} }
err = db.Update(func(tx *bolt.Tx) error {
db.Update(func(tx *bolt.Tx) error { root, err := tx.CreateBucketIfNotExists([]byte("DB"))
_, err := tx.CreateBucketIfNotExists([]byte(BDD_VOTES))
if err != nil { if err != nil {
return fmt.Errorf("create bucket: %s", err) return fmt.Errorf("could not create root bucket: %v", err)
}
_, err = root.CreateBucketIfNotExists([]byte("VOTES"))
if err != nil {
return fmt.Errorf("could not create votes bucket: %v", err)
} }
return nil return nil
}) })
if err != nil {
return nil, fmt.Errorf("could not set up buckets, %v", err)
}
return db, nil
}
// CloseDB closes the key-value store file.
func CloseDB(db *bolt.DB) error {
return db.Close()
}
// AddVote ajoute un vote à la bdd
func AddVote(db *bolt.DB, vote string, date time.Time) error {
err := db.Update(func(tx *bolt.Tx) error {
err := tx.Bucket([]byte("DB")).Bucket([]byte("VOTES")).Put([]byte(date.Format(time.RFC3339)), []byte(vote))
if err != nil {
return fmt.Errorf("could not insert vote: %v", err)
}
return nil
})
fmt.Println("Added vote")
return err
}
// GetAllVotes liste tous les votes
func GetAllVotes(db *bolt.DB) ([]string, error) {
res := []string{}
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("DB")).Bucket([]byte("VOTES"))
b.ForEach(func(k, v []byte) error {
res = append(res, string(v))
return nil
})
return nil
})
return res, err
}
// GetVotesOfTheDay liste tous les votes du jour
func GetVotesOfTheDay(db *bolt.DB, date time.Time) ([]string, error) {
res := []string{}
err := db.View(func(tx *bolt.Tx) error {
c := tx.Bucket([]byte("DB")).Bucket([]byte("VOTES")).Cursor()
min := []byte(time.Now().AddDate(0, 0, -1).Format(time.RFC3339))
max := []byte(time.Now().AddDate(0, 0, 0).Format(time.RFC3339))
for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() {
res = append(res, string(v))
}
return nil
})
return res, err
} }

View File

@ -6,6 +6,7 @@ import (
"io" "io"
"log" "log"
"os" "os"
"time"
) )
// FoodOfTheDay is the food list of the day // FoodOfTheDay is the food list of the day
@ -21,7 +22,7 @@ type Food struct {
} }
// GetFoodOfTheDay return the list of food of the day // GetFoodOfTheDay return the list of food of the day
func GetFoodOfTheDay(Today string) FoodOfTheDay { func GetFoodOfTheDay() FoodOfTheDay {
foodcsv, _ := os.Open("foodlist/foods.csv") foodcsv, _ := os.Open("foodlist/foods.csv")
foodreader := csv.NewReader(bufio.NewReader(foodcsv)) foodreader := csv.NewReader(bufio.NewReader(foodcsv))
foods := FoodOfTheDay{} foods := FoodOfTheDay{}
@ -35,7 +36,7 @@ func GetFoodOfTheDay(Today string) FoodOfTheDay {
food := Food{line[0], line[1]} food := Food{line[0], line[1]}
foods.Foods = append(foods.Foods, food) foods.Foods = append(foods.Foods, food)
} }
foods.Date = Today foods.Date = time.Now().Format("02/01/2006")
return foods return foods
} }

BIN
foods.db

Binary file not shown.

BIN
my.db

Binary file not shown.

BIN
server

Binary file not shown.

View File

@ -3,42 +3,48 @@ package main
import ( import (
"cadoles/foodoles/bdd" "cadoles/foodoles/bdd"
"cadoles/foodoles/foodlist" "cadoles/foodoles/foodlist"
votefood "cadoles/foodoles/vote" "cadoles/foodoles/vote"
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
"time"
) )
// Today is today
var Today = time.Now().Format("02/01/2006")
func main() { func main() {
http.HandleFunc("/", base) http.HandleFunc("/", Base)
http.HandleFunc("/results", resultsPage) http.HandleFunc("/results", ResultsPage)
bdd.InitBDD() db, err := bdd.OpenDB()
log.Print("ready: listening on localhost:8080\n") if err != nil {
log.Printf("\nOpenDB error: %v", err)
return
}
bdd.CloseDB(db)
vote.GetVotesOfTheDay()
log.Print("\nready: listening on localhost:8080\n")
if err := http.ListenAndServe(":8080", nil); err != nil { if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err) panic(err)
} }
} }
func base(w http.ResponseWriter, r *http.Request) { // Base is the entry point to all requests
func Base(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
votePage(w, r) VotePage(w, r)
} else if r.Method == http.MethodGet { } else if r.Method == http.MethodGet {
homePage(w, r) HomePage(w, r)
} else { } else {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("400 - Unsupported Request Method!")) w.Write([]byte("400 - Unsupported Request Method!"))
} }
} }
func homePage(w http.ResponseWriter, r *http.Request) { // HomePage is the homepage of the app
foods := foodlist.GetFoodOfTheDay(Today) func HomePage(w http.ResponseWriter, r *http.Request) {
foods := foodlist.GetFoodOfTheDay()
paths := []string{ paths := []string{
"./templates/index.tmpl", "./templates/index.tmpl",
} }
@ -50,23 +56,33 @@ func homePage(w http.ResponseWriter, r *http.Request) {
} }
} }
func resultsPage(w http.ResponseWriter, r *http.Request) { // ResultsPage is the page displaiyng the votes results
func ResultsPage(w http.ResponseWriter, r *http.Request) {
db, err := bdd.OpenDB()
if err != nil {
log.Printf("\nOpenDB error: %v", err)
return
}
//vote, _ := bdd.GetVotesOfTheDay(db, time.Now().AddDate(0, 0, -1))
bdd.CloseDB(db)
paths := []string{ paths := []string{
"./templates/results.tmpl", "./templates/results.tmpl",
} }
t := template.Must(template.New("results.tmpl").ParseFiles(paths...)) t := template.Must(template.New("results.tmpl").ParseFiles(paths...))
err := t.Execute(w, "") err = t.Execute(w, "")
if err != nil { if err != nil {
log.Printf("\nExecute error: %v", err) log.Printf("\nExecute error: %v", err)
return return
} }
} }
func votePage(w http.ResponseWriter, r *http.Request) { // VotePage is the endpoint to add votes
func VotePage(w http.ResponseWriter, r *http.Request) {
r.ParseForm() r.ParseForm()
option := r.Form.Get("option") option := r.Form.Get("option")
log.Print("vote for : ", option) log.Print("vote for : ", option)
votefood.ForFood(Today, option) vote.ForFood(option)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@ -9,6 +9,11 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.js"></script>
</head> </head>
<body> <body>
{{ range .Foods }}
<div>
<div class="ui massive label"> {{ .Icon }}</div>
</div>
{{ end }}
<div class="ui container"> <div class="ui container">
<h2 class="ui header">TV Show - Poll Results</h2><br/> <h2 class="ui header">TV Show - Poll Results</h2><br/>
<div class="ui one column grid link cards"> <div class="ui one column grid link cards">
@ -17,6 +22,7 @@
</div> </div>
</div> </div>
</div> </div>
<div style="color:#fff" id="key">{{.Key}}</div> <div style="color:#fff" id="key">{{.Key}}</div>
<div style="color:#fff" id="cluster">{{.Cluster}}</div> <div style="color:#fff" id="cluster">{{.Cluster}}</div>
</body> </body>

View File

@ -1,5 +1,12 @@
package vote package vote
import (
"cadoles/foodoles/bdd"
"fmt"
"log"
"time"
)
// VotesOfTheDay est le résultat des votes du jour // VotesOfTheDay est le résultat des votes du jour
type VotesOfTheDay struct { type VotesOfTheDay struct {
Date string Date string
@ -13,6 +20,69 @@ type Vote struct {
} }
// ForFood vote pour un choix du jour // ForFood vote pour un choix du jour
func ForFood(Today string, Food string) { func ForFood(Food string) {
db, err := bdd.OpenDB()
if err != nil {
log.Printf("\nOpenDB error: %v", err)
return
}
bdd.AddVote(db, Food, time.Now().AddDate(0, 0, 0))
bdd.CloseDB(db)
return return
} }
// GetVotesOfTheDay récupère les votes du jour
func GetVotesOfTheDay() VotesOfTheDay {
time.Now()
vo := VotesOfTheDay{time.Now().Format("02/01/2006"), nil}
duplicate := FoodList()
dupmap := dupcount(duplicate)
fmt.Println(dupmap)
for k, v := range dupmap {
vv := Vote{k, v}
vo.Votes = append(vo.Votes, vv)
}
fmt.Println(vo)
return vo
}
// FoodList return a list of food
func FoodList() []Vote {
f := []Vote{}
db, err := bdd.OpenDB()
if err != nil {
log.Fatal(err)
}
lvotes, _ := bdd.GetVotesOfTheDay(db, time.Now())
for _, fo := range lvotes {
vf := Vote{fo, 1}
f = append(f, vf)
}
bdd.CloseDB(db)
return f
}
func dupcount(list []Vote) map[string]int {
duplicatefrequency := make(map[string]int)
for _, item := range list {
// check if the item/element exist in the duplicate_frequency map
_, exist := duplicatefrequency[item.Food]
if exist {
duplicatefrequency[item.Food]++ // increase counter by 1 if already in the map
} else {
duplicatefrequency[item.Food] = 1 // else start counting from 1
}
}
return duplicatefrequency
}