mirror of
https://github.com/badges/shields.git
synced 2025-04-18 19:44:04 +03:00
Support [Matrix] summary endpoint (#10782)
* feat: add support for Matrix summary endpoint * docs: update Matrix documentation * refactor: abstract logic into more functions * refactor: revert custom timeout for tests * test: add test for fetchMode override on matrix.org * fix: validate the fetchMode value * docs: extend fetchMode description * fix: add await keywords * clarify test description --------- Co-authored-by: chris48s <git@chris-shaw.dev>
This commit is contained in:
parent
18e17233c4
commit
2c653013c8
@ -5,9 +5,15 @@ import {
|
||||
pathParam,
|
||||
queryParam,
|
||||
} from '../index.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
|
||||
const fetchModeEnum = ['guest', 'summary']
|
||||
|
||||
const queryParamSchema = Joi.object({
|
||||
server_fqdn: Joi.string().hostname(),
|
||||
fetchMode: Joi.string()
|
||||
.valid(...fetchModeEnum)
|
||||
.default('guest'),
|
||||
}).required()
|
||||
|
||||
const matrixRegisterSchema = Joi.object({
|
||||
@ -31,9 +37,16 @@ const matrixStateSchema = Joi.array()
|
||||
)
|
||||
.required()
|
||||
|
||||
const matrixSummarySchema = Joi.object({
|
||||
num_joined_members: nonNegativeInteger,
|
||||
}).required()
|
||||
|
||||
const description = `
|
||||
In order for this badge to work, the host of your room must allow guest accounts or dummy accounts to register, and the room must be world readable (chat history visible to anyone).
|
||||
|
||||
Alternatively access via the experimental <code>summary</code> endpoint ([MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)) can be configured with the query parameter <code>fetchMode</code> for less server load and better performance, if supported by the homeserver<br/>
|
||||
For the <code>matrix.org</code> homeserver <code>fetchMode</code> is hard-coded to <code>summary</code>.
|
||||
|
||||
The following steps will show you how to setup the badge URL using the Element Matrix client.
|
||||
|
||||
<ul>
|
||||
@ -76,6 +89,15 @@ export default class Matrix extends BaseJsonService {
|
||||
name: 'server_fqdn',
|
||||
example: 'matrix.org',
|
||||
}),
|
||||
queryParam({
|
||||
name: 'fetchMode',
|
||||
example: 'guest',
|
||||
description: `<code>guest</code> configures guest authentication while <code>summary</code> configures usage of the experimental "summary" endpoint ([MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266)). If not specified, the default fetch mode is <code>guest</code> (except for matrix.org).`,
|
||||
schema: {
|
||||
type: 'string',
|
||||
enum: fetchModeEnum,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -147,27 +169,27 @@ export default class Matrix extends BaseJsonService {
|
||||
})
|
||||
}
|
||||
|
||||
async fetch({ roomAlias, serverFQDN }) {
|
||||
let host
|
||||
if (serverFQDN === undefined) {
|
||||
const splitAlias = roomAlias.split(':')
|
||||
// A room alias can either be in the form #localpart:server or
|
||||
// #localpart:server:port.
|
||||
switch (splitAlias.length) {
|
||||
case 2:
|
||||
host = splitAlias[1]
|
||||
break
|
||||
case 3:
|
||||
host = `${splitAlias[1]}:${splitAlias[2]}`
|
||||
break
|
||||
default:
|
||||
throw new InvalidParameter({ prettyMessage: 'invalid alias' })
|
||||
}
|
||||
} else {
|
||||
host = serverFQDN
|
||||
}
|
||||
async fetchSummary({ host, roomAlias }) {
|
||||
const data = await this._requestJson({
|
||||
url: `https://${host}/_matrix/client/unstable/im.nheko.summary/rooms/%23${encodeURIComponent(
|
||||
roomAlias,
|
||||
)}/summary`,
|
||||
schema: matrixSummarySchema,
|
||||
httpErrors: {
|
||||
400: 'unknown request',
|
||||
404: 'room or endpoint not found',
|
||||
},
|
||||
})
|
||||
return data.num_joined_members
|
||||
}
|
||||
|
||||
async fetchGuest({ host, roomAlias }) {
|
||||
const accessToken = await this.retrieveAccessToken({ host })
|
||||
const lookup = await this.lookupRoomAlias({ host, roomAlias, accessToken })
|
||||
const lookup = await this.lookupRoomAlias({
|
||||
host,
|
||||
roomAlias,
|
||||
accessToken,
|
||||
})
|
||||
const data = await this._requestJson({
|
||||
url: `https://${host}/_matrix/client/r0/rooms/${encodeURIComponent(
|
||||
lookup.room_id,
|
||||
@ -194,8 +216,36 @@ export default class Matrix extends BaseJsonService {
|
||||
: 0
|
||||
}
|
||||
|
||||
async handle({ roomAlias }, { server_fqdn: serverFQDN }) {
|
||||
const members = await this.fetch({ roomAlias, serverFQDN })
|
||||
async fetch({ roomAlias, serverFQDN, fetchMode }) {
|
||||
let host
|
||||
if (serverFQDN === undefined) {
|
||||
const splitAlias = roomAlias.split(':')
|
||||
// A room alias can either be in the form #localpart:server or
|
||||
// #localpart:server:port.
|
||||
switch (splitAlias.length) {
|
||||
case 2:
|
||||
host = splitAlias[1]
|
||||
break
|
||||
case 3:
|
||||
host = `${splitAlias[1]}:${splitAlias[2]}`
|
||||
break
|
||||
default:
|
||||
throw new InvalidParameter({ prettyMessage: 'invalid alias' })
|
||||
}
|
||||
} else {
|
||||
host = serverFQDN
|
||||
}
|
||||
if (host.toLowerCase() === 'matrix.org' || fetchMode === 'summary') {
|
||||
// summary endpoint (default for matrix.org)
|
||||
return await this.fetchSummary({ host, roomAlias })
|
||||
} else {
|
||||
// guest access
|
||||
return await this.fetchGuest({ host, roomAlias })
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ roomAlias }, { server_fqdn: serverFQDN, fetchMode }) {
|
||||
const members = await this.fetch({ roomAlias, serverFQDN, fetchMode })
|
||||
return this.constructor.render({ members })
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +152,26 @@ t.create('get room state as member (backup method)')
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('get room summary')
|
||||
.get('/ALIAS:DUMMY.dumb.json?fetchMode=summary')
|
||||
.intercept(nock =>
|
||||
nock('https://DUMMY.dumb/')
|
||||
.get(
|
||||
'/_matrix/client/unstable/im.nheko.summary/rooms/%23ALIAS%3ADUMMY.dumb/summary',
|
||||
)
|
||||
.reply(
|
||||
200,
|
||||
JSON.stringify({
|
||||
num_joined_members: 4,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: '4 users',
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('bad server or connection')
|
||||
.get('/ALIAS:DUMMY.dumb.json')
|
||||
.networkOff()
|
||||
@ -263,6 +283,27 @@ t.create('unknown request')
|
||||
color: 'lightgrey',
|
||||
})
|
||||
|
||||
t.create('unknown summary request')
|
||||
.get('/ALIAS:DUMMY.dumb.json?fetchMode=summary')
|
||||
.intercept(nock =>
|
||||
nock('https://DUMMY.dumb/')
|
||||
.get(
|
||||
'/_matrix/client/unstable/im.nheko.summary/rooms/%23ALIAS%3ADUMMY.dumb/summary',
|
||||
)
|
||||
.reply(
|
||||
400,
|
||||
JSON.stringify({
|
||||
errcode: 'M_UNRECOGNIZED',
|
||||
error: 'Unrecognized request',
|
||||
}),
|
||||
),
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: 'unknown request',
|
||||
color: 'lightgrey',
|
||||
})
|
||||
|
||||
t.create('unknown alias')
|
||||
.get('/ALIAS:DUMMY.dumb.json')
|
||||
.intercept(nock =>
|
||||
@ -291,6 +332,27 @@ t.create('unknown alias')
|
||||
color: 'red',
|
||||
})
|
||||
|
||||
t.create('unknown summary alias')
|
||||
.get('/ALIAS:DUMMY.dumb.json?fetchMode=summary')
|
||||
.intercept(nock =>
|
||||
nock('https://DUMMY.dumb/')
|
||||
.get(
|
||||
'/_matrix/client/unstable/im.nheko.summary/rooms/%23ALIAS%3ADUMMY.dumb/summary',
|
||||
)
|
||||
.reply(
|
||||
404,
|
||||
JSON.stringify({
|
||||
errcode: 'M_NOT_FOUND',
|
||||
error: 'Room alias #ALIAS%3ADUMMY.dumb not found.',
|
||||
}),
|
||||
),
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: 'room or endpoint not found',
|
||||
color: 'red',
|
||||
})
|
||||
|
||||
t.create('invalid alias').get('/ALIASDUMMY.dumb.json').expectBadge({
|
||||
label: 'chat',
|
||||
message: 'invalid alias',
|
||||
@ -368,6 +430,26 @@ t.create('server uses a custom port')
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('server uses a custom port for summary')
|
||||
.get('/ALIAS:DUMMY.dumb:5555.json?fetchMode=summary')
|
||||
.intercept(nock =>
|
||||
nock('https://DUMMY.dumb:5555/')
|
||||
.get(
|
||||
'/_matrix/client/unstable/im.nheko.summary/rooms/%23ALIAS%3ADUMMY.dumb%3A5555/summary',
|
||||
)
|
||||
.reply(
|
||||
200,
|
||||
JSON.stringify({
|
||||
num_joined_members: 4,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: '4 users',
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('specify the homeserver fqdn')
|
||||
.get('/ALIAS:DUMMY.dumb.json?server_fqdn=matrix.DUMMY.dumb')
|
||||
.intercept(nock =>
|
||||
@ -439,9 +521,56 @@ t.create('specify the homeserver fqdn')
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('test on real matrix room for API compliance')
|
||||
.get('/twim:matrix.org.json')
|
||||
.timeout(10000)
|
||||
t.create('specify the homeserver fqdn for summary')
|
||||
.get('/ALIAS:DUMMY.dumb.json?server_fqdn=matrix.DUMMY.dumb&fetchMode=summary')
|
||||
.intercept(nock =>
|
||||
nock('https://matrix.DUMMY.dumb/')
|
||||
.get(
|
||||
'/_matrix/client/unstable/im.nheko.summary/rooms/%23ALIAS%3ADUMMY.dumb/summary',
|
||||
)
|
||||
.reply(
|
||||
200,
|
||||
JSON.stringify({
|
||||
num_joined_members: 4,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: '4 users',
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('test fetchMode=guest is ignored for matrix.org')
|
||||
.get('/ALIAS:DUMMY.dumb.json?server_fqdn=matrix.org&fetchMode=guest')
|
||||
.intercept(nock =>
|
||||
nock('https://matrix.org/')
|
||||
.get(
|
||||
'/_matrix/client/unstable/im.nheko.summary/rooms/%23ALIAS%3ADUMMY.dumb/summary',
|
||||
)
|
||||
.reply(
|
||||
200,
|
||||
JSON.stringify({
|
||||
num_joined_members: 4,
|
||||
}),
|
||||
),
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: '4 users',
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('test on real matrix room for guest API compliance')
|
||||
.get('/ndcube:openastronomy.org.json?server_fqdn=openastronomy.modular.im')
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: Joi.string().regex(/^[0-9]+ users$/),
|
||||
color: 'brightgreen',
|
||||
})
|
||||
|
||||
t.create('test on real matrix room for summary API compliance')
|
||||
.get('/twim:matrix.org.json')
|
||||
.expectBadge({
|
||||
label: 'chat',
|
||||
message: Joi.string().regex(/^[0-9]+ users$/),
|
||||
|
Loading…
x
Reference in New Issue
Block a user