Skip to content

Commit

Permalink
Merge pull request #3 from anGie44/f-season-connections
Browse files Browse the repository at this point in the history
feat: add back in connections support
  • Loading branch information
anGie44 authored Jun 5, 2022
2 parents 7afdbc1 + 32647cf commit 653bc32
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 31 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Currently used for: https://angie44.github.io/theOffice

## GET

* Get quotes or nodes/links by season number ⚠️ **Under Maintenance (only `quotes` supported at this time)** ⚠️
* Get quotes or nodes/links by season number
* **URL:** _/season/:season/format/:format_
* **Method:** `GET`
* **URL Params:**
Expand All @@ -26,7 +26,7 @@ Currently used for: https://angie44.github.io/theOffice
* **Success Response:**
* **Code:** 200
* **Content [Quotes]:** `[{ "season": seasonNumber, "episode" : episodeNumber, "scene": sceneNumber, "episode_name": episodeName, "character": character, "quote" : quote}]`
* **Content [Connections]:** `{ "data" : [{ "episode": episodeNumber, "name": episodeName, "links" : [{ "source" : characterName, "target": characterName, "value" : numberOfCoOccurencesInEpisode }], "nodes" : [{ "id" : characterName }]}`
* **Content [Connections]:** `[{ "episode": episodeNumber, "name": episodeName, "links" : [{ "source" : characterName, "target": characterName, "value" : numberOfCoOccurencesInEpisode }], "nodes" : [{ "id" : characterName }]`


* Get quotes for a specific season and episode
Expand Down
116 changes: 116 additions & 0 deletions data/connections.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package data

import (
combinations "github.com/mxschmitt/golang-combinations"
)

type Connection struct {
Episode int `bson:"episode" json:"episode"`
EpisodeName string `bson:"episode_name" json:"episode_name"`
Links []*Link `bson:"links" json:"links"`
Nodes []*Node `bson:"nodes" json:"nodes"`
}

type Link struct {
Source string `bson:"source" json:"source"`
Target string `bson:"target" json:"target"`
Value int `bson:"value" json:"value"`
}

type Node struct {
Id string `bson:"id" json:"id"`
}

type Connections []*Connection

type episode struct {
name string
scenes map[int]Quotes
}

func GetConnectionsPerEpisode(seasonQuotes Quotes) Connections {
// Map of quotes per episode
quotesByEpisode := make(map[int]*episode)

for _, quote := range seasonQuotes {
_, ok := quotesByEpisode[quote.Episode]
if ok {
_, sceneOk := quotesByEpisode[quote.Episode].scenes[quote.Scene]
if sceneOk {
quotesByEpisode[quote.Episode].scenes[quote.Scene] = append(quotesByEpisode[quote.Episode].scenes[quote.Scene], quote)
} else {
quotesByEpisode[quote.Episode].scenes[quote.Scene] = Quotes{quote}
}
} else {
quotesByEpisode[quote.Episode] = &episode{
name: quote.EpisodeName,
scenes: map[int]Quotes{
quote.Scene: []*Quote{quote},
},
}
}
}

var connections Connections

for episodeNum, episode := range quotesByEpisode {
// Loop through scenes in an episode
linksMap := make(map[Link]int)
nodesMap := make(map[string]struct{})

for _, quotes := range episode.scenes {
charactersInScene := make(map[string]struct{})
var exists = struct{}{}

for _, quote := range quotes {
charactersInScene[quote.Character] = exists
}

var chars []string
for c := range charactersInScene {
chars = append(chars, c)
nodesMap[c] = exists
}

if len(chars) < 2 {
continue
}

combinations := combinations.Combinations(chars, 2)

for _, combo := range combinations {
link := Link{
Source: combo[0],
Target: combo[1],
}

linksMap[link]++
}
}

var nodes []*Node
for c := range nodesMap {
nodes = append(nodes, &Node{
Id: c,
})
}

var links []*Link
for l, count := range linksMap {
links = append(links, &Link{
Source: l.Source,
Target: l.Target,
Value: count,
})
}

connections = append(connections, &Connection{
Episode: episodeNum,
EpisodeName: episode.name,
Links: links,
Nodes: nodes,
})
}

return connections
}
2 changes: 1 addition & 1 deletion data/quotes.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (q *QuotesDB) GetQuotes() (Quotes, error) {
}

// GetQuotesBySeason returns all quotes for the given season from the database
func (q *QuotesDB) GetQuotesBySeason(season int, format string) (Quotes, error) {
func (q *QuotesDB) GetQuotesBySeason(season int) (Quotes, error) {
serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1)
clientOptions := options.Client().
ApplyURI(fmt.Sprintf("mongodb+srv://%s:%s@%s", q.opts.username, q.opts.password, q.opts.hostname)).
Expand Down
6 changes: 1 addition & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@ module github.com/anGie44/theOffice-api
go 1.18

require (
github.com/go-playground/validator v9.31.0+incompatible
github.com/gorilla/mux v1.8.0
github.com/mxschmitt/golang-combinations v1.1.0
github.com/nicholasjackson/env v0.6.0
go.mongodb.org/mongo-driver v1.9.1
)

require (
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
Expand All @@ -25,6 +22,5 @@ require (
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
13 changes: 2 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA=
github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
Expand All @@ -20,9 +14,9 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mxschmitt/golang-combinations v1.1.0 h1:WlIZCnDm+Xlb2pRPf+R/qPKlGOU1w8lpN69/uy5z+Zg=
github.com/mxschmitt/golang-combinations v1.1.0/go.mod h1:RbMhWvfCelHR6WROvT2bVfxJvZHoEvBj71SKe+H0MYU=
github.com/nicholasjackson/env v0.6.0 h1:6xdio52m7cKRtgZPER6NFeBZxicR88rx5a+5Jl4/qus=
github.com/nicholasjackson/env v0.6.0/go.mod h1:/GtSb9a/BDUCLpcnpauN0d/Bw5ekSI1vLC1b9Lw0Vyk=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down Expand Up @@ -60,7 +54,6 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand All @@ -69,8 +62,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
24 changes: 16 additions & 8 deletions handlers/get.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package handlers

import (
"fmt"
"net/http"

"github.com/anGie44/theOffice-api/data"
Expand All @@ -26,7 +25,7 @@ func (q *Quotes) GetQuotes(rw http.ResponseWriter, r *http.Request) {

// GetQuotesBySeason handles GET requests and returns quotes for the specified season and format
// GET /season/{season}/format/{format}
func (q *Quotes) GetQuotesBySeason(rw http.ResponseWriter, r *http.Request) {
func (q *Quotes) GetQuotesBySeasonWithFormat(rw http.ResponseWriter, r *http.Request) {
season, err := getSeason(r)
if err != nil {
http.Error(rw, "Unable to convert season", http.StatusBadRequest)
Expand All @@ -37,23 +36,32 @@ func (q *Quotes) GetQuotesBySeason(rw http.ResponseWriter, r *http.Request) {
if format == "" {
http.Error(rw, "Must specify a format", http.StatusBadRequest)
return
} else if format != "quotes" {
http.Error(rw, fmt.Sprintf("%s format not implemented", format), http.StatusNotImplemented)
return
}

q.l.Printf("Handle GET Quotes for Season (%d) in Format (%s)\n", season, format)

quotes, err := q.quotesDB.GetQuotesBySeason(season, format)
quotes, err := q.quotesDB.GetQuotesBySeason(season)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
data.ToJSON(&GenericError{Message: err.Error()}, rw)
return
}

err = data.ToJSON(quotes, rw)
if format == "quotes" {
err = data.ToJSON(quotes, rw)
if err != nil {
http.Error(rw, "Unable to marshal quotes json", http.StatusInternalServerError)
}
return
}

// Connections

connections := data.GetConnectionsPerEpisode(quotes)

err = data.ToJSON(connections, rw)
if err != nil {
http.Error(rw, "Unable to marshal json", http.StatusInternalServerError)
http.Error(rw, "Unable to marshal connections json", http.StatusInternalServerError)
}
}

Expand Down
11 changes: 7 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ var dbPassword = env.String("MONGODB_PASSWORD", false, "password", "mongodb data
var dbCollection = env.String("MONGODB_COLLECTION", false, "quotes", "mongodb database collection")

func main() {
bindAddress := fmt.Sprintf(":%s", os.Getenv("PORT")) // value provided by Heroku
if bindAddress == "" {
var bindAddress string
port := os.Getenv("PORT") // value provided by Heroku
if port == "" {
bindAddress = ":8080"
} else {
bindAddress = fmt.Sprintf(":%s", port)
}

env.Parse()
Expand All @@ -44,7 +47,7 @@ func main() {
getRouter := sm.Methods(http.MethodGet).Subrouter()
getRouter.HandleFunc("/", wh.Welcome)
// Deprecated handlers
getRouter.HandleFunc("/season/{season:[1-9]}/format/{format:quotes|connections}", qh.GetQuotesBySeason)
getRouter.HandleFunc("/season/{season:[1-9]}/format/{format:quotes|connections}", qh.GetQuotesBySeasonWithFormat)
getRouter.HandleFunc("/season/{season:[1-9]}/episode/{episode:[1-9]|[1][0-9]|2[0-3]}", qh.GetQuotesBySeasonAndEpisode)
// V2 handlers to use request body for filtering data
getRouter.HandleFunc("/v2/quotes", qh.GetQuotes)
Expand All @@ -53,7 +56,7 @@ func main() {
Addr: bindAddress,
Handler: sm,
ErrorLog: l,
ReadTimeout: 5 * time.Second,
ReadTimeout: 1 * time.Minute,
IdleTimeout: 2 * time.Minute,
}

Expand Down

0 comments on commit 653bc32

Please sign in to comment.