From 311e5123e77b3f330f09c825d4145dcaed717581 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Jaenisch?=
Date: Fri, 14 Jun 2024 20:53:32 +0200
Subject: [PATCH] feat: query Vervis for information on a person
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
I discovered that Vervis understands Content Negotiation.
That is, once I figure out my peopleId I can navigate to the respective
paths and resceive JSON that is equal to the prettyjson'ed HTML views I
can see in the web browser.
I don't find everything I would like to have. Therefore I'm writing the
results to a file for now and read it in the profile so I can talk to
our designer how to move on with what we have right now.
Signed-off-by: André Jaenisch
---
.gitignore | 1 +
src/lib/components/templates/Profile.svelte | 18 +++++
src/lib/server/ap/homepage.js | 80 ++++++++++++++++++++-
src/lib/server/ap/login.js | 2 -
src/routes/account/login/+page.server.js | 10 ++-
src/routes/profile/+page.server.js | 13 ++++
6 files changed, 118 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index 21e162a..26220c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ storybook-static
# See https://tauri.app/v1/guides/development/development-cycle#2-start-tauri-development-window
src-tauri/target
+account.json
diff --git a/src/lib/components/templates/Profile.svelte b/src/lib/components/templates/Profile.svelte
index 5657f09..b0c4daf 100644
--- a/src/lib/components/templates/Profile.svelte
+++ b/src/lib/components/templates/Profile.svelte
@@ -96,6 +96,24 @@ You should have received a copy of the GNU Affero General Public License along w
}
})}
+
+
The following is DEBUG information and will be removed in the near future.
+ {#if data?.user}
+
+
Person
+
{JSON.stringify(data.user.person, null, 2)}
+
+
+
Followings
+
{JSON.stringify(data.user.followings, null, 2)}
+
+
+
Followings mapped
+
These are the contents of the items in the previous dump.
+
{JSON.stringify(data.user.followingsMap, null, 2)}
+
+ {/if}
+
diff --git a/src/lib/server/ap/homepage.js b/src/lib/server/ap/homepage.js
index 75ad395..c17a78a 100644
--- a/src/lib/server/ap/homepage.js
+++ b/src/lib/server/ap/homepage.js
@@ -32,7 +32,7 @@ export async function getHomepage({ account, passphrase, server }) {
if (loggedInResponse.status === 200) {
const headers = new AxiosHeaders();
- headers.set({ Cookie: loggedInResponse.headers['set-cookie'].join(';') });
+ headers.set({ Cookie: getCookie(loggedInResponse) });
const response = await loginFormData.instance.get('/', {
headers
@@ -45,6 +45,15 @@ export async function getHomepage({ account, passphrase, server }) {
const tickets = [];
const dom = cheerio.load(response.data);
+ const inbox = getInboxLinkFromResponse(response);
+ const peopleId = getPeopleIdFromInboxLink(inbox);
+ const r = await fetchPersonData(loginFormData, getCookie(response), peopleId);
+ const person = getPersonFromResponse(r);
+ const s = await fetchFollowings(loginFormData, getCookie(r), person);
+ const followings = getFollowingsFromResponse(s);
+ const t = await fetchFollowingsMap(loginFormData, getCookie(s), followings);
+ const followingsMap = getFollowingsMapFromRsponses(t);
+
if (dom('h2:contains("Your teams") + p').text().includes("aren't a member")) {
console.log('No teams');
}
@@ -72,7 +81,10 @@ export async function getHomepage({ account, passphrase, server }) {
}
return {
- cookies: response.headers['set-cookie'].join(';'),
+ cookies: getCookie(t[t.length - 1]),
+ followings,
+ followingsMap,
+ person,
patches,
projects,
repos,
@@ -85,3 +97,67 @@ export async function getHomepage({ account, passphrase, server }) {
return null;
}
+
+function getCookie(lastResponse) {
+ return lastResponse.headers['set-cookie'].join(';');
+}
+
+function getInboxLinkFromResponse(response) {
+ const dom = cheerio.load(response.data);
+ // Since the PeopleID is not marked up anywhere on the homepage,
+ // I pick the first link I know that it contains it.
+ // If there was a /me endpoint or something that would help
+ return dom('header span + span + span a').attr('href');
+}
+
+function getPersonFromResponse(response) {
+ return response.data;
+}
+
+function getFollowingsFromResponse(response) {
+ return response.data;
+}
+
+function getFollowingsMapFromRsponses(responses) {
+ return responses.map((response) => response.data);
+}
+
+function getPeopleIdFromInboxLink(inboxLink) {
+ // The id is part of the pathname as /people/:peopleId/inbox
+ const url = new URL(inboxLink);
+ const parts = url.pathname.split('/');
+ return parts[2];
+}
+
+async function fetchPersonData(loginFormData, cookie, peopleId) {
+ const headers = new AxiosHeaders();
+ headers.set({ Cookie: cookie });
+
+ const response = await loginFormData.instance.get(`/people/${peopleId}`, {
+ headers
+ });
+
+ return response;
+}
+
+async function fetchFollowings(loginFormData, cookie, person) {
+ const headers = new AxiosHeaders();
+ headers.set({ Cookie: cookie });
+ const { pathname } = new URL(person.following);
+
+ const response = await loginFormData.instance.get(pathname, { headers });
+
+ return response;
+}
+
+async function fetchFollowingsMap(loginFormData, cookie, followings) {
+ const headers = new AxiosHeaders();
+ headers.set({ Cookie: cookie });
+
+ const mappedFollowings = followings.items.map((following) => {
+ const { pathname } = new URL(following);
+ return loginFormData.instance.get(pathname, { headers });
+ });
+
+ return Promise.all(mappedFollowings);
+}
diff --git a/src/lib/server/ap/login.js b/src/lib/server/ap/login.js
index 423c8b9..3d80efc 100644
--- a/src/lib/server/ap/login.js
+++ b/src/lib/server/ap/login.js
@@ -59,5 +59,3 @@ export async function postRemoteLogin({ username, password, loginFormData }) {
data
});
}
-
-
diff --git a/src/routes/account/login/+page.server.js b/src/routes/account/login/+page.server.js
index 2031123..53f9772 100644
--- a/src/routes/account/login/+page.server.js
+++ b/src/routes/account/login/+page.server.js
@@ -10,6 +10,8 @@
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
*/
+import { writeFile } from 'node:fs/promises';
+
import { fail, redirect } from '@sveltejs/kit';
import { requests } from '$lib/server/ap/index.js';
@@ -31,8 +33,12 @@ export const actions = {
}
try {
- const response = await requests.post('/login', { account, passphrase, server });
- console.log('DEBUG', response);
+ const response = await requests.post('/login', {
+ account,
+ passphrase,
+ server
+ });
+ await writeFile('account.json', JSON.stringify(response));
} catch (exc) {
console.error(exc);
return fail(400, { account, incorrect: true });
diff --git a/src/routes/profile/+page.server.js b/src/routes/profile/+page.server.js
index 77d3df2..9691176 100644
--- a/src/routes/profile/+page.server.js
+++ b/src/routes/profile/+page.server.js
@@ -9,12 +9,14 @@
*
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
*/
+import { readFile } from 'node:fs/promises';
import { requests } from '$lib/server/ap/index.js';
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const profile = await requests.get('/profile');
+ const account = await readAccountData();
return {
server: {
@@ -22,9 +24,20 @@ export async function load({ params }) {
},
user: {
...profile,
+ ...account,
created_at: new Date(profile.created_at),
created_with: 'Anvil',
instance: 'example.com'
}
};
}
+
+async function readAccountData() {
+ try {
+ const account = await readFile('account.json', 'utf8');
+ return JSON.parse(account);
+ } catch (exc) {
+ console.error(exc);
+ return {};
+ }
+}