Added database search

This commit is contained in:
Eduard Urbach 2017-10-19 21:43:42 +02:00
parent 24914cb6ff
commit da4e026f41
7 changed files with 270 additions and 1 deletions

View File

@ -19,6 +19,7 @@ import (
"github.com/animenotifier/notify.moe/pages/character"
"github.com/animenotifier/notify.moe/pages/charge"
"github.com/animenotifier/notify.moe/pages/dashboard"
"github.com/animenotifier/notify.moe/pages/database"
"github.com/animenotifier/notify.moe/pages/editanime"
"github.com/animenotifier/notify.moe/pages/editor"
"github.com/animenotifier/notify.moe/pages/embed"
@ -153,6 +154,10 @@ func configure(app *aero.Application) *aero.Application {
app.Ajax("/editor/anilist", editor.AniList)
app.Ajax("/editor/shoboi", editor.Shoboi)
// Mixed
app.Ajax("/database", database.Get)
app.Get("/api/select/:data-type/where/:field/is/:field-value", database.Select)
// Import
app.Ajax("/import", listimport.Get)
app.Ajax("/import/anilist/animelist", listimportanilist.Preview)

View File

@ -0,0 +1,11 @@
package database
import (
"github.com/aerogo/aero"
"github.com/animenotifier/notify.moe/components"
)
// Get the dashboard.
func Get(ctx *aero.Context) string {
return ctx.HTML(components.Database())
}

View File

@ -0,0 +1,36 @@
component Database
EditorTabs
.widget-form
.widget
h1.mountable Database search
.widget-section.mountable
label(for="data-type") Search
select#data-type.widget-ui-element(value="Anime")
option(value="Analytics") Analytics
option(value="Anime") Anime
option(value="AnimeList") AnimeList
option(value="Character") Character
option(value="Group") Group
option(value="Post") Post
option(value="Settings") Settings
option(value="SoundTrack") SoundTrack
option(value="Thread") Thread
option(value="User") User
.widget-section.mountable
label(for="field") where
input#field.widget-ui-element(type="text", placeholder="Field name (e.g. Title or Title.Canonical)")
.widget-section.mountable
label(for="field-value") is
input#field-value.widget-ui-element(type="text")
.buttons.mountable
button.action(data-action="searchDB", data-trigger="click")
Icon("search")
span Search
h3.text-center Results
#records

View File

@ -0,0 +1,25 @@
#records
horizontal-wrap
justify-content space-around
margin-top content-padding
.record
vertical
ui-element
padding 0.5rem 1rem
margin 0.5rem
.record-id
:before
content "ID: "
.record-view
//
.record-view-api
//
.record-count
text-align right
font-size 0.8rem
opacity 0.5

113
pages/database/select.go Normal file
View File

@ -0,0 +1,113 @@
package database
import (
"net/http"
"github.com/aerogo/aero"
"github.com/aerogo/mirror"
"github.com/animenotifier/arn"
)
// QueryResponse ..
type QueryResponse struct {
Results []interface{} `json:"results"`
}
// Select ...
func Select(ctx *aero.Context) string {
dataTypeName := ctx.Get("data-type")
field := ctx.Get("field")
searchValue := ctx.Get("field-value")
// Empty values
if dataTypeName == "+" {
dataTypeName = ""
}
if field == "+" {
field = ""
}
if searchValue == "+" {
searchValue = ""
}
// Check empty parameters
if dataTypeName == "" || field == "" {
return ctx.Error(http.StatusBadRequest, "Not enough parameters", nil)
}
// Check data type parameter
_, found := arn.DB.Types()[dataTypeName]
if !found {
return ctx.Error(http.StatusBadRequest, "Invalid type", nil)
}
response := &QueryResponse{
Results: []interface{}{},
}
stream, err := arn.DB.All(dataTypeName)
if err != nil {
return ctx.Error(http.StatusInternalServerError, "Error fetching data from the database", err)
}
process := func(obj interface{}) {
_, _, value, _ := mirror.GetField(obj, field)
if value.String() == searchValue {
response.Results = append(response.Results, obj)
}
}
switch dataTypeName {
case "Analytics":
for obj := range stream.(chan *arn.Analytics) {
process(obj)
}
case "Anime":
for obj := range stream.(chan *arn.Anime) {
process(obj)
}
case "AnimeList":
for obj := range stream.(chan *arn.AnimeList) {
process(obj)
}
case "Character":
for obj := range stream.(chan *arn.Character) {
process(obj)
}
case "Group":
for obj := range stream.(chan *arn.Group) {
process(obj)
}
case "Post":
for obj := range stream.(chan *arn.Post) {
process(obj)
}
case "Settings":
for obj := range stream.(chan *arn.Settings) {
process(obj)
}
case "SoundTrack":
for obj := range stream.(chan *arn.SoundTrack) {
process(obj)
}
case "Thread":
for obj := range stream.(chan *arn.Thread) {
process(obj)
}
case "User":
for obj := range stream.(chan *arn.User) {
process(obj)
}
}
for _, obj := range response.Results {
mirror.GetField(obj, field)
}
return ctx.JSON(response)
}

View File

@ -3,11 +3,12 @@ component Editor
EditorTabs
p Welcome to the Editor Panel!
p.text-center.mountable Welcome to the Editor Panel!
component EditorTabs
.tabs
Tab("Editor", "pencil", "/editor")
Tab("Search", "search", "/database")
Tab("Shoboi", "calendar", "/editor/shoboi")
Tab("AniList", "list", "/editor/anilist")

View File

@ -15,3 +15,81 @@ export function search(arn: AnimeNotifier, search: HTMLInputElement, e: Keyboard
arn.diff("/search/" + term)
}
// Search database
export function searchDB(arn: AnimeNotifier, input: HTMLInputElement, e: KeyboardEvent) {
if(e.ctrlKey || e.altKey) {
return
}
let dataType = (arn.app.find("data-type") as HTMLInputElement).value || "+"
let field = (arn.app.find("field") as HTMLInputElement).value || "+"
let fieldValue = (arn.app.find("field-value") as HTMLInputElement).value || "+"
let records = arn.app.find("records")
arn.loading(true)
fetch(`/api/select/${dataType}/where/${field}/is/${fieldValue}`)
.then(response => {
if(response.status !== 200) {
throw response
}
return response
})
.then(response => response.json())
.then(data => {
records.innerHTML = ""
let count = 0
if(data.results.length === 0) {
records.innerText = "No results."
return
}
for(let record of data.results) {
count++
let container = document.createElement("div")
container.classList.add("record")
let id = document.createElement("div")
id.innerText = record.id
id.classList.add("record-id")
container.appendChild(id)
let link = document.createElement("a")
link.classList.add("record-view")
link.innerText = "Open " + dataType.toLowerCase()
if(dataType === "User") {
link.href = "/+" + record.nick
} else {
link.href = "/" + dataType.toLowerCase() + "/" + record.id
}
link.target = "_blank"
container.appendChild(link)
let apiLink = document.createElement("a")
apiLink.classList.add("record-view-api")
apiLink.innerText = "JSON data"
apiLink.href = "/api/" + dataType.toLowerCase() + "/" + record.id
apiLink.target = "_blank"
container.appendChild(apiLink)
let recordCount = document.createElement("div")
recordCount.innerText = count + "/" + data.results.length
recordCount.classList.add("record-count")
container.appendChild(recordCount)
records.appendChild(container)
}
})
.catch(response => {
response.text().then(text => {
arn.statusMessage.showError(text)
})
})
.then(() => arn.loading(false))
}