Skip to content

Commit

Permalink
feat(fetcher): implement vaksinasi.id db fetcher (#806)
Browse files Browse the repository at this point in the history
* feat(fetcher): implement vaksinasi.id db fetcher

Fetches vaksinasi.id's DB and store it in wbw-vaccination-database.json

Refs: #803

* style(fetcher): sort union type members in fetch-vaccine-database.ts

There is an ESLint warning in c84e78c, this commit addresses that warn

* refactor(fetcher): move types of vaksinid fetcher to lib

* refactor(fetcher): move the vaksin.id url to the top

* feat(fetcher): fetch vaksinasi.id db in fetch-wbw.ts

* refactor(fetcher): reduce repetition in vaccination types

* fix(fetcher): fix program stuck caused by spinner

fetchVaccinationDatabase() is so fast that a spinner stucks the program.

So, move it to the top and remove line 37.

* refactor(fetcher): transform vaksinid output data to be Contact-compatible

Transforms the output of the vaccination db fetcher to VaccinationContact[].

This will make it ready to be used downstream in the components.

The VaccinationContact interface has a 'map' property.
This is unecessary as WBW's "Buka Peta" button uses the address instead.
Though, I still add it in case we want to use that for the "Buka Peta" button.

* refactor(fetcher): change vaksin.id output to PartialVaccinationProvince[]

Make it easy for the DB to be merged with the other contact DBs.

Using VaccinationContact[] might force us into unnecessarily iterating the array just to merge it.

* refactor(fetcher): change vaksin.id output to an object

Using an object provide an easier iteration than PartialProvinceContact[].

PartialProvinceContact is also removed because it's now useless.

Refs: #806 issue comment 940051302

* chore: switch netlify export to yarn fetch-wbw

* feat(fetcher): log some info from  vaccination db

* feat(fetcher): log the output text of vaccine.db fetcher

* fix(fetcher): fix vaksinasi.id fetcher only fetching 4 provinces

* refactor(fetcher): remove console.log()s from vaccination fetcher
  • Loading branch information
togetherwithasteria committed Oct 26, 2021
1 parent 1487177 commit 93b1f76
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 1 deletion.
26 changes: 26 additions & 0 deletions etc/fetchers/__mocks__/vaksinid-locations-aceh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"data": [
{
"province": "Aceh",
"city": "Kota Banda Aceh",
"title": "UPTD PUSKESMAS KOPELMA DARUSSALAM",
"datestart": "2021-06-24",
"dateend": "2022-03-31",
"timestart": "08:00:00",
"timeend": "12:00:00",
"registration": "Walk-in",
"agerange": [
"Dewasa (18-59 Tahun)",
"Lansia (60-)"
],
"description": "-Senin dan Sabtu (bisa berubah sewaktu-waktu)\n-Dibeikan bagi warga dengan kriteria:\n1.petugas pelayanan publik\n2. Pra lansia &lansia\n3. Masyarakat Banda Aceh di utamakan yang berdomisili di wilayah Puskesmas Kopelma Darussalam,Rukoh,ie masen kayee adang,Lamgugob & Deah raya\n-Membawa KTP\n-informasi tambahan bisa dilihat di akun Instagram https://instagram.com/puskesmaskopelmadarussalam?utm_medium=copy_link",
"link": "https://www.instagram.com/p/CQgFAepnZkQ/?utm_medium=copy_link",
"address": "Jalan Inong Balee No.38 Darussalam Banda Aceh",
"map": "https://goo.gl/maps/9hViESZJ9rYwGypb9",
"isfree": true,
"isvalid": true,
"code": "",
"dateadded": "2021-07-30"
}
]
}
15 changes: 15 additions & 0 deletions etc/fetchers/__mocks__/vaksinid-regions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"data": [
{
"province": "Aceh",
"city": [
"Kota Banda Aceh",
"Kota Sabang",
"Kota Lhokseumawe",
"Kota Langsa",
"Kota Subulussalam",
"Kab. Aceh Selatan"
]
}
]
}
22 changes: 22 additions & 0 deletions etc/fetchers/__mocks__/wbw-vaccination-db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"Aceh": [
{
"alamat": "Jalan Inong Balee No.38 Darussalam Banda Aceh",
"lokasi": "Kota Banda Aceh",
"buka_waktu": "08:00:00",
"id": "0",
"informasi_2": "-Senin dan Sabtu (bisa berubah sewaktu-waktu)\n-Dibeikan bagi warga dengan kriteria:\n1.petugas pelayanan publik\n2. Pra lansia &lansia\n3. Masyarakat Banda Aceh di utamakan yang berdomisili di wilayah Puskesmas Kopelma Darussalam,Rukoh,ie masen kayee adang,Lamgugob & Deah raya\n-Membawa KTP\n-informasi tambahan bisa dilihat di akun Instagram https://instagram.com/puskesmaskopelmadarussalam?utm_medium=copy_link",
"keterangan": "Lokasi Vaksinasi COVID-19",
"link": "https://www.instagram.com/p/CQgFAepnZkQ/?utm_medium=copy_link",
"map": "https://goo.gl/maps/9hViESZJ9rYwGypb9",
"mulai_tanggal": "2021-06-24",
"penyedia": "UPTD PUSKESMAS KOPELMA DARUSSALAM",
"rentang_umur": ["Dewasa (18-59 Tahun)", "Lansia (60-)"],
"selesai_tanggal": "2022-03-31",
"slug": "uptd-puskesmas-kopelma-darussalam",
"terakhir_update": "2021-07-30",
"tutup_waktu": "12:00:00",
"verifikasi": 1
}
]
}
53 changes: 53 additions & 0 deletions etc/fetchers/__tests__/fetch-vaccination-database.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import fs from "fs";
import path from "path";
import fetchMock from "jest-fetch-mock";
import { fetchVaccinationDatabase } from "../fetch-vaccination-database";

describe("fetchVaksinasiDB", () => {
const writeFileSyncSpy = jest.spyOn(fs, "writeFileSync");

beforeEach(() => {
fetchMock.resetMocks();
writeFileSyncSpy.mockImplementation(() => {});
});

afterEach(() => {
writeFileSyncSpy.mockRestore();
});
it("fetches database from api.vaksinasi.id correctly", async () => {
const mockedResponses: { [url: string]: string } = {
"/regions": fs.readFileSync(
path.resolve(__dirname, "../__mocks__/vaksinid-regions.json"),
"utf-8",
),
"/locations/Aceh": fs.readFileSync(
path.resolve(__dirname, "../__mocks__/vaksinid-locations-aceh.json"),
"utf-8",
),
};

fetchMock.mockResponse(
async (req) =>
mockedResponses[new URL(req.url).pathname] ||
'{ "details":"Not Found" }',
);
await fetchVaccinationDatabase();

expect(fetchMock).toBeCalledTimes(2);

expect(fetchMock).toBeCalledWith("https://api.vaksinasi.id/regions");
expect(fetchMock).toHaveBeenCalledWith(
"https://api.vaksinasi.id/locations/Aceh",
);

expect(writeFileSyncSpy).toHaveBeenCalledTimes(1);
expect(JSON.parse(writeFileSyncSpy.mock.calls[0][1] as string)).toEqual(
JSON.parse(
fs.readFileSync(
path.resolve(__dirname, "../__mocks__/wbw-vaccination-db.json"),
"utf-8",
),
),
);
});
});
57 changes: 57 additions & 0 deletions etc/fetchers/fetch-vaccination-database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import fs from "fs";
import path from "path";
import fetch from "cross-fetch";
import {
VaccinationRegionsResponse,
VaccinationRegion,
VaccinationContact,
} from "../../lib/data/vaccination";
import { getKebabCase } from "../../lib/string-utils";

const vaksinId = "https://api.vaksinasi.id";

export async function fetchVaccinationDatabase() {
const regions = (await (
await fetch(`${vaksinId}/regions`)
).json()) as VaccinationRegionsResponse;

const locations: { [province: string]: VaccinationContact[] } = {};

const promisedLocations = [];
for (const { province } of regions.data) {
promisedLocations.push(
fetch(`${vaksinId}/locations/${province}`)
.then((res) => res.json() as unknown as VaccinationRegion)
.then((region) => {
locations[region.data[0].province] = region.data.map((location) => ({
id: `${region.data.findIndex(
(index) => location.title === index.title,
)}`,
keterangan: "Lokasi Vaksinasi COVID-19",
lokasi: location.city,
verifikasi: location.isvalid ? 1 : 0,
penyedia: location.title,
alamat: location.address,
slug: getKebabCase(location.title),
informasi_2: location.description,
terakhir_update: location.dateadded,
rentang_umur: location.agerange,
buka_waktu: location.timestart,
tutup_waktu: location.timeend,
mulai_tanggal: location.datestart,
selesai_tanggal: location.dateend,
link: location.link,
map: location.map,
}));
}),
);
}

await Promise.all(promisedLocations);

const text = JSON.stringify(locations);
fs.writeFileSync(
path.resolve(__dirname, "../../data/wbw-vaccination-database.json"),
text,
);
}
14 changes: 14 additions & 0 deletions etc/fetchers/fetch-wbw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,25 @@ import { toSecond } from "../../lib/string-utils";
import { fetchDatabase } from "./fetch-database";
import { fetchFaqSheets } from "./fetch-faq-sheets";
import { fetchSheets } from "./fetch-sheets";
import { fetchVaccinationDatabase } from "./fetch-vaccination-database";

(function fetchWbw() {
const start = process.hrtime();
const spinner = ora(`${chalk.yellowBright("Fetching all data...")}`).start();

fetchVaccinationDatabase()
.then(() => {
const end = `${toSecond(process.hrtime(start))} seconds`;
spinner.succeed(
`Fetching vaccination database (vaksinasi.id) done in ${chalk.greenBright(
end,
)}`,
);
})
.catch((err) => {
chalk.red(err);
});

fetchFaqSheets()
.then(() => {
const end = `${toSecond(process.hrtime(start))} seconds`;
Expand Down
53 changes: 53 additions & 0 deletions lib/data/vaccination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Contact } from "./provinces";

type City = `${"Kab." | "Kota"} ${string}`;
type DateString = `${number}-${number}-${number}`;
type TimeString = `${number}:${number}:${number}`;
type VaccinationAgeRange = Array<`${string} (${number}-${
| number
| null} Tahun)`>;

export interface VaccinationRegions {
province: string;
city: Array<City>;
}

export interface VaccinationRegionsResponse {
data: Array<VaccinationRegions>;
}
export interface VaccinationLocation {
province: string;
city: City;
title: string;
datestart: DateString;
dateend: DateString;
timestart: TimeString;
timeend: TimeString;
registration: string;
agerange: VaccinationAgeRange;
description: string;
link: string;
address: string;
map: string;
isFree: boolean;
isvalid: boolean;
code: string;
dateadded: DateString;
}

type _location = VaccinationLocation;
export interface VaccinationRegion {
data: Array<VaccinationLocation>;
}

export interface VaccinationContact extends Contact {
rentang_umur: _location["agerange"];
buka_waktu: _location["timestart"];
tutup_waktu: _location["timeend"];
mulai_tanggal: _location["datestart"];
selesai_tanggal: _location["dateend"];
kode?: _location["code"];
gratis?: _location["isFree"];
map: _location["map"];
link: _location["link"];
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"lint": "eslint \"**/*.{js,jsx,ts,tsx,yml,yaml}\"",
"lint:fix": "eslint --fix \"**/*.{js,jsx,ts,tsx,yml,yaml}\"",
"mirror-box": "ts-node etc/mirror-box.ts",
"netlify-export": "yarn mirror-box && yarn build && next export",
"netlify-export": "yarn fetch-wbw && yarn build && next export",
"prepare": "husky install",
"start": "next start",
"cypress:open": "cypress open",
Expand Down

0 comments on commit 93b1f76

Please sign in to comment.