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"
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 )
}
2020-12-16 19:21:35 +00:00
published , _ := dateparse . ParseLocal ( p . Published )
2021-06-06 12:39:42 +00:00
pathTmplString := a . cfg . Blogs [ p . Blog ] . Sections [ p . Section ] . PathTemplate
2020-10-06 17:07:48 +00:00
if pathTmplString == "" {
return errors . New ( "path template empty" )
}
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-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 {
p , err := a . db . deletePost ( path )
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-06-15 15:36:41 +00:00
func ( db * database ) deletePost ( 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-07-23 07:53:35 +00:00
db . pcm . Lock ( )
defer db . pcm . Unlock ( )
2021-06-15 15:36:41 +00:00
p , err := db . 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-07-23 07:53:35 +00:00
_ , err = db . exec (
` 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-06-15 15:36:41 +00:00
db . rebuildFTSIndex ( )
return p , nil
2021-01-20 12:38:24 +00:00
}
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
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 { } ) {
2020-11-09 15:40:12 +00:00
args = [ ] interface { } { }
2021-07-02 14:52:09 +00:00
table := "posts"
2021-06-06 12:39:42 +00:00
if c . search != "" {
2021-07-02 14:52:09 +00:00
table = "posts_fts(@search)"
2021-06-06 12:39:42 +00:00
args = append ( args , sql . Named ( "search" , c . search ) )
2020-11-15 10:34:48 +00:00
}
2021-07-03 10:11:57 +00:00
var wheres [ ] string
if c . path != "" {
wheres = append ( wheres , "path = @path" )
args = append ( args , sql . Named ( "path" , c . path ) )
}
2021-06-06 12:39:42 +00:00
if c . status != "" && c . status != statusNil {
2021-07-03 10:11:57 +00:00
wheres = append ( wheres , "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-03 10:11:57 +00:00
wheres = append ( wheres , "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-03 10:11:57 +00:00
wheres = append ( wheres , "path in (select path from post_parameters where parameter = @param and value = @paramval)" )
args = append ( args , sql . Named ( "param" , c . parameter ) , sql . Named ( "paramval" , c . parameterValue ) )
2020-11-09 15:40:12 +00:00
} else {
2021-07-03 10:11:57 +00:00
wheres = append ( wheres , "path in (select path from post_parameters where parameter = @param and length(coalesce(value, '')) > 0)" )
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-07-03 10:11:57 +00:00
wheres = append ( wheres , "path in (select path from post_parameters where parameter = @taxname and lower(value) = lower(@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-03 10:11:57 +00:00
ws := "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-03 10:11:57 +00:00
ws += ", "
2020-11-09 15:40:12 +00:00
}
named := fmt . Sprintf ( "section%v" , i )
2021-07-03 10:11:57 +00:00
ws += "@" + named
2020-11-09 15:40:12 +00:00
args = append ( args , sql . Named ( named , section ) )
}
2021-07-03 10:11:57 +00:00
ws += ")"
wheres = append ( wheres , ws )
2020-11-09 15:40:12 +00:00
}
2021-06-06 12:39:42 +00:00
if c . publishedYear != 0 {
2021-07-14 13:44:57 +00:00
wheres = append ( wheres , "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-14 13:44:57 +00:00
wheres = append ( wheres , "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-14 13:44:57 +00:00
wheres = append ( wheres , "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-03 10:11:57 +00:00
if len ( wheres ) > 0 {
table += " where " + strings . Join ( wheres , " and " )
}
sorting := " order by published desc"
2021-06-06 12:39:42 +00:00
if c . randomOrder {
2021-07-03 10:11:57 +00:00
sorting = " order by random()"
2021-07-12 14:19:28 +00:00
} else if c . priorityOrder {
sorting = " order by priority desc, published desc"
2021-01-20 12:38:24 +00:00
}
2021-07-03 10:11:57 +00:00
table += sorting
if c . limit != 0 || c . offset != 0 {
table += " 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-03 10:11:57 +00:00
query = "select " + selection + " from " + table
return query , args
}
2021-07-19 14:32:45 +00:00
func ( d * database ) loadPostParameters ( posts [ ] * post , parameters ... string ) ( err error ) {
2021-07-06 19:06:39 +00:00
var sqlArgs [ ] interface { }
// Parameter filter
paramFilter := ""
if len ( parameters ) > 0 {
paramFilter = " and parameter in ("
for i , p := range parameters {
if i > 0 {
paramFilter += ", "
}
named := fmt . Sprintf ( "param%v" , i )
paramFilter += "@" + named
sqlArgs = append ( sqlArgs , sql . Named ( named , p ) )
}
paramFilter += ")"
}
2021-07-19 14:32:45 +00:00
// Path filter
pathFilter := ""
if len ( posts ) > 0 {
pathFilter = " and path in ("
for i , p := range posts {
if i > 0 {
pathFilter += ", "
}
named := fmt . Sprintf ( "path%v" , i )
pathFilter += "@" + named
sqlArgs = append ( sqlArgs , sql . Named ( named , p . Path ) )
}
pathFilter += ")"
}
2021-07-06 19:06:39 +00:00
// Query
2021-07-19 14:32:45 +00:00
rows , err := d . query ( "select path, parameter, value from post_parameters where 1 = 1" + paramFilter + pathFilter + " order by id" , 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-06-06 12:39:42 +00:00
func ( d * database ) 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-06-06 12:39:42 +00:00
rows , err := d . 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 {
err = d . loadPostParameters ( posts , config . withOnlyParameters ... )
if err != nil {
return nil , err
}
}
2020-11-09 15:40:12 +00:00
return posts , nil
}
2021-06-06 12:39:42 +00:00
func ( d * database ) getPost ( path string ) ( * post , error ) {
2021-07-03 10:11:57 +00:00
posts , err := d . 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
2020-12-26 19:40:22 +00:00
type publishedDate struct {
year , month , day int
}
2021-06-06 12:39:42 +00:00
func ( d * database ) allPublishedDates ( blog string ) ( dates [ ] publishedDate , err error ) {
2021-07-14 13:44:57 +00:00
rows , err := d . query ( "select distinct substr(tolocal(published), 1, 4) as year, substr(tolocal(published), 6, 2) as month, substr(tolocal(published), 9, 2) as day from posts where blog = @blog and status = @status and year != '' and month != '' and day != ''" , sql . Named ( "blog" , blog ) , sql . Named ( "status" , statusPublished ) )
2020-12-13 14:16:47 +00:00
if err != nil {
return nil , err
}
for rows . Next ( ) {
2020-12-26 19:40:22 +00:00
var year , month , day int
err = rows . Scan ( & year , & month , & day )
2020-12-13 14:16:47 +00:00
if err != nil {
return nil , err
}
2020-12-26 19:40:22 +00:00
dates = append ( dates , publishedDate { year , month , day } )
2020-12-13 14:16:47 +00:00
}
return
}
2021-06-29 16:11:42 +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 }
nameValues := ""
for i , n := range names {
if i > 0 {
nameValues += ", "
}
named := fmt . Sprintf ( "name%v" , i )
nameValues += fmt . Sprintf ( "(@%s)" , named )
sqlArgs = append ( sqlArgs , sql . Named ( named , n ) )
2021-06-29 16:11:42 +00:00
}
2021-07-12 17:29:32 +00:00
rows , err := db . query ( fmt . Sprintf ( mediaUseSql , nameValues ) , 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
}