Merge pull request #178 from velour/web

Web
This commit is contained in:
Chris Sexton 2019-05-27 23:19:49 -04:00 committed by GitHub
commit 3d47d03ce0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 129 additions and 117 deletions

View File

@ -138,7 +138,7 @@ var rootIndex = `
<html> <html>
<head> <head>
<title>Factoids</title> <title>Factoids</title>
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.1.0/pure-min.css"> <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css" integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
</head> </head>
{{if .EndPoints}} {{if .EndPoints}}

View File

@ -117,6 +117,8 @@ var indexHTML = `
}, },
send(evt) { send(evt) {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation()
this.input = "";
if (!this.authenticated) { if (!this.authenticated) {
console.log("User is a bot."); console.log("User is a bot.");
this.err = "User appears to be a bot."; this.err = "User appears to be a bot.";

View File

@ -14,6 +14,7 @@ var html = `
<script src="//unpkg.com/vue@latest/dist/vue.min.js"></script> <script src="//unpkg.com/vue@latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script> <script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>Counters</title>
</head> </head>
<body> <body>

View File

@ -4,6 +4,7 @@ package fact
import ( import (
"database/sql" "database/sql"
"encoding/json"
"fmt" "fmt"
"html/template" "html/template"
"math/rand" "math/rand"
@ -759,6 +760,7 @@ func (p *FactoidPlugin) factTimer(c bot.Connector, channel string) {
// Register any web URLs desired // Register any web URLs desired
func (p *FactoidPlugin) registerWeb() { func (p *FactoidPlugin) registerWeb() {
http.HandleFunc("/factoid/api", p.serveAPI)
http.HandleFunc("/factoid/req", p.serveQuery) http.HandleFunc("/factoid/req", p.serveQuery)
http.HandleFunc("/factoid", p.serveQuery) http.HandleFunc("/factoid", p.serveQuery)
p.Bot.RegisterWeb("/factoid", "Factoid") p.Bot.RegisterWeb("/factoid", "Factoid")
@ -773,28 +775,38 @@ func linkify(text string) template.HTML {
} }
return template.HTML(strings.Join(parts, " ")) return template.HTML(strings.Join(parts, " "))
} }
func (p *FactoidPlugin) serveAPI(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
fmt.Fprintf(w, "Incorrect HTTP method")
return
}
info := struct {
Query string `json:"query"`
}{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&info)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
entries, err := getFacts(p.db, info.Query, "")
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
data, err := json.Marshal(entries)
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
w.Write(data)
}
func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) { func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) {
context := make(map[string]interface{}) fmt.Fprint(w, factoidIndex)
funcMap := template.FuncMap{
// The name "title" is what the function will be called in the template text.
"linkify": linkify,
}
if e := r.FormValue("entry"); e != "" {
entries, err := getFacts(p.db, e, "")
if err != nil {
log.Error().Err(err).Msg("Web error searching")
}
context["Count"] = fmt.Sprintf("%d", len(entries))
context["Entries"] = entries
context["Search"] = e
}
t, err := template.New("factoidIndex").Funcs(funcMap).Parse(factoidIndex)
if err != nil {
log.Error().Err(err)
}
err = t.Execute(w, context)
if err != nil {
log.Error().Err(err)
}
} }

View File

@ -9,104 +9,101 @@ package fact
var factoidIndex = ` var factoidIndex = `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CMutationObserver"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue@latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/vue-router"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<meta charset="UTF-8">
<title>Factoids</title> <title>Factoids</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pure/0.6.0/base-min.css">
<!-- DataTables CSS -->
<link rel="stylesheet" type="text/css" href="https://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css">
<!-- jQuery -->
<script type="text/javascript" charset="utf8" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.min.js"></script>
<!-- DataTables -->
<script type="text/javascript" charset="utf8" src="https://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
</head> </head>
<div> <body>
<form action="/factoid" method="GET" class="pure-form">
<fieldset> <div id="app">
<legend>Search for a factoid</legend> <h1>Factoids</h1>
<input type="text" name="entry" placeholder="trigger" value="{{.Search}}" /> <b-alert
<button type="submit" class="pure-button notice">Find</button> dismissable
</fieldset> variant="error"
</form> v-if="err"
@dismissed="err = ''">
{{ err }}
</b-alert>
<b-form @submit="runQuery">
<b-container>
<b-row>
<b-col cols="10">
<b-input v-model="query"></b-input>
</b-col>
<b-col cols="2">
<b-button>Search</b-button>
</b-col>
</b-row>
<b-row>
<b-col>
<b-table
fixed
:items="results"
:fields="fields"></b-table>
</b-col>
</b-row>
</b-container>
</b-form>
</div> </div>
<div>
<style scoped>
.pure-button-success,
.pure-button-error,
.pure-button-warning,
.pure-button-secondary {
color: white;
border-radius: 4px;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
padding: 2px;
}
.pure-button-success {
background: rgb(76, 201, 71); /* this is a green */
}
.pure-button-error {
background: rgb(202, 60, 60); /* this is a maroon */
}
.pure-button-warning {
background: orange;
}
.pure-button-secondary {
background: rgb(95, 198, 218); /* this is a light blue */
}
</style>
{{if .Error}}
<span id="error" class="pure-button-error">{{.Error}}</span>
{{end}}
{{if .Count}}
<span id="count" class="pure-button-success">Found {{.Count}} entries.</span>
{{end}}
</div>
{{if .Entries}}
<div style="padding-top: 1em;">
<table class="pure-table" id="factTable">
<thead>
<tr>
<th>Trigger</th>
<th>Full Text</th>
<th>Author</th>
<th># Hits</th>
</tr>
</thead>
<tbody>
{{range .Entries}}
<tr>
<td>{{linkify .Fact}}</td>
<td>{{linkify .Tidbit}}</td>
<td>{{linkify .Owner}}</td>
<td>{{.Count}}</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{end}}
<script> <script>
$(document).ready(function(){ var router = new VueRouter({
$('#factTable').dataTable({ mode: 'history',
"bPaginate": false routes: []
});
}); });
var app = new Vue({
el: '#app',
router,
data: {
err: '',
query: '',
results: [],
fields: [
{ key: 'Fact', sortable: true },
{ key: 'Tidbit', sortable: true },
{ key: 'Owner', sortable: true },
{ key: 'Count' }
]
},
mounted() {
if (this.$route.query.query) {
this.query = this.$route.query.query;
this.runQuery()
}
},
computed: {
result0: function() {
return this.results[0] || "";
}
},
methods: {
runQuery: function(evt) {
if (evt) {
evt.preventDefault();
evt.stopPropagation()
}
axios.post('/factoid/api', {query: this.query})
.then(resp => {
this.results = resp.data;
})
.catch(err => (this.err = err));
}
}
})
</script> </script>
</body>
</html> </html>
` `