Skip to content

Commit

Permalink
User not same pair twice
Browse files Browse the repository at this point in the history
  • Loading branch information
karlsb committed Nov 22, 2024
1 parent 1a6aade commit 1dc2c72
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 46 deletions.
Binary file modified WouldYouRatherBackend/build-database/wouldyourather.db
Binary file not shown.
2 changes: 1 addition & 1 deletion WouldYouRatherBackend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module gcloud-setup-test
go 1.23.3

require (
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
modernc.org/sqlite v1.34.1
)

require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
Expand Down
143 changes: 100 additions & 43 deletions WouldYouRatherBackend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import (
"log"
"net/http"
"os"
"strings"
"time"

"github.com/google/uuid"
"github.com/joho/godotenv"
_ "modernc.org/sqlite" // fast but be careful, since it is written in CGO - might have compatibility issues
)
Expand All @@ -25,6 +28,9 @@ type Choice struct {
LeftRight string `json:"leftright"`
}

// -----UUID: string - pairIDs: []int
var SeenPairs = make(map[string][]int)

/*
* DATABASE
*
Expand All @@ -48,10 +54,27 @@ func (db *Database) Close() {
db.sqldb.Close()
}

func createGetRandomPairQueryString(userID string) (string, []interface{}) {
placeholders := make([]string, len(SeenPairs[userID]))
args := make([]interface{}, len(SeenPairs[userID]))
for i, id := range SeenPairs[userID] {
placeholders[i] = "?"
args[i] = id
}

// Create the query string
queryString := fmt.Sprintf(
"SELECT id, left, right, lcount, rcount FROM pairs WHERE id NOT IN (%s) ORDER BY RANDOM() LIMIT 1",
strings.Join(placeholders, ","),
)
return queryString, args
}

// NOW ONLY GETS TOP
func (db Database) getRandomPair() TextPair {
func (db Database) getRandomPair(userID string) TextPair {
// get number of rows pick an id in the range of num of rows
rows, err := db.sqldb.Query("SELECT id, left, right, lcount, rcount FROM pairs ORDER BY RANDOM() LIMIT 1")
queryString, args := createGetRandomPairQueryString(userID)
rows, err := db.sqldb.Query(queryString, args...)
if err != nil {
fmt.Println("error in db.Query")
}
Expand Down Expand Up @@ -103,66 +126,50 @@ var db Database

func getRandomPairHandler(w http.ResponseWriter, r *http.Request) {
//respond with json
cookie, err := r.Cookie("user_id")
if err != nil {
newUserID := uuid.New().String()
cookie = &http.Cookie{
Name: "user_id",
Value: newUserID,
Path: "/",
Expires: time.Now().Add(24 * time.Hour),
}
log.Println("Generated new user ID:", newUserID)
log.Println("cookie created: ", cookie)
} else {
log.Println("we have a cookie: ", cookie)
}

response := Message{
Status: "success",
Pair: db.getRandomPair(),
Pair: db.getRandomPair(cookie.Value),
}

SeenPairs[cookie.Value] = append(SeenPairs[cookie.Value], response.Pair.Id)
w.Header().Set("Content-Type", "application/json")

http.SetCookie(w, cookie)
log.Println("Headers", w.Header())
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to encdode JSON", http.StatusInternalServerError)
}
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, World!")
}

// a template for middleware, can use for logging aswell?
func routeCheckMiddleware(expectedPath string, handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != expectedPath {
http.NotFound(w, r)
return
}
handler(w, r)
}
}

func enableCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
allowed_origin := os.Getenv("ALLOWED_ORIGIN")
w.Header().Set("Access-Control-Allow-Origin", allowed_origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

if r.Method == http.MethodOptions {
w.WriteHeader((http.StatusNoContent))
return
}
next.ServeHTTP(w, r)
})

}

func loggerMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log_level := os.Getenv("LOG_LEVEL")
if log_level == "DEV" {
log.Println(r.Body)
}
next.ServeHTTP(w, r)
})

fmt.Fprint(w, "Hello There")
}

func storeAnswer(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
cookie, err := r.Cookie("user_id")
if err != nil {
http.Error(w, "Invalid cookie", http.StatusBadRequest)
}

log.Println("cookie: ", cookie)

var choice Choice

Expand All @@ -183,6 +190,13 @@ func storeAnswer(w http.ResponseWriter, r *http.Request) {
Pair: db.increaseCountAndReturnPair(choice),
}

value, exists := SeenPairs[cookie.Value]
if !exists {
log.Fatal("we dont have a SeenPair value of: ", cookie.Value)
} else {
log.Println(value)
}

// TODO I can break this out into its own method
w.Header().Set("Content-Type", "application/json")

Expand All @@ -192,6 +206,45 @@ func storeAnswer(w http.ResponseWriter, r *http.Request) {

}

// a template for middleware, can use for logging aswell?
func routeCheckMiddleware(expectedPath string, handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != expectedPath {
http.NotFound(w, r)
return
}
handler(w, r)
}
}

func enableCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
allowed_origin := os.Getenv("ALLOWED_ORIGIN")
w.Header().Set("Access-Control-Allow-Origin", allowed_origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
w.Header().Set("Access-Control-Allow-Credentials", "true")

if r.Method == http.MethodOptions {
w.WriteHeader((http.StatusNoContent))
return
}
next.ServeHTTP(w, r)
})

}

func loggerMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//log_level := os.Getenv("LOG_LEVEL")
//if log_level == "DEV" {
//log.Println(r.Body)
//}
next.ServeHTTP(w, r)
})

}

func main() {
err := godotenv.Load()
if err != nil {
Expand All @@ -200,6 +253,10 @@ func main() {
db.init()
defer db.Close()

//TESTTING

//

mux := http.NewServeMux()

mux.HandleFunc("/", routeCheckMiddleware("/", indexHandler))
Expand Down
13 changes: 11 additions & 2 deletions WouldYouRatherClient/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ type CardProps = {
handleClick: (e:React.MouseEvent<HTMLDivElement, MouseEvent>) => void
}




const random_pair_url = import.meta.env.VITE_RANDOM_PAIR_URL
const store_answer_url = import.meta.env.VITE_STORE_ANSWER_URL

Expand Down Expand Up @@ -50,7 +53,7 @@ function CardWrapper(props: CardWrapperProps) {
const handleClick = async (leftright: string, e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
e.preventDefault()
if(!choiceMade) {
const res = await fetch(store_answer_url, {method:"POST", headers: {"Content-Type":"application/json"}, body: JSON.stringify({"id":props.pair.id , "leftright": leftright })}) //need to attach payload
const res = await fetch(store_answer_url, {method:"POST", credentials:"include", headers: {"Content-Type":"application/json"}, body: JSON.stringify({"id":props.pair.id , "leftright": leftright })}) //need to attach payload
if(res.ok) {
const data = await res.json()
const lpercentage = data.pair.lcount * 100 / (data.pair.lcount + data.pair.rcount)
Expand Down Expand Up @@ -79,8 +82,10 @@ function App() {
const [pair,setPair] = useState<Pair>({id:-1, left:"Welcome to",right:"Would you rather"})

async function apiCall(){
const res = await fetch(random_pair_url, {method:"GET", headers: {"Content-Type":"application/json"}})
const res = await fetch(random_pair_url, {method:"GET", credentials:"include",headers: {"Content-Type":"application/json"}})
console.log(res)
if(res.ok) {
console.log(document.cookie)
const data = await res.json()
setPair({id:data.pair.id, left:data.pair.left, right:data.pair.right})
}
Expand All @@ -89,6 +94,10 @@ function App() {
}
}

useEffect(() => {
apiCall()
},[])

return (
<div className="h-screen bg-slate-100">
<div className="h-1/6 bg-blue-400 flex justify-center items-center"> {/* NavBar */}
Expand Down

0 comments on commit 1dc2c72

Please sign in to comment.