2020-09-18 10:34:52 +00:00
package main
import (
2020-10-06 17:07:48 +00:00
"bytes"
2020-11-09 15:40:12 +00:00
"database/sql"
2020-09-18 10:34:52 +00:00
"errors"
2020-10-06 17:07:48 +00:00
"fmt"
2021-07-23 15:26:14 +00:00
"strconv"
2020-09-18 10:34:52 +00:00
"strings"
2020-10-06 17:07:48 +00:00
"text/template"
2020-09-18 10:34:52 +00:00
"time"
2020-10-06 17:07:48 +00:00
"github.com/araddon/dateparse"
2021-06-15 15:36:41 +00:00
"github.com/thoas/go-funk"
2020-09-18 10:34:52 +00:00
)
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) checkPost ( p * post ) ( err error ) {
2020-09-18 10:34:52 +00:00
if p == nil {
return errors . New ( "no post" )
}
2020-10-06 17:07:48 +00:00
now := time . Now ( )
2020-09-18 10:34:52 +00:00
// Fix content
p . Content = strings . TrimSuffix ( strings . TrimPrefix ( p . Content , "\n" ) , "\n" )
// Fix date strings
if p . Published != "" {
2020-12-16 20:24:53 +00:00
p . Published , err = toLocal ( p . Published )
2020-09-18 10:34:52 +00:00
if err != nil {
return err
}
}
if p . Updated != "" {
2020-12-16 20:24:53 +00:00
p . Updated , err = toLocal ( p . Updated )
2020-09-18 10:34:52 +00:00
if err != nil {
return err
}
}
2021-01-15 20:56:46 +00:00
// Check status
if p . Status == "" {
p . Status = statusPublished
}
2020-10-14 16:31:05 +00:00
// Cleanup params
for key , value := range p . Parameters {
if value == nil {
delete ( p . Parameters , key )
continue
}
allValues := [ ] string { }
for _ , v := range value {
if v != "" {
allValues = append ( allValues , v )
}
}
if len ( allValues ) >= 1 {
p . Parameters [ key ] = allValues
} else {
delete ( p . Parameters , key )
}
}
2020-10-06 17:07:48 +00:00
// Check blog
if p . Blog == "" {
2021-06-06 12:39:42 +00:00
p . Blog = a . cfg . DefaultBlog
2020-10-06 17:07:48 +00:00
}
2021-06-06 12:39:42 +00:00
if _ , ok := a . cfg . Blogs [ p . Blog ] ; ! ok {
2020-12-12 22:44:03 +00:00
return errors . New ( "blog doesn't exist" )
}
// Check if section exists
2021-06-06 12:39:42 +00:00
if _ , ok := a . cfg . Blogs [ p . Blog ] . Sections [ p . Section ] ; p . Section != "" && ! ok {
2020-12-12 22:44:03 +00:00
return errors . New ( "section doesn't exist" )
}
2020-10-06 17:07:48 +00:00
// Check path
2020-12-23 15:53:10 +00:00
if p . Path != "/" {
p . Path = strings . TrimSuffix ( p . Path , "/" )
}
2020-10-06 17:07:48 +00:00
if p . Path == "" {
if p . Section == "" {
2021-06-06 12:39:42 +00:00
p . Section = a . cfg . Blogs [ p . Blog ] . DefaultSection
2020-10-06 17:07:48 +00:00
}
if p . Slug == "" {
2020-10-26 16:37:31 +00:00
random := generateRandomString ( 5 )
2020-10-06 17:07:48 +00:00
p . Slug = fmt . Sprintf ( "%v-%02d-%02d-%v" , now . Year ( ) , int ( now . Month ( ) ) , now . Day ( ) , random )
}
2021-07-27 10:51:08 +00:00
published := timeNoErr ( dateparse . ParseLocal ( p . Published ) )
2021-07-30 13:43:13 +00:00
pathTmplString := defaultIfEmpty (
a . cfg . Blogs [ p . Blog ] . Sections [ p . Section ] . PathTemplate ,
"{{printf \"" + a . getRelativePath ( p . Blog , "/%v/%02d/%02d/%v" ) + "\" .Section .Year .Month .Slug}}" ,
)
2020-10-06 17:07:48 +00:00
pathTmpl , err := template . New ( "location" ) . Parse ( pathTmplString )
if err != nil {
return errors . New ( "failed to parse location template" )
}
var pathBuffer bytes . Buffer
2020-11-01 17:37:21 +00:00
err = pathTmpl . Execute ( & pathBuffer , map [ string ] interface { } {
2021-06-11 06:24:41 +00:00
"BlogPath" : a . getRelativePath ( p . Blog , "" ) ,
2020-11-01 17:37:21 +00:00
"Year" : published . Year ( ) ,
"Month" : int ( published . Month ( ) ) ,
"Day" : published . Day ( ) ,
"Slug" : p . Slug ,
"Section" : p . Section ,
} )
2020-10-06 17:07:48 +00:00
if err != nil {
return errors . New ( "failed to execute location template" )
}
p . Path = pathBuffer . String ( )
}
if p . Path != "" && ! strings . HasPrefix ( p . Path , "/" ) {
return errors . New ( "wrong path" )
}
2020-09-18 10:34:52 +00:00
return nil
}
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) createPost ( p * post ) error {
return a . createOrReplacePost ( p , & postCreationOptions { new : true } )
2021-01-15 20:56:46 +00:00
}
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) replacePost ( p * post , oldPath string , oldStatus postStatus ) error {
return a . createOrReplacePost ( p , & postCreationOptions { new : false , oldPath : oldPath , oldStatus : oldStatus } )
2020-10-14 16:23:56 +00:00
}
2021-01-15 20:56:46 +00:00
type postCreationOptions struct {
new bool
oldPath string
oldStatus postStatus
2020-10-14 16:23:56 +00:00
}
2021-06-06 12:39:42 +00:00
func ( a * goBlog ) createOrReplacePost ( p * post , o * postCreationOptions ) error {
2021-06-15 15:36:41 +00:00
// Check post
if err := a . checkPost ( p ) ; err != nil {
return err
}
// Save to db
if err := a . db . savePost ( p , o ) ; err != nil {
2020-09-18 10:34:52 +00:00
return err
}
2021-08-07 12:39:23 +00:00
// Reload post from database
p , err := a . getPost ( p . Path )
if err != nil {
// Failed to reload post from database
return err
}
2021-06-15 15:36:41 +00:00
// Trigger hooks
2021-07-14 14:15:24 +00:00
if p . Status == statusPublished || p . Status == statusUnlisted {
if o . new || ( o . oldStatus != statusPublished && o . oldStatus != statusUnlisted ) {
2021-06-15 15:36:41 +00:00
defer a . postPostHooks ( p )
} else {
defer a . postUpdateHooks ( p )
}
}
2021-07-17 07:33:44 +00:00
// Purge cache
a . cache . purge ( )
return nil
2021-06-15 15:36:41 +00:00
}
// Save check post to database
func ( db * database ) savePost ( p * post , o * postCreationOptions ) error {
2021-07-01 16:51:04 +00:00
// Check
if ! o . new && o . oldPath == "" {
return errors . New ( "old path required" )
}
// Lock post creation
2021-06-18 12:32:03 +00:00
db . pcm . Lock ( )
defer db . pcm . Unlock ( )
2021-05-29 11:32:00 +00:00
// Build SQL
var sqlBuilder strings . Builder
2021-07-01 16:51:04 +00:00
var sqlArgs = [ ] interface { } { dbNoCache }
// Start transaction
sqlBuilder . WriteString ( "begin;" )
2021-05-29 11:32:00 +00:00
// Delete old post
if ! o . new {
2021-07-03 10:11:57 +00:00
sqlBuilder . WriteString ( "delete from posts where path = ?;delete from post_parameters where path = ?;" )
sqlArgs = append ( sqlArgs , o . oldPath , o . oldPath )
2020-09-18 10:34:52 +00:00
}
2021-05-29 11:32:00 +00:00
// Insert new post
2021-07-12 14:19:28 +00:00
sqlBuilder . WriteString ( "insert into posts (path, content, published, updated, blog, section, status, priority) values (?, ?, ?, ?, ?, ?, ?, ?);" )
2021-07-14 13:44:57 +00:00
sqlArgs = append ( sqlArgs , p . Path , p . Content , toUTCSafe ( p . Published ) , toUTCSafe ( p . Updated ) , p . Blog , p . Section , p . Status , p . Priority )
2021-05-29 11:32:00 +00:00
// Insert post parameters
2020-09-18 10:34:52 +00:00
for param , value := range p . Parameters {
for _ , value := range value {
if value != "" {
2021-05-29 11:32:00 +00:00
sqlBuilder . WriteString ( "insert into post_parameters (path, parameter, value) values (?, ?, ?);" )
sqlArgs = append ( sqlArgs , p . Path , param , value )
2020-09-18 10:34:52 +00:00
}
}
}
2021-07-01 16:51:04 +00:00
// Commit transaction
sqlBuilder . WriteString ( "commit;" )
2021-05-29 11:32:00 +00:00
// Execute
2021-07-01 16:51:04 +00:00
if _ , err := db . exec ( sqlBuilder . String ( ) , sqlArgs ... ) ; err != nil {
if strings . Contains ( err . Error ( ) , "UNIQUE constraint failed: posts.path" ) {
return errors . New ( "post already exists at given path" )
}
2020-09-18 10:34:52 +00:00
return err
}
2021-06-15 15:36:41 +00:00
// Update FTS index
db . rebuildFTSIndex ( )
return nil
}
func ( a * goBlog ) deletePost ( path string ) error {
2021-08-05 06:09:34 +00:00
p , err := a . deletePostFromDb ( path )
2021-06-15 15:36:41 +00:00
if err != nil || p == nil {
return err
2020-11-09 15:40:12 +00:00
}
2021-07-17 07:33:44 +00:00
// Purge cache
a . cache . purge ( )
// Trigger hooks
a . postDeleteHooks ( p )
return nil
2020-09-18 10:34:52 +00:00
}
2021-08-05 06:09:34 +00:00
func ( a * goBlog ) deletePostFromDb ( path string ) ( * post , error ) {
2020-10-14 16:23:56 +00:00
if path == "" {
2021-06-15 15:36:41 +00:00
return nil , nil
2020-09-18 10:34:52 +00:00
}
2021-08-05 06:09:34 +00:00
a . db . pcm . Lock ( )
defer a . db . pcm . Unlock ( )
p , err := a . getPost ( path )
2020-11-08 22:04:32 +00:00
if err != nil {
2021-06-15 15:36:41 +00:00
return nil , err
2020-11-08 22:04:32 +00:00
}
2021-08-05 06:09:34 +00:00
_ , err = a . db . exec (
2021-07-23 07:53:35 +00:00
` begin ;
delete from posts where path = ? ;
delete from post_parameters where path = ? ;
insert or ignore into deleted ( path ) values ( ? ) ;
commit ; ` ,
dbNoCache , p . Path , p . Path , p . Path ,
)
2020-11-15 10:34:48 +00:00
if err != nil {
2021-06-15 15:36:41 +00:00
return nil , err
2020-11-15 10:34:48 +00:00
}
2021-08-05 06:09:34 +00:00
a . db . rebuildFTSIndex ( )
2021-06-15 15:36:41 +00:00
return p , nil
2021-01-20 12:38:24 +00:00
}
2021-09-07 20:16:28 +00:00
func ( db * database ) replacePostParam ( path , param string , values [ ] string ) error {
// Lock post creation
db . pcm . Lock ( )
defer db . pcm . Unlock ( )
// Build SQL
var sqlBuilder strings . Builder
var sqlArgs = [ ] interface { } { dbNoCache }
// Start transaction
sqlBuilder . WriteString ( "begin;" )
// Delete old post
sqlBuilder . WriteString ( "delete from post_parameters where path = ? and parameter = ?;" )
sqlArgs = append ( sqlArgs , path , param )
// Insert new post parameters
for _ , value := range values {
if value != "" {
sqlBuilder . WriteString ( "insert into post_parameters (path, parameter, value) values (?, ?, ?);" )
sqlArgs = append ( sqlArgs , path , param , value )
}
}
// Commit transaction
sqlBuilder . WriteString ( "commit;" )
// Execute
if _ , err := db . exec ( sqlBuilder . String ( ) , sqlArgs ... ) ; err != nil {
return err
}
// Update FTS index
db . rebuildFTSIndex ( )
return nil
}
2020-11-09 15:40:12 +00:00
type postsRequestConfig struct {
2020-12-26 19:40:22 +00:00
search string
blog string
path string
limit int
offset int
sections [ ] string
2021-01-15 20:56:46 +00:00
status postStatus
2021-07-12 14:19:28 +00:00
taxonomy * configTaxonomy
2020-12-26 19:40:22 +00:00
taxonomyValue string
parameter string
parameterValue string
publishedYear , publishedMonth , publishedDay int
2021-01-20 12:38:24 +00:00
randomOrder bool
2021-07-12 14:19:28 +00:00
priorityOrder bool
2021-07-03 10:11:57 +00:00
withoutParameters bool
2021-07-06 19:06:39 +00:00
withOnlyParameters [ ] string
2021-08-10 11:27:19 +00:00
withoutRenderedTitle bool
2020-11-09 15:40:12 +00:00
}
2021-07-03 10:11:57 +00:00
func buildPostsQuery ( c * postsRequestConfig , selection string ) ( query string , args [ ] interface { } ) {
2021-07-23 15:26:14 +00:00
var queryBuilder strings . Builder
// Selection
queryBuilder . WriteString ( "select " )
queryBuilder . WriteString ( selection )
queryBuilder . WriteString ( " from " )
// Table
2021-06-06 12:39:42 +00:00
if c . search != "" {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( "posts_fts(@search)" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "search" , c . search ) )
2021-07-23 15:26:14 +00:00
} else {
queryBuilder . WriteString ( "posts" )
2020-11-15 10:34:48 +00:00
}
2021-07-23 15:26:14 +00:00
// Filter
queryBuilder . WriteString ( " where 1" )
2021-07-03 10:11:57 +00:00
if c . path != "" {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and path = @path" )
2021-07-03 10:11:57 +00:00
args = append ( args , sql . Named ( "path" , c . path ) )
}
2021-06-06 12:39:42 +00:00
if c . status != "" && c . status != statusNil {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and status = @status" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "status" , c . status ) )
2021-01-15 20:56:46 +00:00
}
2021-06-06 12:39:42 +00:00
if c . blog != "" {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and blog = @blog" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "blog" , c . blog ) )
2020-11-09 15:40:12 +00:00
}
2021-06-06 12:39:42 +00:00
if c . parameter != "" {
if c . parameterValue != "" {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and path in (select path from post_parameters where parameter = @param and value = @paramval)" )
2021-07-03 10:11:57 +00:00
args = append ( args , sql . Named ( "param" , c . parameter ) , sql . Named ( "paramval" , c . parameterValue ) )
2020-11-09 15:40:12 +00:00
} else {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and path in (select path from post_parameters where parameter = @param and length(coalesce(value, '')) > 0)" )
2021-07-03 10:11:57 +00:00
args = append ( args , sql . Named ( "param" , c . parameter ) )
2020-11-09 15:40:12 +00:00
}
}
2021-06-06 12:39:42 +00:00
if c . taxonomy != nil && len ( c . taxonomyValue ) > 0 {
2021-08-09 11:09:45 +00:00
queryBuilder . WriteString ( " and path in (select path from post_parameters where parameter = @taxname and lowerx(value) = lowerx(@taxval))" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "taxname" , c . taxonomy . Name ) , sql . Named ( "taxval" , c . taxonomyValue ) )
2020-11-09 15:40:12 +00:00
}
2021-06-06 12:39:42 +00:00
if len ( c . sections ) > 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and section in (" )
2021-06-06 12:39:42 +00:00
for i , section := range c . sections {
2020-11-09 15:40:12 +00:00
if i > 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( ", " )
2020-11-09 15:40:12 +00:00
}
2021-07-23 15:26:14 +00:00
named := "section" + strconv . Itoa ( i )
queryBuilder . WriteByte ( '@' )
queryBuilder . WriteString ( named )
2020-11-09 15:40:12 +00:00
args = append ( args , sql . Named ( named , section ) )
}
2021-07-23 15:26:14 +00:00
queryBuilder . WriteByte ( ')' )
2020-11-09 15:40:12 +00:00
}
2021-06-06 12:39:42 +00:00
if c . publishedYear != 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and substr(tolocal(published), 1, 4) = @publishedyear" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "publishedyear" , fmt . Sprintf ( "%0004d" , c . publishedYear ) ) )
2020-12-13 14:16:47 +00:00
}
2021-06-06 12:39:42 +00:00
if c . publishedMonth != 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and substr(tolocal(published), 6, 2) = @publishedmonth" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "publishedmonth" , fmt . Sprintf ( "%02d" , c . publishedMonth ) ) )
2020-12-13 14:16:47 +00:00
}
2021-06-06 12:39:42 +00:00
if c . publishedDay != 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and substr(tolocal(published), 9, 2) = @publishedday" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "publishedday" , fmt . Sprintf ( "%02d" , c . publishedDay ) ) )
2020-12-26 19:40:22 +00:00
}
2021-07-23 15:26:14 +00:00
// Order
queryBuilder . WriteString ( " order by " )
2021-06-06 12:39:42 +00:00
if c . randomOrder {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( "random()" )
2021-07-12 14:19:28 +00:00
} else if c . priorityOrder {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( "priority desc, published desc" )
} else {
queryBuilder . WriteString ( "published desc" )
2021-01-20 12:38:24 +00:00
}
2021-07-23 15:26:14 +00:00
// Limit & Offset
2021-07-03 10:11:57 +00:00
if c . limit != 0 || c . offset != 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " limit @limit offset @offset" )
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "limit" , c . limit ) , sql . Named ( "offset" , c . offset ) )
2020-11-09 15:40:12 +00:00
}
2021-07-23 15:26:14 +00:00
return queryBuilder . String ( ) , args
2021-07-03 10:11:57 +00:00
}
2021-07-19 14:32:45 +00:00
func ( d * database ) loadPostParameters ( posts [ ] * post , parameters ... string ) ( err error ) {
2021-07-23 15:26:14 +00:00
if len ( posts ) == 0 {
return nil
}
// Build query
2021-07-06 19:06:39 +00:00
var sqlArgs [ ] interface { }
2021-07-23 15:26:14 +00:00
var queryBuilder strings . Builder
queryBuilder . WriteString ( "select path, parameter, value from post_parameters where" )
// Paths
queryBuilder . WriteString ( " path in (" )
for i , p := range posts {
if i > 0 {
queryBuilder . WriteString ( ", " )
}
named := "path" + strconv . Itoa ( i )
queryBuilder . WriteByte ( '@' )
queryBuilder . WriteString ( named )
sqlArgs = append ( sqlArgs , sql . Named ( named , p . Path ) )
}
queryBuilder . WriteByte ( ')' )
// Parameters
2021-07-06 19:06:39 +00:00
if len ( parameters ) > 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( " and parameter in (" )
2021-07-06 19:06:39 +00:00
for i , p := range parameters {
if i > 0 {
2021-07-23 15:26:14 +00:00
queryBuilder . WriteString ( ", " )
2021-07-06 19:06:39 +00:00
}
2021-07-23 15:26:14 +00:00
named := "param" + strconv . Itoa ( i )
queryBuilder . WriteByte ( '@' )
queryBuilder . WriteString ( named )
2021-07-06 19:06:39 +00:00
sqlArgs = append ( sqlArgs , sql . Named ( named , p ) )
}
2021-07-23 15:26:14 +00:00
queryBuilder . WriteByte ( ')' )
2021-07-19 14:32:45 +00:00
}
2021-07-23 15:26:14 +00:00
// Order
queryBuilder . WriteString ( " order by id" )
2021-07-06 19:06:39 +00:00
// Query
2021-07-23 15:26:14 +00:00
rows , err := d . query ( queryBuilder . String ( ) , sqlArgs ... )
2021-07-03 10:11:57 +00:00
if err != nil {
2021-07-19 14:32:45 +00:00
return err
2021-07-03 10:11:57 +00:00
}
2021-07-06 19:06:39 +00:00
// Result
2021-07-19 14:32:45 +00:00
var path , name , value string
params := map [ string ] map [ string ] [ ] string { }
2021-07-03 10:11:57 +00:00
for rows . Next ( ) {
2021-07-19 14:32:45 +00:00
if err = rows . Scan ( & path , & name , & value ) ; err != nil {
return err
}
m , ok := params [ path ]
if ! ok {
m = map [ string ] [ ] string { }
2021-07-03 10:11:57 +00:00
}
2021-07-19 14:32:45 +00:00
m [ name ] = append ( m [ name ] , value )
params [ path ] = m
2021-07-03 10:11:57 +00:00
}
2021-07-19 14:32:45 +00:00
// Add to posts
for _ , p := range posts {
p . Parameters = params [ p . Path ]
}
return nil
2020-11-09 15:40:12 +00:00
}
2021-08-05 06:09:34 +00:00
func ( a * goBlog ) getPosts ( config * postsRequestConfig ) ( posts [ ] * post , err error ) {
2021-07-02 14:52:09 +00:00
// Query posts
2021-07-12 14:19:28 +00:00
query , queryParams := buildPostsQuery ( config , "path, coalesce(content, ''), coalesce(published, ''), coalesce(updated, ''), blog, coalesce(section, ''), status, priority" )
2021-08-05 06:09:34 +00:00
rows , err := a . db . query ( query , queryParams ... )
2020-09-18 10:34:52 +00:00
if err != nil {
2020-11-09 15:40:12 +00:00
return nil , err
2020-09-18 10:34:52 +00:00
}
2021-07-03 10:11:57 +00:00
// Prepare row scanning
var path , content , published , updated , blog , section , status string
2021-07-12 14:19:28 +00:00
var priority int
2020-11-09 15:40:12 +00:00
for rows . Next ( ) {
2021-07-12 14:19:28 +00:00
if err = rows . Scan ( & path , & content , & published , & updated , & blog , & section , & status , & priority ) ; err != nil {
2020-11-09 15:40:12 +00:00
return nil , err
}
2021-07-03 10:11:57 +00:00
// Create new post, fill and add to list
p := & post {
Path : path ,
Content : content ,
Published : toLocalSafe ( published ) ,
Updated : toLocalSafe ( updated ) ,
Blog : blog ,
Section : section ,
Status : postStatus ( status ) ,
2021-07-12 14:19:28 +00:00
Priority : priority ,
2021-07-03 10:11:57 +00:00
}
posts = append ( posts , p )
2021-07-02 14:52:09 +00:00
}
2021-07-19 14:32:45 +00:00
if ! config . withoutParameters {
2021-08-05 06:09:34 +00:00
err = a . db . loadPostParameters ( posts , config . withOnlyParameters ... )
2021-07-19 14:32:45 +00:00
if err != nil {
return nil , err
}
}
2021-08-05 06:09:34 +00:00
// Render post title
2021-08-10 11:27:19 +00:00
if ! config . withoutRenderedTitle {
for _ , p := range posts {
if t := p . Title ( ) ; t != "" {
p . RenderedTitle = a . renderMdTitle ( t )
}
2021-08-05 06:09:34 +00:00
}
}
2020-11-09 15:40:12 +00:00
return posts , nil
}
2021-08-05 06:09:34 +00:00
func ( a * goBlog ) getPost ( path string ) ( * post , error ) {
posts , err := a . getPosts ( & postsRequestConfig { path : path , limit : 1 } )
2021-06-06 12:39:42 +00:00
if err != nil {
return nil , err
} else if len ( posts ) == 0 {
return nil , errPostNotFound
}
return posts [ 0 ] , nil
}
func ( d * database ) countPosts ( config * postsRequestConfig ) ( count int , err error ) {
2021-07-03 10:11:57 +00:00
query , params := buildPostsQuery ( config , "path" )
row , err := d . queryRow ( "select count(distinct path) from (" + query + ")" , params ... )
2020-09-18 10:34:52 +00:00
if err != nil {
2020-11-09 15:40:12 +00:00
return
2020-09-18 10:34:52 +00:00
}
2020-11-09 15:40:12 +00:00
err = row . Scan ( & count )
return
}
2021-07-14 13:44:57 +00:00
func ( d * database ) getPostPaths ( status postStatus ) ( [ ] string , error ) {
2020-11-09 15:40:12 +00:00
var postPaths [ ] string
2021-06-06 12:39:42 +00:00
rows , err := d . query ( "select path from posts where status = @status" , sql . Named ( "status" , status ) )
2020-11-09 15:40:12 +00:00
if err != nil {
return nil , err
}
2021-07-02 14:52:09 +00:00
var path string
2020-11-09 15:40:12 +00:00
for rows . Next ( ) {
_ = rows . Scan ( & path )
2021-02-16 15:26:21 +00:00
if path != "" {
postPaths = append ( postPaths , path )
}
2020-11-09 15:40:12 +00:00
}
return postPaths , nil
}
2021-07-03 10:11:57 +00:00
func ( a * goBlog ) getRandomPostPath ( blog string ) ( path string , err error ) {
2021-06-15 15:36:41 +00:00
sections , ok := funk . Keys ( a . cfg . Blogs [ blog ] . Sections ) . ( [ ] string )
if ! ok {
return "" , errors . New ( "no sections" )
2021-06-06 12:39:42 +00:00
}
2021-07-03 10:11:57 +00:00
query , params := buildPostsQuery ( & postsRequestConfig { randomOrder : true , limit : 1 , blog : blog , sections : sections } , "path" )
row , err := a . db . queryRow ( query , params ... )
2021-06-06 12:39:42 +00:00
if err != nil {
2021-07-03 10:11:57 +00:00
return
}
err = row . Scan ( & path )
if errors . Is ( err , sql . ErrNoRows ) {
2021-06-06 12:39:42 +00:00
return "" , errPostNotFound
2021-07-03 10:11:57 +00:00
} else if err != nil {
return "" , err
2021-06-06 12:39:42 +00:00
}
2021-07-03 10:11:57 +00:00
return path , nil
2021-06-06 12:39:42 +00:00
}
func ( d * database ) allTaxonomyValues ( blog string , taxonomy string ) ( [ ] string , error ) {
2020-11-09 15:40:12 +00:00
var values [ ] string
2021-07-03 10:11:57 +00:00
rows , err := d . query ( "select distinct value from post_parameters where parameter = @tax and length(coalesce(value, '')) > 0 and path in (select path from posts where blog = @blog and status = @status) order by value" , sql . Named ( "tax" , taxonomy ) , sql . Named ( "blog" , blog ) , sql . Named ( "status" , statusPublished ) )
2020-11-09 15:40:12 +00:00
if err != nil {
return nil , err
}
2021-07-03 10:11:57 +00:00
var value string
2020-11-09 15:40:12 +00:00
for rows . Next ( ) {
2021-07-03 10:11:57 +00:00
if err = rows . Scan ( & value ) ; err != nil {
return nil , err
}
2020-11-09 15:40:12 +00:00
values = append ( values , value )
}
return values , nil
2020-09-18 10:34:52 +00:00
}
2020-12-13 14:16:47 +00:00
2021-07-12 17:29:32 +00:00
const mediaUseSql = `
with mediafiles ( name ) as ( values % s )
select name , count ( path ) as count from (
select distinct m . name , p . path
from mediafiles m , post_parameters p
where instr ( p . value , m . name ) > 0
union
select distinct m . name , p . path
from mediafiles m , posts_fts p
where p . content match '"' || m . name || '"'
)
group by name ;
`
func ( db * database ) usesOfMediaFile ( names ... string ) ( counts map [ string ] int , err error ) {
sqlArgs := [ ] interface { } { dbNoCache }
2021-07-23 15:26:14 +00:00
var nameValues strings . Builder
2021-07-12 17:29:32 +00:00
for i , n := range names {
if i > 0 {
2021-07-23 15:26:14 +00:00
nameValues . WriteString ( ", " )
2021-07-12 17:29:32 +00:00
}
2021-07-23 15:26:14 +00:00
named := "name" + strconv . Itoa ( i )
nameValues . WriteString ( "(@" )
nameValues . WriteString ( named )
nameValues . WriteByte ( ')' )
2021-07-12 17:29:32 +00:00
sqlArgs = append ( sqlArgs , sql . Named ( named , n ) )
2021-06-29 16:11:42 +00:00
}
2021-07-23 15:26:14 +00:00
rows , err := db . query ( fmt . Sprintf ( mediaUseSql , nameValues . String ( ) ) , sqlArgs ... )
2021-06-29 16:11:42 +00:00
if err != nil {
2021-07-12 17:29:32 +00:00
return nil , err
}
counts = map [ string ] int { }
var name string
var count int
for rows . Next ( ) {
err = rows . Scan ( & name , & count )
if err != nil {
return nil , err
}
counts [ name ] = count
2021-06-29 16:11:42 +00:00
}
2021-07-12 17:29:32 +00:00
return counts , nil
2021-06-29 16:11:42 +00:00
}