UNPKG

6.61 kBJavaScriptView Raw
1module.exports.publish = (options) => {
2 // TODO: Get cover attributes up here.
3
4 'use strong'
5
6 const chalk = require('chalk')
7 const request = require('superagent')
8 const path = require('path')
9 const osHomeDir = require('os').homedir()
10 const fs = require('fs')
11 const jsonfile = require('jsonfile')
12 const manuscript = require('book-length')
13 const arc = require('arc-bookiza')
14
15 const location = path.join(osHomeDir, '.', '.bookizarc')
16
17 arc.read(location)
18 .then(data => {
19 const bookizArc = JSON.parse(data) // Arc object
20 if (bookizArc.token === '') {
21 throw new Error('BookizArc.token unavailable!')
22 }
23 initializeBookPress(bookizArc)
24 })
25 .catch(err => {
26 console.log(chalk.bold.red('Unregistered client'))
27 console.log(chalk.bold.cyan('Try $ bookiza register --help'))
28 console.log(err)
29 })
30
31
32 function initializeBookPress (bookizArc) {
33 const file = '.bookrc'
34
35 jsonfile.readFile(file, (err, bookrc) => {
36 if (err) {
37 throw new Error('Couldn\'t read the arc.')
38 }
39 if (!(bookrc.hasOwnProperty('book_id'))) {
40 requestBookId(bookizArc, bookrc, options.token)
41 } else {
42 patchBook(bookizArc, bookrc, options.token)
43 }
44 })
45 }
46
47 function requestBookId (bookizArc, bookrc, token = bookizArc.token) {
48 if (token === undefined) {
49 console.log(chalk.red('Cannot proceed without API_token'))
50 return
51 }
52
53 const url = bookizArc.urls.baseURL
54 const method = 'post'
55
56 request[method](url)
57 .send()
58 .set('Accept', 'application/json')
59 .set('Accept', 'application/bookiza.bubblin.v2')
60 .set('Authorization', `Token token=${token}`)
61 .end((err, res) => {
62 if (!err && res.ok && res.body.status === 201 && res.body.id !== null) {
63 bookrc.book_id = res.body.id
64 fs.writeFileSync('.bookrc', JSON.stringify(bookrc, null, 2))
65 patchBook(bookizArc, bookrc, token)
66 } else {
67 let errorMessage
68 if (res && res.body.status === 401) {
69 errorMessage = 'Authentication failed! Bad username/password?'
70 } else if (res.body.status === 403) {
71 errorMessage = 'Submission unauthorized!'
72 } else {
73 errorMessage = res.text
74 }
75 console.error(chalk.red(errorMessage))
76 process.exit(1)
77 }
78 })
79 }
80
81 function patchBook (bookizArc, bookrc, token = bookizArc.token) {
82 const book = {}
83
84 book.title = bookrc.name || 'Untitled'
85 book.has_page_numbers = bookrc.has_page_numbers || 'false'
86 book.status = bookrc.status || 'draft' /* Required for automated publishing only. */
87 book.id = bookrc.book_id
88
89 /*
90 * Nested attributes for layout template.
91 */
92
93 const COMPONENTS = [
94 { name: 'HEAD', path: 'head.html' },
95 { name: 'HTML', path: 'body.html' },
96 { name: 'CSS', path: 'style.css' },
97 { name: 'JS', path: 'script.js' }
98 ]
99
100 const template = {}
101
102 for (const templateIndex in COMPONENTS) {
103 const templateComponentPath = path.join('build', 'templates', COMPONENTS[templateIndex].path)
104 if (fs.existsSync(templateComponentPath)) {
105 template[COMPONENTS[templateIndex].name] = fs.readFileSync(templateComponentPath, 'utf-8').toString()
106 }
107 }
108
109 book.template_attributes = template
110
111 /*
112 * Nested attributes for cover page.
113 */
114 const cover = {}
115
116 let toc = ''
117 if (fs.existsSync(path.join('.', 'cover', 'toc.html'))) {
118 toc = fs.readFileSync(path.join('.', 'cover', 'toc.html'), 'utf-8').toString()
119 }
120
121 if (bookrc.hasOwnProperty('cover')) {
122 cover.punchline = bookrc.cover.punchline || ''
123 cover.toc = toc
124 cover.author_detail = bookrc.cover.author_detail || ''
125 cover.colophon = bookrc.cover.colophon || ''
126 cover.synopsis = bookrc.cover.synopsis || ''
127 }
128
129 book.cover_attributes = cover
130
131 const length = manuscript.length()
132
133 let pages = [] // Array of Page Objects
134
135 const PAGES_CHUNK_SIZE = 50
136
137 let batchStart = 1
138 let batchEnd = length < PAGES_CHUNK_SIZE ? length : PAGES_CHUNK_SIZE
139
140 let requestStatus = []
141
142 do {
143 for (let pageNo = batchStart; pageNo <= batchEnd; pageNo++) {
144 const page = {}
145
146 page.book_id = book.id
147
148 page.page_no = pageNo
149 for (const index in COMPONENTS) {
150 const componentPath = path.join('build', 'manuscript', `page-${pageNo}`, COMPONENTS[index].path)
151 if (fs.existsSync(componentPath)) {
152 page[COMPONENTS[index].name] = fs.readFileSync(componentPath, 'utf-8').toString()
153 }
154 }
155 pages.push(page)
156 }
157
158 book.pages_attributes = pages
159
160 const bookJson = {}
161
162 bookJson.book = book
163 bookJson.length = length
164
165 const url = bookizArc.urls.baseURL + book.id
166 const method = 'patch'
167
168 request[method](url)
169 .send(encodeURI(JSON.stringify(bookJson)))
170 .set('Accept', 'application/json')
171 .set('Accept', 'application/bookiza.bubblin.v2')
172 .set('Authorization', `Token token=${token}`)
173 .set('gzip', 'true')
174 .end((err, res) => {
175 process.stdout.write(chalk.bold.blue('🖇'))
176
177 requestStatus.push(1)
178
179 if (batchStart > length && batchEnd === length) {
180 printComplete(res)
181 }
182
183 if (!(!err && res.ok && res.body.status === 200)) {
184 let errorMessage
185 if (res && res.body.status === 401) {
186 errorMessage = 'Authentication failed! Bad username/password?'
187 } else if (res.body.status === 403) {
188 errorMessage = 'Submission unauthorized!'
189 } else {
190 errorMessage = res.text
191 }
192 console.error(chalk.red(errorMessage))
193 process.exit(1)
194 }
195 })
196
197 batchStart = batchEnd + 1
198 batchEnd = (batchEnd + PAGES_CHUNK_SIZE) > length ? length : (batchEnd + PAGES_CHUNK_SIZE)
199
200 pages = []
201 } while (batchStart <= length)
202
203 function float2int (value) {
204 return value | 0
205 }
206
207 function printComplete (response) {
208 if (requestStatus.every(elem => elem === 1) && requestStatus.length === float2int(length / PAGES_CHUNK_SIZE) + 1) {
209
210 bookrc.book_url = response.body.url
211 fs.writeFileSync('.bookrc', JSON.stringify(bookrc, null, 2))
212
213
214 console.log(chalk.bold.cyan(' [100%] Manuscript patch completed successfully.'))
215 console.log(chalk.bold.yellow(' Book was patched into your Bubblin Account. Check online @ https://bubblin.io!'))
216 }
217 }
218 }
219}