From 39e3493dd3bfa2382d996864d1737a5db3297432 Mon Sep 17 00:00:00 2001 From: Ethan Shen <42264778+nczitzk@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:57:53 +0800 Subject: [PATCH] feat(route): add UK Parliament Petitions (#17746) * feat(route): add UK Parliament Petitions * fix typo --- lib/routes/parliament.uk/namespace.ts | 2 + lib/routes/parliament.uk/petitions.ts | 191 ++++++++++++++++++ .../parliament.uk/templates/description.art | 7 + 3 files changed, 200 insertions(+) create mode 100644 lib/routes/parliament.uk/petitions.ts create mode 100644 lib/routes/parliament.uk/templates/description.art diff --git a/lib/routes/parliament.uk/namespace.ts b/lib/routes/parliament.uk/namespace.ts index 18d9ae467c3459..5817bd6ba50d75 100644 --- a/lib/routes/parliament.uk/namespace.ts +++ b/lib/routes/parliament.uk/namespace.ts @@ -3,5 +3,7 @@ import type { Namespace } from '@/types'; export const namespace: Namespace = { name: 'UK Parliament', url: 'parliament.uk', + categories: ['government'], + description: 'The UK Parliament has two Houses that work on behalf of UK citizens to check and challenge the work of Government, make and shape effective laws, and debate/make decisions on the big issues of the day.', lang: 'en', }; diff --git a/lib/routes/parliament.uk/petitions.ts b/lib/routes/parliament.uk/petitions.ts new file mode 100644 index 00000000000000..1700598b579b7d --- /dev/null +++ b/lib/routes/parliament.uk/petitions.ts @@ -0,0 +1,191 @@ +import path from 'node:path'; + +import { type Context } from 'hono'; +import { load, type CheerioAPI } from 'cheerio'; + +import { type DataItem, type Route, type Data, ViewType } from '@/types'; +import { getCurrentPath } from '@/utils/helpers'; +import { parseDate } from '@/utils/parse-date'; +import { art } from '@/utils/render'; +import ofetch from '@/utils/ofetch'; + +const __dirname = getCurrentPath(import.meta.url); + +export const handler = async (ctx: Context): Promise => { + const { state = 'all' } = ctx.req.param(); + const limit: number = Number.parseInt(ctx.req.query('limit') ?? '50', 10); + + const rootUrl: string = 'https://petition.parliament.uk'; + const targetUrl: string = new URL(`petitions?state=${state}`, rootUrl).href; + const jsonUrl: string = new URL('petitions.json', rootUrl).href; + + const response = await ofetch(targetUrl); + const $: CheerioAPI = load(response); + const language: string = $('html').prop('lang') ?? 'en'; + + const jsonResponse = await ofetch(jsonUrl, { + query: { + page: 1, + state, + }, + }); + + const items = jsonResponse.data.slice(0, limit).map((item): DataItem => { + const attributes = item.attributes; + + const title = attributes.action; + const description = art(path.join(__dirname, 'templates/description.art'), { + intro: attributes.background, + description: attributes.additional_details, + }); + const guid = `parliament.uk-petition-${item.id}`; + + const author: DataItem['author'] = attributes.creator_name; + + const extraLinks = attributes.departments?.map((link) => ({ + url: link.url, + type: 'related', + content_html: link.name, + })); + + return { + title, + description, + pubDate: parseDate(attributes.created_at), + link: new URL(`petitions/${item.id}`, rootUrl).href, + category: [...new Set([...(attributes.topics ?? []), ...(attributes.departments?.map((d) => d.name) ?? [])])].filter(Boolean), + author, + guid, + id: guid, + content: { + html: description, + text: attributes.background, + }, + updated: parseDate(attributes.updated_at), + language, + _extra: { + links: extraLinks?.length ? extraLinks : undefined, + }, + }; + }); + + const feedImage = $('meta[property="og:image"]').prop('content'); + + return { + title: $('h1.page-title').text(), + description: $('meta[property="twitter:description"]').prop('content'), + link: targetUrl, + item: items, + allowEmpty: true, + image: feedImage, + author: $('meta[name="msapplication-tooltip"]').prop('content'), + language, + id: $('meta[property="og:url"]').prop('content'), + }; +}; + +export const route: Route = { + path: '/petitions/:state?', + name: 'Petitions', + url: 'petition.parliament.uk', + maintainers: ['nczitzk'], + handler, + example: '/parliament.uk/petitions/all', + parameters: { + state: 'State, `all` by default, see below', + }, + description: `:::tip +If you subscribe to [Recent petitions](https://petition.parliament.uk/petitions?state=recent),where the URL is \`https://petition.parliament.uk/petitions?state=recent\`, use the value of \`state\` as the parameter to fill in. Therefore, the route will be [\`/parliament.uk/petitions/recent\`](https://rsshub.app/parliament.uk/petitions/recent). +::: + +
+ More states + +| Name | ID | +| ------------------------------- | ----------------- | +| All petitions | all | +| Open petitions | open | +| Recent petitions | recent | +| Closed petitions | closed | +| Rejected petitions | rejected | +| Awaiting government response | awaiting_response | +| Government responses | with_response | +| Awaiting a debate in Parliament | awaiting_debate | +| Debated in Parliament | debated | +| Not debated in Parliament | not_debated | + +
+ `, + categories: ['government'], + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportRadar: true, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + radar: [ + { + source: ['petition.parliament.uk/petitions'], + target: (_, url) => { + const urlObj = new URL(url); + const state = urlObj.searchParams.get('state'); + + return `/parliament.uk/petitions${state ? `/${state}` : ''}`; + }, + }, + { + title: 'All petitions', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/all', + }, + { + title: 'Open petitions', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/open', + }, + { + title: 'Recent petitions', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/recent', + }, + { + title: 'Closed petitions', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/closed', + }, + { + title: 'Rejected petitions', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/rejected', + }, + { + title: 'Awaiting government response', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/awaiting_response', + }, + { + title: 'Government responses', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/with_response', + }, + { + title: 'Awaiting a debate in Parliament', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/awaiting_debate', + }, + { + title: 'Debated in Parliament', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/debated', + }, + { + title: 'Not debated in Parliament', + source: ['petition.parliament.uk/petitions'], + target: '/petitions/not_debated', + }, + ], + view: ViewType.Articles, +}; diff --git a/lib/routes/parliament.uk/templates/description.art b/lib/routes/parliament.uk/templates/description.art new file mode 100644 index 00000000000000..eee77a05425830 --- /dev/null +++ b/lib/routes/parliament.uk/templates/description.art @@ -0,0 +1,7 @@ +{{ if intro }} +
{{ intro }}
+{{ /if }} + +{{ if description }} +

{{ description }}

+{{ /if }} \ No newline at end of file