Merge branch 'staging' of github.com:EbookFoundation/river-of-ebooks into staging
commit
dcdde17cdd
|
@ -22,12 +22,15 @@ module.exports = {
|
|||
if (!body.metadata) throw new HttpError(400, 'Missing OPDS metadata')
|
||||
if (!body.metadata['@type'] || body.metadata['@type'] !== 'http://schema.org/Book') throw new HttpError(400, 'Invalid \'@type\': expected \'http://schema.org/Book\'')
|
||||
|
||||
let tags = (body.metadata.tags || '').split(/,\s*/)
|
||||
if (!tags.length && body.metadata.title) tags = body.metadata.title.split(/\s+/).filter(x => x.length < 3)
|
||||
const query = {
|
||||
hostname: host,
|
||||
title: body.metadata.title,
|
||||
author: body.metadata.author,
|
||||
publisher: body.metadata.publisher,
|
||||
identifier: body.metadata.identifier,
|
||||
tags: JSON.stringify(tags),
|
||||
version: body.metadata.modified.replace(/\D/g, '')
|
||||
}
|
||||
|
||||
|
@ -49,7 +52,10 @@ module.exports = {
|
|||
}
|
||||
|
||||
sendUpdatesAsync(result)
|
||||
return res.json(result)
|
||||
return res.json({
|
||||
...result,
|
||||
tags: JSON.parse(result.tags || '[]')
|
||||
})
|
||||
} catch (e) {
|
||||
if (e instanceof HttpError) return e.send(res)
|
||||
return res.status(500).json({
|
||||
|
@ -67,9 +73,8 @@ async function sendUpdatesAsync (book) {
|
|||
try {
|
||||
const item = targets[i]
|
||||
const user = await User.findOne({ id: item.user })
|
||||
const { author: fAuthor, publisher: fPublisher, title: fTitle, identifier: fIsbn, url } = item
|
||||
const { author: bAuthor, publisher: bPublisher, title: bTitle, identifier: bIsbn, opds } = book
|
||||
sails.log('sending ' + book.id + ' info to ' + url)
|
||||
const { author: fAuthor, publisher: fPublisher, title: fTitle, identifier: fIsbn, tags: fTags, url } = item
|
||||
const { author: bAuthor, publisher: bPublisher, title: bTitle, identifier: bIsbn, tags: bTags, opds } = book
|
||||
|
||||
if (uriRegex.test(url)) {
|
||||
if (fAuthor && !((bAuthor || '').includes(fAuthor))) continue
|
||||
|
@ -77,6 +82,13 @@ async function sendUpdatesAsync (book) {
|
|||
if (fTitle && !((bTitle || '').includes(fTitle))) continue
|
||||
if (fIsbn && !((bIsbn || '').includes(fIsbn))) continue
|
||||
|
||||
const filterTags = JSON.parse(fTags || '[]')
|
||||
if (filterTags.length && filterTags[0].length) {
|
||||
const otherSet = new Set(filterTags)
|
||||
if (!([...new Set(JSON.parse(bTags || '[]'))].filter(x => otherSet.has(x)).length)) continue
|
||||
}
|
||||
sails.log('sending ' + book.id + ' info to ' + url)
|
||||
|
||||
let content = opds
|
||||
const timestamp = Date.now()
|
||||
request.post({
|
||||
|
|
|
@ -42,7 +42,17 @@ module.exports = {
|
|||
page = Math.abs(+body.page) || 1
|
||||
delete body.page
|
||||
}
|
||||
let books = await Book.find(body || {}).skip((page * perPage) - perPage).limit(perPage)
|
||||
const searchBody = { ...body }
|
||||
if (searchBody.tags) {
|
||||
const tags = searchBody.tags.split(/,\s*/)
|
||||
searchBody.tags = {
|
||||
or: [
|
||||
...tags.map(tag => ({ contains: tag })),
|
||||
{ in: tags }
|
||||
]
|
||||
}
|
||||
}
|
||||
let books = await Book.find(body ? searchBody : {}).skip((page * perPage) - perPage).limit(perPage)
|
||||
|
||||
if (!books.length) {
|
||||
throw new HttpError(404, 'No books matching those parameters were found.')
|
||||
|
|
|
@ -25,13 +25,15 @@ module.exports = {
|
|||
const publisher = req.param('publisher') || ''
|
||||
const title = req.param('title') || ''
|
||||
const isbn = req.param('isbn') || ''
|
||||
const tags = req.param('tags') || ''
|
||||
if (value.length) {
|
||||
const url = await TargetUrl.update({ id, user: req.user.id }, {
|
||||
url: value,
|
||||
author,
|
||||
publisher,
|
||||
title,
|
||||
isbn
|
||||
isbn,
|
||||
tags: JSON.stringify(tags.split(/,\s*/))
|
||||
}).fetch()
|
||||
return res.json(url)
|
||||
} else {
|
||||
|
@ -52,9 +54,13 @@ module.exports = {
|
|||
},
|
||||
list: async function (req, res) {
|
||||
try {
|
||||
const urls = await TargetUrl.find({
|
||||
let urls = await TargetUrl.find({
|
||||
user: req.user.id
|
||||
})
|
||||
urls = urls.map(url => ({
|
||||
...url,
|
||||
tags: JSON.parse(url.tags || '[]')
|
||||
}))
|
||||
return res.json(urls)
|
||||
} catch (e) {
|
||||
return (new HttpError(500, e.message)).send(res)
|
||||
|
|
|
@ -23,7 +23,8 @@ module.exports = {
|
|||
identifier: { type: 'string' },
|
||||
version: { type: 'string' },
|
||||
hostname: { type: 'string' },
|
||||
opds: { type: 'json' }
|
||||
opds: { type: 'json' },
|
||||
tags: { type: 'string' }
|
||||
|
||||
// ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
|
||||
// ║╣ ║║║╠╩╗║╣ ║║╚═╗
|
||||
|
|
|
@ -15,6 +15,7 @@ module.exports = {
|
|||
author: 'string',
|
||||
publisher: 'string',
|
||||
title: 'string',
|
||||
isbn: 'string'
|
||||
isbn: 'string',
|
||||
tags: 'string'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class UriListItem extends React.Component {
|
|||
</div>
|
||||
<div className='col stack flex flex-container flex-vertical'>
|
||||
<span className='label'>Filters</span>
|
||||
<span className='value'>{['publisher', 'title', 'author', 'isbn'].reduce((a, x) => a + (this.props.item[x] ? 1 : 0), 0) || 'None'}</span>
|
||||
<span className='value'>{['publisher', 'title', 'author', 'isbn', 'tags'].reduce((a, x) => a + (this.props.item[x] ? 1 : 0), 0) || 'None'}</span>
|
||||
</div>
|
||||
<ConfirmIconButton icon='delete' onClick={() => this.props.dispatch(removeUrl(this.props.item.id))} />
|
||||
</li>
|
||||
|
@ -86,6 +86,15 @@ class UriListItem extends React.Component {
|
|||
value={'' + this.props.item.isbn}
|
||||
onChange={(e) => this.props.dispatch(changeUrlField(this.props.item.id, 'isbn', e.target.value))}
|
||||
onBlur={(e) => this.props.dispatch(setUrl(this.props.item))} />
|
||||
<UnderlineInput
|
||||
className='uri flex'
|
||||
type='text'
|
||||
name={'tags-' + this.props.item.id}
|
||||
placeholder='Tags'
|
||||
value={this.props.item.tags ? this.props.item.tags.join(', ') : ''}
|
||||
pattern={/^.*?(?:,\s+\S.+?)*$/}
|
||||
onChange={(e) => this.props.dispatch(changeUrlField(this.props.item.id, 'tags', e.target.value.split(/,\s+/)))}
|
||||
onBlur={(e) => this.props.dispatch(setUrl(this.props.item))} />
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
|
|
|
@ -18,6 +18,7 @@ and opds2 publication body with type `application/json`:
|
|||
"title": "Moby-Dick",
|
||||
"author": "Herman Melville",
|
||||
"identifier": "urn:isbn:978031600000X",
|
||||
"tags": ["story", "classic"],
|
||||
"publisher": "Ebook Publisher.com",
|
||||
"language": "en",
|
||||
"modified": "2015-09-29T17:00:00Z"
|
||||
|
@ -46,6 +47,7 @@ The server will respond with either:
|
|||
"id": number,
|
||||
"title": string,
|
||||
"author": string,
|
||||
"tags": array,
|
||||
"publisher": string,
|
||||
"identifier": string,
|
||||
"version": string,
|
||||
|
@ -72,6 +74,7 @@ title: The ebook's title (optional)
|
|||
author: The author (optional)
|
||||
version: A version number (optional)
|
||||
isbn: The ISBN (optional)
|
||||
tags: Comma-separated search tags (optional)
|
||||
|
||||
page: The page of results to view (200 results per page)
|
||||
```
|
||||
|
@ -107,6 +110,7 @@ The server will respond with either:
|
|||
"@type": "http://schema.org/Book",
|
||||
"title": "Moby-Dick",
|
||||
"author": "Herman Melville",
|
||||
"tags": ["story", "classic"],
|
||||
"publisher": "Ebook Publisher.com",
|
||||
"identifier": "urn:isbn:978031600000X",
|
||||
"language": "en",
|
||||
|
@ -165,6 +169,7 @@ HTTP Body:
|
|||
"@type": "http://schema.org/Book",
|
||||
"title": "Moby-Dick",
|
||||
"author": "Herman Melville",
|
||||
"tags": ["story", "classic"],
|
||||
"publisher": "Ebook Publisher.com",
|
||||
"identifier": "urn:isbn:978031600000X",
|
||||
"language": "en",
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
exports.up = function (knex, Promise) {
|
||||
return Promise.all([
|
||||
knex.schema.table('book', t => {
|
||||
t.string('tags')
|
||||
}),
|
||||
knex.schema.table('targeturl', t => {
|
||||
t.string('tags')
|
||||
})
|
||||
])
|
||||
}
|
||||
|
||||
exports.down = function (knex, Promise) {
|
||||
return Promise.all([
|
||||
knex.schema.table('book', t => {
|
||||
t.dropColumns('tags')
|
||||
}),
|
||||
knex.schema.table('targeturl', t => {
|
||||
t.dropColumns('tags')
|
||||
})
|
||||
])
|
||||
}
|
Loading…
Reference in New Issue