Skip to content

Instantly share code, notes, and snippets.

@toVersus
Created April 24, 2018 11:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toVersus/5c596b29eb39a45e8d3b69c0b32cd13f to your computer and use it in GitHub Desktop.
Save toVersus/5c596b29eb39a45e8d3b69c0b32cd13f to your computer and use it in GitHub Desktop.
[Language Processing 100 Essentials] #69: Create web application to search artist information
<!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>
<!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>
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
}
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