• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

scriptype / writ-cms / 28513799482

01 Jul 2026 11:20AM UTC coverage: 54.006% (+0.1%) from 53.905%
28513799482

push

github

scriptype
Simplify data payload in post create/update

650 of 1205 branches covered (53.94%)

Branch coverage included in aggregate %.

0 of 6 new or added lines in 2 files covered. (0.0%)

2242 of 4150 relevant lines covered (54.02%)

1574.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/cms/api/models/post.js
1
const { writeFile, mkdir, rename, rm } = require('fs/promises')
×
2
const { join, dirname, basename, relative } = require('path')
×
3
const matter = require('gray-matter')
×
NEW
4
const _ = require('lodash')
×
5
const { ['default']: filenamify } = require('filenamify')
×
6
const { unusedFilename } = require('unused-filename')
×
7
const { contentRootPath } = require('../helpers')
×
8

9
const replaceFilename = (oldAbsolutePath, newAbsolutePath) => {
×
10
  return join(
×
11
    dirname(oldAbsolutePath),
12
    basename(newAbsolutePath)
13
  )
14
}
15

16
const createPostModel = ({ getSettings, getContentModel }) => {
×
17
  const createPost = async (data, attachments) => {
×
18
    const opts = {
×
19
      taxonomyPath: data.taxonomyPath || [],
×
20
      title: data.title || 'Untitled',
×
21
      content: data.content || '',
×
22
      excerpt: data.excerpt || '',
×
23
      extension: data.extension || '.md',
×
24
      metadata: _.omit(data, ['taxonomyPath', 'title', 'content', 'excerpt', 'extension'])
25
    }
26
    const { rootDirectory, contentDirectory } = getSettings()
×
27
    const root = await contentRootPath(rootDirectory, contentDirectory)
×
28

29
    const sanitizedTitle = filenamify(opts.title)
×
30

31
    const path = join(...[root].concat(opts.taxonomyPath).concat(sanitizedTitle))
×
32
    const unusedPath = await unusedFilename(path)
×
33

34
    const shouldOverrideTitle = (sanitizedTitle !== opts.title) || (unusedPath !== path)
×
35
    const metadataWithTitle = shouldOverrideTitle ?
×
36
      {
37
        ...opts.metadata,
38
        title: `${opts.title}`
39
      } : opts.metadata
40

41
    const fileContent = matter.stringify({
×
42
      data: metadataWithTitle,
43
      content: opts.content,
44
      excerpt: opts.excerpt
45
    })
46
    try {
×
47
      await mkdir(unusedPath, { recursive: true })
×
48
    } catch {}
49
    return Promise.all([
×
50
      writeFile(`${join(unusedPath, 'post')}${opts.extension}`, fileContent),
51
      ...attachments.map(file => {
52
        const dest = join(unusedPath, file.originalname)
×
53
        return writeFile(dest, file.buffer)
×
54
      })
55
    ])
56
  }
57

58
  const updatePost = async (path, data, attachments = []) => {
×
59
    if (!path) {
×
60
      throw new Error('path is required')
×
61
    }
62

63
    const opts = {
×
64
      title: data.title || 'Untitled',
×
65
      content: data.content || '',
×
66
      excerpt: data.excerpt || '',
×
67
      extension: data.extension || '',
×
68
      metadata: _.omit(data, ['title', 'content', 'excerpt', 'extension'])
69
    }
70

71
    const collectionName = path.split('/')[0]
×
72
    const collection = getContentModel().subtree.collections.find(c => c.name === collectionName)
×
73
    const post = collection.subtree.posts.find(p => p.path === path)
×
74

75
    const isFoldered = !post.extension
×
76
    const isTitleDifferent = opts.title !== post.title
×
77
    let absolutePath = post.absolutePath
×
78
    let isPathDifferentThanTitle
79

80
    if (isTitleDifferent) {
×
81
      const sanitizedTitle = filenamify(opts.title)
×
82
      const sanitizedPath = replaceFilename(post.absolutePath, sanitizedTitle)
×
83
      const unusedPath = await unusedFilename(sanitizedPath)
×
84

85
      if (isFoldered) {
×
86
        await rename(post.absolutePath, unusedPath)
×
87
      } else {
88
        await rm(post.absolutePath)
×
89
      }
90

91
      isPathDifferentThanTitle = (sanitizedTitle !== opts.title) || (unusedPath !== sanitizedPath)
×
92
      absolutePath = isFoldered ? unusedPath : `${unusedPath}${opts.extension || post.extension}`
×
93
    }
94

95
    const metadataWithTitle = isPathDifferentThanTitle ? {
×
96
      ...opts.metadata,
97
      title: `${opts.title}`
98
    } : opts.metadata
99

100
    const fileContent = matter.stringify({
×
101
      data: metadataWithTitle,
102
      content: opts.content,
103
      excerpt: opts.excerpt
104
    })
105

106
    const targetPath = isFoldered ?
×
107
      join(absolutePath, post.indexFile.name) :
108
      absolutePath
109

110
    await Promise.all([
×
111
      writeFile(targetPath, fileContent),
112
      ...attachments.map(file => {
113
        const dest = join(absolutePath, file.originalname)
×
114
        return writeFile(dest, file.buffer)
×
115
      })
116
    ])
117

118
    const { rootDirectory, contentDirectory } = getSettings()
×
119
    const root = await contentRootPath(rootDirectory, contentDirectory)
×
120

121
    return {
×
122
      path: relative(root, absolutePath)
123
    }
124
  }
125

126
  return {
×
127
    create: createPost,
128
    update: updatePost
129
  }
130
}
131

132
module.exports = createPostModel
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc