Compare commits
No commits in common. "e9360e50823df0ebd942b0f59a3273fc820e39f9" and "6ac7ba8fd04d0b0b15eb2d73377397c6853e79f6" have entirely different histories.
e9360e5082
...
6ac7ba8fd0
|
@ -15,7 +15,6 @@ type Entry struct {
|
||||||
db *db.Database
|
db *db.Database
|
||||||
ID int64
|
ID int64
|
||||||
Slug string
|
Slug string
|
||||||
Title string
|
|
||||||
Content string
|
Content string
|
||||||
Tags []string
|
Tags []string
|
||||||
Created time.Time
|
Created time.Time
|
||||||
|
@ -52,18 +51,13 @@ func PrepareTable(tx *sqlx.Tx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(db *db.Database) *Entry {
|
func New(db *db.Database) Entry {
|
||||||
e := Entry{
|
return Entry{
|
||||||
db: db,
|
db: db,
|
||||||
ID: -1,
|
ID: -1,
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
Updated: time.Now(),
|
Updated: time.Now(),
|
||||||
Tags: []string{},
|
|
||||||
}
|
}
|
||||||
e.Title = e.GenerateTitle()
|
|
||||||
e.Slug = e.UniqueSlug()
|
|
||||||
e.Content = "= " + e.Title
|
|
||||||
return &e
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBySlug(db *db.Database, slug string) (Entry, error) {
|
func GetBySlug(db *db.Database, slug string) (Entry, error) {
|
||||||
|
@ -72,7 +66,6 @@ func GetBySlug(db *db.Database, slug string) (Entry, error) {
|
||||||
if err := db.Get(&e, q, slug); err != nil {
|
if err := db.Get(&e, q, slug); err != nil {
|
||||||
return e, err
|
return e, err
|
||||||
}
|
}
|
||||||
e.Title = e.GenerateTitle()
|
|
||||||
return e, e.populateTags()
|
return e, e.populateTags()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,21 +75,19 @@ func GetByID(db *db.Database, id int64) (Entry, error) {
|
||||||
if err := db.Get(&e, q, id); err != nil {
|
if err := db.Get(&e, q, id); err != nil {
|
||||||
return e, err
|
return e, err
|
||||||
}
|
}
|
||||||
e.Title = e.GenerateTitle()
|
|
||||||
return e, e.populateTags()
|
return e, e.populateTags()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Search(db *db.Database, query string) ([]*Entry, error) {
|
func Search(db *db.Database, query string) ([]*Entry, error) {
|
||||||
entries := []*Entry{}
|
entries := []*Entry{}
|
||||||
log.Debug().Str("query", query).Msg("searching")
|
|
||||||
if query != "" {
|
if query != "" {
|
||||||
q := `select * from entries where content like ? order by updated desc`
|
q := `select * from entries where content like '%?%'`
|
||||||
err := db.Select(&entries, q, "%"+query+"%")
|
err := db.Select(&entries, q, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
q := `select * from entries order by updated desc`
|
q := `select * from entries`
|
||||||
err := db.Select(&entries, q)
|
err := db.Select(&entries, q)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -104,7 +95,6 @@ func Search(db *db.Database, query string) ([]*Entry, error) {
|
||||||
}
|
}
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
e.db = db
|
e.db = db
|
||||||
e.Title = e.GenerateTitle()
|
|
||||||
e.populateTags()
|
e.populateTags()
|
||||||
}
|
}
|
||||||
return entries, nil
|
return entries, nil
|
||||||
|
@ -124,12 +114,12 @@ func RemoveBySlug(db *db.Database, slug string) error {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
q = `delete from entries where id = ?`
|
q = `delete from entries where entry_id = ?`
|
||||||
if _, err := tx.Exec(q, e.ID); err != nil {
|
if _, err := tx.Exec(q, e.ID); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return tx.Commit()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Entry) populateTags() error {
|
func (e *Entry) populateTags() error {
|
||||||
|
@ -151,16 +141,18 @@ func (e *Entry) removeTag(tag string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Entry) GenerateTitle() string {
|
func (e *Entry) UniqueSlug() string {
|
||||||
candidate := strings.Split(e.Content, "\n")[0]
|
candidate := strings.Split(e.Content, "\n")[0]
|
||||||
candidateNumber := 0
|
candidateNumber := 0
|
||||||
|
|
||||||
r := regexp.MustCompile(`[^a-zA-Z0-9 -]`)
|
r := regexp.MustCompile(`[^a-zA-Z0-9 -]`)
|
||||||
candidate = r.ReplaceAllString(candidate, "")
|
candidate = r.ReplaceAllString(candidate, "")
|
||||||
candidate = strings.TrimSpace(candidate)
|
candidate = strings.TrimSpace(candidate)
|
||||||
|
candidate = strings.ReplaceAll(candidate, " ", "-")
|
||||||
if len(candidate) == 0 {
|
if len(candidate) == 0 {
|
||||||
candidate = "untitled"
|
candidate = "untitled"
|
||||||
}
|
}
|
||||||
|
candidate = strings.ToLower(candidate)
|
||||||
|
|
||||||
q := `select slug from entries where slug like ?`
|
q := `select slug from entries where slug like ?`
|
||||||
slugs := []string{}
|
slugs := []string{}
|
||||||
|
@ -187,20 +179,6 @@ func (e *Entry) GenerateTitle() string {
|
||||||
return tmpCandidate
|
return tmpCandidate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Entry) UniqueSlug() string {
|
|
||||||
if e.Title == "" {
|
|
||||||
e.Title = e.GenerateTitle()
|
|
||||||
}
|
|
||||||
candidate := e.Title
|
|
||||||
|
|
||||||
r := regexp.MustCompile(`[^a-zA-Z0-9 -]`)
|
|
||||||
candidate = r.ReplaceAllString(candidate, "")
|
|
||||||
candidate = strings.TrimSpace(candidate)
|
|
||||||
candidate = strings.ReplaceAll(candidate, " ", "-")
|
|
||||||
candidate = strings.ToLower(candidate)
|
|
||||||
return candidate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Entry) Update() error {
|
func (e *Entry) Update() error {
|
||||||
if e.ID == -1 {
|
if e.ID == -1 {
|
||||||
return e.Create()
|
return e.Create()
|
||||||
|
|
|
@ -7,11 +7,6 @@
|
||||||
<b-nav-item to="/console">Console</b-nav-item>
|
<b-nav-item to="/console">Console</b-nav-item>
|
||||||
<b-nav-item to="/about">About</b-nav-item>
|
<b-nav-item to="/about">About</b-nav-item>
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
<b-navbar-nav class="ml-auto">
|
|
||||||
<b-nav-form>
|
|
||||||
<b-button @click="newFile">+</b-button>
|
|
||||||
</b-nav-form>
|
|
||||||
</b-navbar-nav>
|
|
||||||
</b-navbar>
|
</b-navbar>
|
||||||
<Error/>
|
<Error/>
|
||||||
<router-view/>
|
<router-view/>
|
||||||
|
@ -47,16 +42,6 @@
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: {
|
components: {
|
||||||
Error
|
Error
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
newFile: function() {
|
|
||||||
this.$store.dispatch('newFile')
|
|
||||||
.catch(() => {})
|
|
||||||
.then(file => {
|
|
||||||
this.$store.dispatch('updateSearch')
|
|
||||||
this.$router.push({ name: 'console-slug', params: { slug: file.Slug }})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -56,29 +56,32 @@
|
||||||
this.$store.dispatch('getFile', slug)
|
this.$store.dispatch('getFile', slug)
|
||||||
},
|
},
|
||||||
tagUpdate: function(newTags) {
|
tagUpdate: function(newTags) {
|
||||||
if (JSON.stringify(newTags) === JSON.stringify(this.$store.state.file.Tags))
|
if (JSON.stringify(newTags) === JSON.stringify(this.file.Tags))
|
||||||
return
|
return
|
||||||
this.$store.commit('setTags', newTags)
|
this.file.Tags = newTags
|
||||||
this.$emit('markDirty', true)
|
this.$emit('markDirty', true)
|
||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
updateContent: function (newContent) {
|
updateContent: function (newContent) {
|
||||||
if (this.$store.state.file.Content === newContent)
|
if (this.$store.state.file.Content === newContent)
|
||||||
return
|
return
|
||||||
this.$store.commit('setContent', newContent)
|
this.$store.state.file.Content = newContent
|
||||||
this.$emit('markDirty', true)
|
this.$emit('markDirty', true)
|
||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
save: function () {
|
save: function () {
|
||||||
this.$store.commit('setContent', this.content)
|
this.$store.state.file.Content = this.content
|
||||||
this.$store.dispatch('saveFile')
|
console.log("Saving file: " + this.file.Slug)
|
||||||
|
this.$store.dispatch('saveFile', this.file)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.$emit('markDirty', false)
|
this.$emit('markDirty', false)
|
||||||
this.$store.dispatch('updateSearch')
|
this.$store.dispatch('updateSearch')
|
||||||
if (res.data.Slug != this.$route.params.slug)
|
if (res.data.Slug != this.$route.params.slug)
|
||||||
this.$router.replace({params: { slug: res.data.Slug }})
|
this.$router.replace({params: { slug: res.data.Slug }})
|
||||||
})
|
})
|
||||||
.catch(() => { })
|
.catch(err => {
|
||||||
|
console.log('err:' + err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {TagList, Editor}
|
components: {TagList, Editor}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row>
|
<b-row>
|
||||||
<b-col cols="10">
|
<b-col cols="10">
|
||||||
<label for="tagList" :hidden="!tags">Tags</label>
|
<label for="tagList" >Tags</label>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row>
|
<b-row>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<b-container fluid>
|
<b-container fluid>
|
||||||
<b-row>
|
<b-row>
|
||||||
<b-input placeholder="Search" @update="getResults" v-model="queryText" />
|
<b-input placeholder="Search" @update="runQuery" v-model="queryText" />
|
||||||
</b-row>
|
</b-row>
|
||||||
<b-row v-for="item in results" v-bind:key="item.ID">
|
<b-row v-for="item in results" v-bind:key="item.ID">
|
||||||
<b-col>
|
<b-col>
|
||||||
<b-button :hidden="!editMode" size="sm" class="deleteLink" @click="deleteFile(item.Slug)">X</b-button> <b-link
|
<b-link
|
||||||
:to="{ name: target, params: { slug: item.Slug } }"
|
:to="{ name: target, params: { slug: item.Slug } }"
|
||||||
>{{item.Title}}</b-link>
|
>{{item.Slug}}</b-link>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
</b-container>
|
</b-container>
|
||||||
|
@ -24,39 +24,30 @@
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
target: String,
|
target: String,
|
||||||
query: String,
|
query: String
|
||||||
editMode: Boolean
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
query: function(newValue) {
|
query: function(newValue) {
|
||||||
this.queryText = newValue
|
this.queryText = newValue
|
||||||
},
|
|
||||||
queryText: function(newValue) {
|
|
||||||
this.$store.commit('setQuery', newValue)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
results: function() {
|
results: function() {
|
||||||
|
console.log("results:"+this.$store.state.searchResults)
|
||||||
return this.$store.state.searchResults
|
return this.$store.state.searchResults
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getResults()
|
this.getResults()
|
||||||
this.getResults = _.debounce(this.getResults, 1000)
|
this.runQuery = _.debounce(this.runQuery, 1000)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getResults: function () {
|
getResults: function () {
|
||||||
this.$store.dispatch('updateSearch')
|
this.$store.dispatch('getSearchResults', null)
|
||||||
},
|
},
|
||||||
deleteFile: function(slug) {
|
runQuery: function() {
|
||||||
this.$store.dispatch('deleteBySlug', slug)
|
this.$store.dispatch('getSearchResults', this.query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.deleteLink {
|
|
||||||
font-size: x-small;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
tags: function (newValue) {
|
tags: function (newValue) {
|
||||||
this.internalTags = newValue || []
|
this.internalTags = newValue
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -40,28 +40,9 @@ export default new Vuex.Store({
|
||||||
},
|
},
|
||||||
setFile(state, file) {
|
setFile(state, file) {
|
||||||
state.file = file
|
state.file = file
|
||||||
},
|
|
||||||
setContent(state, content) {
|
|
||||||
state.file.Content = content
|
|
||||||
},
|
|
||||||
setTags(state, tags) {
|
|
||||||
state.file.Tags = tags
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
newFile: function({commit}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
axios.post('/v1/entries', {})
|
|
||||||
.catch(err => {
|
|
||||||
commit('addError', err)
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
commit('setFile', res.data)
|
|
||||||
resolve(res.data)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getFile: function({ commit }, slug) {
|
getFile: function({ commit }, slug) {
|
||||||
if (slug)
|
if (slug)
|
||||||
return axios.get('/v1/entries/'+slug)
|
return axios.get('/v1/entries/'+slug)
|
||||||
|
@ -70,32 +51,29 @@ export default new Vuex.Store({
|
||||||
commit('setFile', res.data)
|
commit('setFile', res.data)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
getSearchResults: function ({dispatch, commit}, query) {
|
||||||
|
commit('setQuery', query)
|
||||||
|
dispatch('updateSearch')
|
||||||
|
},
|
||||||
updateSearch: function ({commit, state}) {
|
updateSearch: function ({commit, state}) {
|
||||||
return new Promise((resolve, reject) => {
|
let query = state.query
|
||||||
let query = state.query || ""
|
if (query) {
|
||||||
axios.get('/v1/entries?query='+query)
|
axios.get('/v1/entries?query='+query)
|
||||||
.catch(err => {
|
.catch(err => state.addError(err))
|
||||||
state.addError(err)
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
.then(res =>{
|
.then(res =>{
|
||||||
|
console.log("getSearchResults:"+res.data)
|
||||||
commit('setResults', res.data)
|
commit('setResults', res.data)
|
||||||
resolve(res.data)
|
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
},
|
axios.get('/v1/entries')
|
||||||
saveFile: function({state}) {
|
.catch(err => state.addError(err))
|
||||||
if (state.file)
|
.then(res =>{
|
||||||
return axios.put('/v1/entries/'+state.file.Slug, state.file)
|
console.log("getSearchResults:"+res.data)
|
||||||
},
|
commit('setResults', res.data)
|
||||||
deleteBySlug: function({dispatch,commit}, slug) {
|
|
||||||
axios.delete('/v1/entries/'+slug)
|
|
||||||
.catch(err => {
|
|
||||||
commit('addError', err)
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
dispatch('updateSearch')
|
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
saveFile: function(state, file) {
|
||||||
|
return axios.put('/v1/entries/'+file.Slug, file)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<b-col md="5">
|
<b-col md="5">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<b-tabs content-class="mt-3" v-model="tabIndex">
|
<b-tabs content-class="mt-3">
|
||||||
<b-tab active>
|
<b-tab active>
|
||||||
<template v-slot:title>
|
<template v-slot:title>
|
||||||
Editor <span v-bind:class="{ dirty: isDirty, clean: !isDirty }">•</span>
|
Editor <span v-bind:class="{ dirty: isDirty, clean: !isDirty }">•</span>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col md="2">
|
<b-col md="2">
|
||||||
<h2>Search Results</h2>
|
<h2>Search Results</h2>
|
||||||
<SearchResults :editMode="true" target="console-slug" />
|
<SearchResults target="console-slug" :query="query"/>
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
</b-container>
|
</b-container>
|
||||||
|
@ -49,11 +49,15 @@ export default {
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
isDirty: false,
|
isDirty: false,
|
||||||
tabIndex: 0
|
query: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
provide: {
|
||||||
|
update: function() {}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
markDirty: function(dirty) {
|
markDirty: function(dirty) {
|
||||||
|
console.log('markDirty:'+dirty)
|
||||||
this.isDirty = dirty
|
this.isDirty = dirty
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -61,6 +65,7 @@ export default {
|
||||||
// called before the route that renders this component is confirmed.
|
// called before the route that renders this component is confirmed.
|
||||||
// does NOT have access to `this` component instance,
|
// does NOT have access to `this` component instance,
|
||||||
// because it has not been created yet when this guard is called!
|
// because it has not been created yet when this guard is called!
|
||||||
|
console.log('beforeRouteEnter'+to+from)
|
||||||
next()
|
next()
|
||||||
},
|
},
|
||||||
beforeRouteUpdate (to, from, next) {
|
beforeRouteUpdate (to, from, next) {
|
||||||
|
@ -78,13 +83,13 @@ export default {
|
||||||
next(false)
|
next(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.tabIndex = 0
|
|
||||||
next()
|
next()
|
||||||
},
|
},
|
||||||
beforeRouteLeave (to, from, next) {
|
beforeRouteLeave (to, from, next) {
|
||||||
// called when the route that renders this component is about to
|
// called when the route that renders this component is about to
|
||||||
// be navigated away from.
|
// be navigated away from.
|
||||||
// has access to `this` component instance.
|
// has access to `this` component instance.
|
||||||
|
console.log('beforeRouteLeave'+to+from)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
todo.adoc
33
todo.adoc
|
@ -1,20 +1,27 @@
|
||||||
= Todo
|
= Todo
|
||||||
:icons: font
|
:icons: font
|
||||||
|
|
||||||
* Backend
|
* Operations
|
||||||
** Authentication
|
|
||||||
*** [ ] some kind of user auth
|
|
||||||
** save endpoint
|
|
||||||
*** [ ] add authentication/authorization
|
|
||||||
*** [ ] convert document to adoc (give format?)
|
|
||||||
*** [ ] check for unique tags
|
|
||||||
** [ ] search endpoint
|
|
||||||
*** [ ] search for tags
|
|
||||||
*** [ ] fulltext search
|
|
||||||
**** with link:https://blevesearch.com/docs/Getting%20Started/[Bleve]
|
|
||||||
* [ ] CLI Frontend
|
|
||||||
* [ ] Operations
|
|
||||||
** [ ] dockerize the build
|
** [ ] dockerize the build
|
||||||
** [ ] integrate CI/CD
|
** [ ] integrate CI/CD
|
||||||
** [ ] run on https://cabinet.chrissexton.org[cabinet.chrissexton.org]
|
** [ ] run on https://cabinet.chrissexton.org[cabinet.chrissexton.org]
|
||||||
** [ ] create redirect or https://cab.chrissexton.org[cab.chrissexton.org]
|
** [ ] create redirect or https://cab.chrissexton.org[cab.chrissexton.org]
|
||||||
|
* Vue Frontend
|
||||||
|
** [ ] spend some time learning about TypeScript/Vue.js style
|
||||||
|
** Documents
|
||||||
|
*** [x] adoc editor widget
|
||||||
|
** Authentication
|
||||||
|
*** [ ] some kind of user auth
|
||||||
|
** Views
|
||||||
|
*** [ ] editor view
|
||||||
|
*** [ ] public index/search view
|
||||||
|
* Backend
|
||||||
|
** [?] save endpoint
|
||||||
|
*** [ ] need to generate a slug for entries
|
||||||
|
*** [ ] add authentication/authorization
|
||||||
|
*** [ ] convert document to adoc (give format?)
|
||||||
|
*** [x] test in frontend
|
||||||
|
*** [ ] check for unique tags
|
||||||
|
*** [ ] set some db fields not null
|
||||||
|
** [ ] search endpoint
|
||||||
|
* CLI Frontend
|
||||||
|
|
|
@ -81,11 +81,8 @@ func (web *Web) newEntry(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (web *Web) allEntries(w http.ResponseWriter, r *http.Request) {
|
func (web *Web) allEntries(w http.ResponseWriter, r *http.Request) {
|
||||||
query := ""
|
r.ParseForm()
|
||||||
items, ok := r.URL.Query()["query"]
|
query := r.Form.Get("query")
|
||||||
if ok {
|
|
||||||
query = items[0]
|
|
||||||
}
|
|
||||||
entries, err := entry.Search(web.db, query)
|
entries, err := entry.Search(web.db, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
|
@ -130,7 +127,6 @@ func (web *Web) removeEntry(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
err := entry.RemoveBySlug(web.db, slug)
|
err := entry.RemoveBySlug(web.db, slug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("Error deleting: %s", err)
|
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
fmt.Fprint(w, err)
|
fmt.Fprint(w, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -11,25 +11,25 @@ import (
|
||||||
|
|
||||||
"github.com/speps/go-hashids"
|
"github.com/speps/go-hashids"
|
||||||
|
|
||||||
"github.com/gorilla/handlers"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/gorilla/handlers"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/stretchr/graceful"
|
"github.com/stretchr/graceful"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Web struct {
|
type Web struct {
|
||||||
addr string
|
addr string
|
||||||
db *db.Database
|
db *db.Database
|
||||||
salt string
|
salt string
|
||||||
h *hashids.HashID
|
h *hashids.HashID
|
||||||
box *packr.Box
|
box *packr.Box
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(addr string, db *db.Database, box *packr.Box) *Web {
|
func New(addr string, db *db.Database, box *packr.Box) *Web {
|
||||||
w := &Web{
|
w := &Web{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
db: db,
|
db: db,
|
||||||
box: box,
|
box: box,
|
||||||
}
|
}
|
||||||
if err := db.MakeDB(); err != nil {
|
if err := db.MakeDB(); err != nil {
|
||||||
log.Fatal().
|
log.Fatal().
|
||||||
|
@ -44,7 +44,7 @@ func (web *Web) routeSetup() http.Handler {
|
||||||
api := r.PathPrefix("/v1/").Subrouter()
|
api := r.PathPrefix("/v1/").Subrouter()
|
||||||
api.HandleFunc("/entries", web.allEntries).Methods(http.MethodGet)
|
api.HandleFunc("/entries", web.allEntries).Methods(http.MethodGet)
|
||||||
api.HandleFunc("/entries", web.newEntry).Methods(http.MethodPost)
|
api.HandleFunc("/entries", web.newEntry).Methods(http.MethodPost)
|
||||||
api.HandleFunc("/entries/{slug}", web.removeEntry).Methods(http.MethodDelete)
|
api.HandleFunc("/entries", web.removeEntry).Methods(http.MethodDelete)
|
||||||
api.HandleFunc("/entries/{slug}", web.editEntry).Methods(http.MethodPut)
|
api.HandleFunc("/entries/{slug}", web.editEntry).Methods(http.MethodPut)
|
||||||
api.HandleFunc("/entries/{slug}", web.getEntry).Methods(http.MethodGet)
|
api.HandleFunc("/entries/{slug}", web.getEntry).Methods(http.MethodGet)
|
||||||
r.PathPrefix("/").HandlerFunc(web.indexHandler("/index.html"))
|
r.PathPrefix("/").HandlerFunc(web.indexHandler("/index.html"))
|
||||||
|
|
Loading…
Reference in New Issue