feat: query Vervis for information on a person
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 <andre.jaenisch@posteo.de>
This commit is contained in:
parent
bafd831696
commit
311e5123e7
6 changed files with 118 additions and 6 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,3 +18,4 @@ storybook-static
|
||||||
|
|
||||||
# See https://tauri.app/v1/guides/development/development-cycle#2-start-tauri-development-window
|
# See https://tauri.app/v1/guides/development/development-cycle#2-start-tauri-development-window
|
||||||
src-tauri/target
|
src-tauri/target
|
||||||
|
account.json
|
||||||
|
|
|
@ -96,6 +96,24 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
<div>
|
||||||
|
<p>The following is DEBUG information and will be removed in the near future.</p>
|
||||||
|
{#if data?.user}
|
||||||
|
<div>
|
||||||
|
<b>Person</b>
|
||||||
|
<pre>{JSON.stringify(data.user.person, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Followings</b>
|
||||||
|
<pre>{JSON.stringify(data.user.followings, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Followings mapped</b>
|
||||||
|
<p>These are the contents of the items in the previous dump.</p>
|
||||||
|
<pre>{JSON.stringify(data.user.followingsMap, null, 2)}</pre>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- History -->
|
<!-- History -->
|
||||||
|
|
|
@ -32,7 +32,7 @@ export async function getHomepage({ account, passphrase, server }) {
|
||||||
|
|
||||||
if (loggedInResponse.status === 200) {
|
if (loggedInResponse.status === 200) {
|
||||||
const headers = new AxiosHeaders();
|
const headers = new AxiosHeaders();
|
||||||
headers.set({ Cookie: loggedInResponse.headers['set-cookie'].join(';') });
|
headers.set({ Cookie: getCookie(loggedInResponse) });
|
||||||
|
|
||||||
const response = await loginFormData.instance.get('/', {
|
const response = await loginFormData.instance.get('/', {
|
||||||
headers
|
headers
|
||||||
|
@ -45,6 +45,15 @@ export async function getHomepage({ account, passphrase, server }) {
|
||||||
const tickets = [];
|
const tickets = [];
|
||||||
|
|
||||||
const dom = cheerio.load(response.data);
|
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")) {
|
if (dom('h2:contains("Your teams") + p').text().includes("aren't a member")) {
|
||||||
console.log('No teams');
|
console.log('No teams');
|
||||||
}
|
}
|
||||||
|
@ -72,7 +81,10 @@ export async function getHomepage({ account, passphrase, server }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cookies: response.headers['set-cookie'].join(';'),
|
cookies: getCookie(t[t.length - 1]),
|
||||||
|
followings,
|
||||||
|
followingsMap,
|
||||||
|
person,
|
||||||
patches,
|
patches,
|
||||||
projects,
|
projects,
|
||||||
repos,
|
repos,
|
||||||
|
@ -85,3 +97,67 @@ export async function getHomepage({ account, passphrase, server }) {
|
||||||
|
|
||||||
return null;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -59,5 +59,3 @@ export async function postRemoteLogin({ username, password, loginFormData }) {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { writeFile } from 'node:fs/promises';
|
||||||
|
|
||||||
import { fail, redirect } from '@sveltejs/kit';
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
|
|
||||||
import { requests } from '$lib/server/ap/index.js';
|
import { requests } from '$lib/server/ap/index.js';
|
||||||
|
@ -31,8 +33,12 @@ export const actions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await requests.post('/login', { account, passphrase, server });
|
const response = await requests.post('/login', {
|
||||||
console.log('DEBUG', response);
|
account,
|
||||||
|
passphrase,
|
||||||
|
server
|
||||||
|
});
|
||||||
|
await writeFile('account.json', JSON.stringify(response));
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
console.error(exc);
|
console.error(exc);
|
||||||
return fail(400, { account, incorrect: true });
|
return fail(400, { account, incorrect: true });
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
|
||||||
import { requests } from '$lib/server/ap/index.js';
|
import { requests } from '$lib/server/ap/index.js';
|
||||||
|
|
||||||
/** @type {import('./$types').PageServerLoad} */
|
/** @type {import('./$types').PageServerLoad} */
|
||||||
export async function load({ params }) {
|
export async function load({ params }) {
|
||||||
const profile = await requests.get('/profile');
|
const profile = await requests.get('/profile');
|
||||||
|
const account = await readAccountData();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
server: {
|
server: {
|
||||||
|
@ -22,9 +24,20 @@ export async function load({ params }) {
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
...profile,
|
...profile,
|
||||||
|
...account,
|
||||||
created_at: new Date(profile.created_at),
|
created_at: new Date(profile.created_at),
|
||||||
created_with: 'Anvil',
|
created_with: 'Anvil',
|
||||||
instance: 'example.com'
|
instance: 'example.com'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function readAccountData() {
|
||||||
|
try {
|
||||||
|
const account = await readFile('account.json', 'utf8');
|
||||||
|
return JSON.parse(account);
|
||||||
|
} catch (exc) {
|
||||||
|
console.error(exc);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue