Created
April 24, 2018 11:48
-
-
Save toVersus/5c596b29eb39a45e8d3b69c0b32cd13f to your computer and use it in GitHub Desktop.
[Language Processing 100 Essentials] #69: Create web application to search artist information
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Document</title> | |
</head> | |
<style> | |
h1 { | |
font: 2em sans-serif; | |
margin: 0 auto; | |
padding: 0.5em; | |
text-align: center; | |
} | |
h2 { | |
font: 1.5em sans-serif; | |
margin: 0 auto; | |
padding: 0.5em; | |
text-align: center; | |
} | |
div+div { | |
margin-top: 1em; | |
} | |
.button { | |
text-align: center; | |
} | |
.square-button { | |
font: 0.8em sans-serif; | |
display: inline-block; | |
padding: 0.5em 1em; | |
text-decoration: none; | |
background-color: white; | |
color: black; | |
border: 1px solid rgba(0, 0, 0, 0.514); | |
border-radius: 8px; | |
transition-duration: 0.4s; | |
} | |
.square-button:hover { | |
background-color: rgba(0, 0, 0, 0.514); | |
color: white; | |
} | |
table { | |
margin-left: auto; | |
margin-right: auto; | |
border-collapse: collapse; | |
} | |
th { | |
border: solid 1px; | |
padding: 0.5em; | |
background: #ccccff | |
} | |
td { | |
text-align: center; | |
border: solid 1px; | |
padding: 0.5em; | |
} | |
</style> | |
<body> | |
<h1> Search Results </h1> | |
<h2> {{ len . }} artists found...</h2> | |
<div class="button"> | |
<button class="square-button" type="button" onclick="history.back()">Back</button> | |
</div> | |
<div> | |
<table> | |
<tr> | |
<th> | |
<strong>Rating</strong> | |
</th> | |
<th> | |
<strong>Name</strong> | |
</th> | |
<th> | |
<strong>Area</strong> | |
</th> | |
</tr> | |
{{ range . }} | |
<tr> | |
<td>{{ if .Rating }} {{ .Rating.Count }} {{ else }} NA {{ end }}</td> | |
<td>{{ .Name }}</td> | |
<td>{{ if .Area }}{{ .Area }} {{ else }} Unknown {{ end }} </td> | |
</tr> | |
{{ end }} | |
</table> | |
</div> | |
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Document</title> | |
</head> | |
<style> | |
h1 { | |
font: 2em sans-serif; | |
margin: 0 auto; | |
width: 300px; | |
padding: 0.5em; | |
text-align: center; | |
} | |
form { | |
margin: 0 auto; | |
width: 300px; | |
padding: 1em; | |
border: 1px solid rgba(37, 37, 37, 0.144); | |
border-radius: 1em; | |
} | |
form div+div { | |
margin-top: 1em; | |
} | |
label { | |
display: inline-block; | |
width: 25%; | |
text-align: right; | |
} | |
input { | |
font: 1em sans-serif; | |
width: 190px; | |
-moz-box-sizing: border-box; | |
box-sizing: border-box; | |
border: 1px solid #999; | |
} | |
input:focus { | |
border-color: #000; | |
} | |
.square-button { | |
font: 0.8em sans-serif; | |
display: inline-block; | |
padding: 0.5em 1em; | |
text-decoration: none; | |
background-color: white; | |
color: black; | |
border: 1px solid rgba(0, 0, 0, 0.514); | |
border-radius: 8px; | |
transition-duration: 0.4s; | |
} | |
.square-button:hover { | |
background-color: rgba(0, 0, 0, 0.514); | |
color: white; | |
} | |
.button { | |
text-align: center; | |
} | |
</style> | |
<body> | |
<h1>Artist Database</h1> | |
<form action="/result/" method="POST"> | |
<div> | |
<label for="artist-name">Name:</label> | |
<input class="search-condition" type="text" name="name" /> | |
</div> | |
<div> | |
<label for="artist-alias">Alias:</label> | |
<input class="search-condition" type="text" name="alias" /> | |
</div> | |
<div> | |
<label for="artist-tag">Tag:</label> | |
<input class="search-condition" type="text" name="tag" /> | |
</div> | |
<div class="button"> | |
<button class="square-button" type="submit">Search</button> | |
</div> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"html/template" | |
"io" | |
"log" | |
"net/http" | |
"os" | |
mgo "gopkg.in/mgo.v2" | |
"gopkg.in/mgo.v2/bson" | |
) | |
type Artist struct { | |
ID int `json:"id"` | |
GID string `json:"gid"` | |
Name string `json:"name"` | |
SortName string `json:"sort_name"` | |
Area string `json:"area"` | |
Aliases []*Alias `json:"aliases"` | |
Begin *Begin `json:"begin"` | |
End *End `json:"end"` | |
Tags []*Tag `json:"tags"` | |
Rating *Rating `json:"rating"` | |
} | |
type Artists []*Artist | |
type Alias struct { | |
Name string `json:"name"` | |
SortName string `json:"sort_name"` | |
} | |
type Begin struct { | |
Year int `json:"year"` | |
Month int `json:"month"` | |
Date int `json:"date"` | |
} | |
type End struct { | |
Year int `json:"year"` | |
Month int `json:"month"` | |
Date int `json:"date"` | |
} | |
type Tag struct { | |
Count int `json:"count"` | |
Value string `json:"value"` | |
} | |
type Rating struct { | |
Count int `json:"count"` | |
Value int `json:"value"` | |
} | |
func main() { | |
http.HandleFunc("/search/", searchHandler) | |
http.HandleFunc("/result/", resultHandler) | |
log.Fatal(http.ListenAndServe(":8080", nil)) | |
} | |
func searchHandler(w http.ResponseWriter, r *http.Request) { | |
if r.Method == "GET" { | |
t, _ := template.ParseFiles("search.html") | |
t.Execute(w, nil) | |
} else { | |
r.ParseForm() | |
fmt.Println(r.Form) | |
} | |
} | |
func resultHandler(w http.ResponseWriter, r *http.Request) { | |
session, err := mgo.Dial("mongodb://localhost") | |
if err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
c := session.DB("MusicBrainz").C("artist") | |
searchOpt := bson.M{} | |
r.ParseForm() | |
if r.Form["name"][0] != "" { | |
searchOpt["name"] = r.Form["name"][0] | |
} | |
if r.Form["alias"][0] != "" { | |
fmt.Println("ok") | |
searchOpt["aliases.name"] = r.Form["alias"][0] | |
} | |
if r.Form["tag"][0] != "" { | |
searchOpt["tags.value"] = r.Form["tag"][0] | |
} | |
artists := Artists{} | |
if len(searchOpt) > 0 { | |
if err = c.Find(searchOpt).Sort("-rating.count").All(&artists); err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
} | |
t, _ := template.ParseFiles("result.html") | |
t.Execute(w, artists) | |
} | |
func readBSON(path string) (Artists, error) { | |
f, err := os.Open(path) | |
if err != nil { | |
return nil, fmt.Errorf("could not open a file: %s\n %s", path, err) | |
} | |
defer f.Close() | |
var artists Artists | |
reader := bufio.NewReader(f) | |
for { | |
artist := Artist{} | |
buf, readErr := reader.ReadBytes('\n') | |
if (readErr != nil) && (readErr != io.EOF) { | |
panic(err) | |
} | |
if err = bson.UnmarshalJSON(buf, &artist); err != nil && readErr != io.EOF { | |
fmt.Print("could not parse json file.") | |
break | |
} | |
artists = append(artists, &artist) | |
if readErr == io.EOF { | |
break | |
} | |
} | |
return artists, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"io/ioutil" | |
"net/http" | |
"net/http/httptest" | |
"testing" | |
) | |
func TestSearchHandler(t *testing.T) { | |
t.Log("should get the 200 OK status") | |
ts := httptest.NewServer(http.HandlerFunc(searchHandler)) | |
defer ts.Close() | |
res, err := http.Get(ts.URL + "/search/") | |
if err != nil { | |
t.Error("unexpected response") | |
} | |
body, err := ioutil.ReadAll(res.Body) | |
res.Body.Close() | |
t.Log(string(body)) | |
if res.StatusCode != 200 { | |
t.Error("Incorrect status code:", res.StatusCode) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment