initial commit
Todas las comprobaciones han sido exitosas
continuous-integration/drone Build is passing
Todas las comprobaciones han sido exitosas
continuous-integration/drone Build is passing
Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
545
back/lib/apiswagger.js
Archivo normal
545
back/lib/apiswagger.js
Archivo normal
@@ -0,0 +1,545 @@
|
||||
module.exports = (app, client) => {
|
||||
const constant = require('../constant'),
|
||||
zlib = require('zlib'),
|
||||
asyncHandler = require('express-async-handler'),
|
||||
{ param, validationResult } = require('express-validator')
|
||||
/**
|
||||
* @swagger
|
||||
* /api/stats:
|
||||
* get:
|
||||
* summary: Retrieve stats of instances.
|
||||
* description: Retrieve stats of total instances.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A object with stats parameters.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* instance_count:
|
||||
* type: integer
|
||||
* description: Count of instances.
|
||||
* example: 0
|
||||
* status_avg:
|
||||
* type: float
|
||||
* description: Average statuses of total instances.
|
||||
* example: 0
|
||||
* status_max:
|
||||
* type: integer
|
||||
* description: Max of total statuses instances.
|
||||
* example: 0
|
||||
* user_avg:
|
||||
* type: float
|
||||
* description: Average users of total instances.
|
||||
* example: 0
|
||||
* user_max:
|
||||
* type: integer
|
||||
* description: Max of total users instances.
|
||||
* example: 0
|
||||
* domain_avg:
|
||||
* type: float
|
||||
* description: Number of average domains instances.
|
||||
* example: 0
|
||||
* domain_max:
|
||||
* type: integer
|
||||
* description: Number of max domains instances.
|
||||
* example: 0
|
||||
* stats_filtered:
|
||||
* type: integer
|
||||
* description: Number of instances stats.
|
||||
* example: 0
|
||||
*/
|
||||
app.get('/api/stats', asyncHandler(async (req, res) => {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
body: {
|
||||
size: 0,
|
||||
aggs: {
|
||||
instance_count: {
|
||||
value_count: {
|
||||
field: '_id'
|
||||
}
|
||||
},
|
||||
stats_filtered: {
|
||||
filter: {
|
||||
exists: {
|
||||
field: 'api.stats'
|
||||
}
|
||||
}
|
||||
},
|
||||
user_avg: {
|
||||
avg: {
|
||||
field: 'api.stats.user_count'
|
||||
}
|
||||
},
|
||||
user_max: {
|
||||
max: {
|
||||
field: 'api.stats.user_count'
|
||||
}
|
||||
},
|
||||
domain_avg: {
|
||||
avg: {
|
||||
field: 'api.stats.domain_count'
|
||||
}
|
||||
},
|
||||
domain_max: {
|
||||
max: {
|
||||
field: 'api.stats.domain_count'
|
||||
}
|
||||
},
|
||||
status_avg: {
|
||||
avg: {
|
||||
field: 'api.stats.status_count'
|
||||
}
|
||||
},
|
||||
status_max: {
|
||||
max: {
|
||||
field: 'api.stats.status_count'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
res.json(Object.keys(result.aggregations).reduce((prev, curr) => ({
|
||||
...prev, [curr]: result.aggregations[curr][Object.keys(result.aggregations[curr])[0]]
|
||||
}), {}))
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/count:
|
||||
* get:
|
||||
* summary: Retrieve count of instances.
|
||||
* description: Retrieve a number of total instances.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A object with count parameter.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* count:
|
||||
* type: integer
|
||||
* description: Number of instances.
|
||||
* example: 0
|
||||
*/
|
||||
app.get('/api/count', asyncHandler(async (req, res) => {
|
||||
res.json({ count: (await client.count({ index: constant.index })).count })
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/ranking:
|
||||
* get:
|
||||
* summary: Retrieve one ranking of instances.
|
||||
* description: Retrieve a top ten ranking of total fediblock instances.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A object with count parameter.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* domain:
|
||||
* type: string
|
||||
* description: Domain of the instance.
|
||||
* example: "mastodon.social"
|
||||
* count:
|
||||
* type: integer
|
||||
* description: Number of fediblocks.
|
||||
* example: 0
|
||||
*/
|
||||
app.get('/api/ranking', asyncHandler(async (req, res) => {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
body: {
|
||||
size: 0,
|
||||
aggs: {
|
||||
blocks: {
|
||||
nested: {
|
||||
path: 'blocks'
|
||||
},
|
||||
aggs: {
|
||||
ranking: {
|
||||
terms: {
|
||||
field: 'blocks.domain',
|
||||
size: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const ranking = result.aggregations?.blocks?.ranking?.buckets
|
||||
res.json(ranking.map(r => ({ domain: r.key, count: r.doc_count })))
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/list/{instance}:
|
||||
* get:
|
||||
* summary: Search result array of intances.
|
||||
* description: Retrieve a result array of instances matching search input.
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: instance
|
||||
* required: true
|
||||
* description: String for search instance
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of instances.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* instances:
|
||||
* type: array
|
||||
* items:
|
||||
* type: data
|
||||
* description: List of instances.
|
||||
* example: "mastodon.social"
|
||||
* suggests:
|
||||
* type: array
|
||||
* items:
|
||||
* type: data
|
||||
* description: Suggest of the instance.
|
||||
* example: "mastodon.social"
|
||||
*/
|
||||
app.get('/api/list/:instance', param('instance').notEmpty().trim().escape(), asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
errors: errors.array()
|
||||
})
|
||||
}
|
||||
if (req.params.instance && req.params.instance.length > 0) {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
size: 10,
|
||||
query: {
|
||||
wildcard: {
|
||||
instance: {
|
||||
value: `*${req.params.instance}*`
|
||||
}
|
||||
},
|
||||
},
|
||||
suggest: {
|
||||
suggests: {
|
||||
text: req.params.instance,
|
||||
term: {
|
||||
field: 'instance',
|
||||
size: 3,
|
||||
sort: 'score',
|
||||
suggest_mode: 'always',
|
||||
max_edits: 2,
|
||||
min_word_length: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const instances = result.hits?.hits?.length > 0 ? result.hits.hits : [],
|
||||
suggests = result.suggest.suggests && result.suggest.suggests.length > 0 && result.suggest.suggests[0].options.length > 0 ? result.suggest.suggests[0].options : []
|
||||
res.json({
|
||||
instances: instances.map(instance => ({
|
||||
domain: instance._source.instance,
|
||||
api: instance._source.api ? instance._source.api : null,
|
||||
blocks: instance._source.blocks && instance._source.blocks.length > 0 ? instance._source.blocks.length : null,
|
||||
last: instance._source.last ? instance._source.last : null,
|
||||
nodeinfo: instance._source.nodeinfo ? true : false
|
||||
})), suggests: suggests.map(instance => instance.text)
|
||||
})
|
||||
} else {
|
||||
res.status(404).end()
|
||||
}
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/detail/{instance}:
|
||||
* get:
|
||||
* summary: Search result array of fediblocks intances.
|
||||
* description: Retrieve a result array of fediblock instances matching search input.
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: instance
|
||||
* required: true
|
||||
* description: String to detail of the instance
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of instances.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* domain:
|
||||
* type: string
|
||||
* description: Domain of the block instance.
|
||||
* example: "mastodon.social"
|
||||
* comment:
|
||||
* type: string
|
||||
* description: Comment of the block instance.
|
||||
* example: "mastodon.social"
|
||||
* severity:
|
||||
* type: string
|
||||
* description: Severity of the block instance.
|
||||
* example: "mastodon.social"
|
||||
*
|
||||
*/
|
||||
app.get('/api/detail/:instance', param('instance').notEmpty().trim().escape(), asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
errors: errors.array()
|
||||
})
|
||||
}
|
||||
if (req.params.instance && req.params.instance.length > 0) {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
size: 1,
|
||||
query: {
|
||||
term: {
|
||||
instance: req.params.instance
|
||||
}
|
||||
}
|
||||
})
|
||||
const instances = result.hits?.hits?.length > 0 ? result.hits.hits : []
|
||||
res.json(instances.length > 0 && instances[0]._source.blocks && instances[0]._source.blocks.length > 0 ?
|
||||
{
|
||||
blocks: instances[0]._source.blocks.map(instance => ({ domain: instance.domain, comment: instance.comment, severity: instance.severity })),
|
||||
last: instances[0]._source.last,
|
||||
instance: instances[0]._source.instance,
|
||||
nodeinfo: instances[0]._source.nodeinfo,
|
||||
api: instances[0]._source.api,
|
||||
took: result.took
|
||||
} : [])
|
||||
} else {
|
||||
res.status(404).end()
|
||||
}
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/detail_api/{instance}:
|
||||
* get:
|
||||
* summary: Search result of detail's api intance.
|
||||
* description: Retrieve a result of detail's api instance.
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: instance
|
||||
* required: true
|
||||
* description: String to detail of the instance
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Detail of the api instance.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
*/
|
||||
app.get('/api/detail_api/:instance', param('instance').notEmpty().trim().escape(), asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
errors: errors.array()
|
||||
})
|
||||
}
|
||||
if (req.params.instance && req.params.instance.length > 0) {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
size: 1,
|
||||
query: {
|
||||
term: {
|
||||
instance: req.params.instance
|
||||
}
|
||||
}
|
||||
})
|
||||
const instances = result.hits?.hits?.length > 0 ? result.hits.hits : []
|
||||
res.json(instances.length > 0 ? instances[0]._source.api : {})
|
||||
} else {
|
||||
res.status(404).end()
|
||||
}
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/detail_nodeinfo/{instance}:
|
||||
* get:
|
||||
* summary: Search result of detail's nodeinfo intance.
|
||||
* description: Retrieve a result of detail's nodeinfo instance.
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: instance
|
||||
* required: true
|
||||
* description: String to detail of the instance
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Detail of the nodeinfo instance.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
*/
|
||||
app.get('/api/detail_nodeinfo/:instance', param('instance').notEmpty().trim().escape(), asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
errors: errors.array()
|
||||
})
|
||||
}
|
||||
if (req.params.instance && req.params.instance.length > 0) {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
size: 1,
|
||||
query: {
|
||||
term: {
|
||||
instance: req.params.instance
|
||||
}
|
||||
}
|
||||
})
|
||||
const instances = result.hits?.hits?.length > 0 ? result.hits.hits : []
|
||||
res.json(instances.length > 0 ? instances[0]._source.nodeinfo : {})
|
||||
} else {
|
||||
res.status(404).end()
|
||||
}
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/block_count/{instance}:
|
||||
* get:
|
||||
* summary: Retrieve count of fediblocked instances.
|
||||
* description: Retrieve a number of total fediblocked instances.
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: instance
|
||||
* required: true
|
||||
* description: String to search fediblocks of the instance
|
||||
* schema:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A object with block_count parameter.
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* data:
|
||||
* type: object
|
||||
* properties:
|
||||
* block_count:
|
||||
* type: integer
|
||||
* description: Number of fediblock instances.
|
||||
* example: 0
|
||||
* instances:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* instance:
|
||||
* type: string
|
||||
* description: Instance of the block.
|
||||
* example: mastodon.social
|
||||
* comment:
|
||||
* type: string
|
||||
* description: Comment about the block.
|
||||
* example: spam
|
||||
*/
|
||||
app.get('/api/block_count/:instance', param('instance').notEmpty().trim().escape(), asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
errors: errors.array()
|
||||
})
|
||||
}
|
||||
if (req.params.instance && req.params.instance.length > 0) {
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
size: 9999,
|
||||
query: {
|
||||
nested: {
|
||||
path: 'blocks',
|
||||
query: {
|
||||
term: {
|
||||
'blocks.domain': req.params.instance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const instances = result.hits?.hits?.length > 0 ? result.hits.hits : [],
|
||||
instancescomment = instances.map(i => ({
|
||||
instance: i._source.instance, comment: i._source.blocks.find(block => block.domain === req.params.instance).comment
|
||||
}))
|
||||
res.json({
|
||||
block_count: instances.length,
|
||||
instances: instancescomment,
|
||||
took: result.took
|
||||
})
|
||||
} else {
|
||||
res.status(404).end()
|
||||
}
|
||||
}))
|
||||
/**
|
||||
* @swagger
|
||||
* /api/download_index:
|
||||
* get:
|
||||
* summary: Retrieve all content of ElasticSearch index.
|
||||
* description: Retrieve all content of ElasticSearch index.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A file compressed with gzip.
|
||||
* content:
|
||||
* application/gzip:
|
||||
*/
|
||||
app.get('/api/download_index', asyncHandler(async (req, res) => {
|
||||
try {
|
||||
res.setHeader('Content-Type', 'application/gzip')
|
||||
res.setHeader('Content-disposition', 'attachment; filename=fediblock-index.json.gz')
|
||||
const result = await client.search({
|
||||
index: constant.index,
|
||||
size: 9999,
|
||||
query: {
|
||||
match_all: {}
|
||||
}
|
||||
}, { asStream: true, meta: false })
|
||||
result.pipe(zlib.createGzip()).pipe(res)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
res.status(404).end()
|
||||
}
|
||||
}))
|
||||
}
|
||||
Referencia en una nueva incidencia
Block a user