refactor: ♻️ Rewrite relationship system

This commit is contained in:
Jesse Wierzbinski 2024-07-27 20:46:19 +02:00
parent 62b68a64ac
commit 3baac85cf7
No known key found for this signature in database
23 changed files with 2634 additions and 596 deletions

View file

@ -1,96 +0,0 @@
import type { Relationship as ApiRelationship } from "@lysand-org/client/types";
import type { InferSelectModel } from "drizzle-orm";
import { db } from "~/drizzle/db";
import { Relationships } from "~/drizzle/schema";
import type { User } from "~/packages/database-interface/user";
export type Relationship = InferSelectModel<typeof Relationships> & {
requestedBy: boolean;
};
/**
* Creates a new relationship between two users.
* @param owner The user who owns the relationship.
* @param other The user who is the subject of the relationship.
* @returns The newly created relationship.
*/
export const createNewRelationship = async (
owner: User,
other: User,
): Promise<Relationship> => {
return {
...(
await db
.insert(Relationships)
.values({
ownerId: owner.id,
subjectId: other.id,
languages: [],
following: false,
showingReblogs: false,
notifying: false,
followedBy: false,
blocking: false,
blockedBy: false,
muting: false,
mutingNotifications: false,
requested: false,
domainBlocking: false,
endorsed: false,
note: "",
updatedAt: new Date().toISOString(),
})
.returning()
)[0],
requestedBy: false,
};
};
export const checkForBidirectionalRelationships = async (
user1: User,
user2: User,
createIfNotExists = true,
): Promise<boolean> => {
const relationship1 = await db.query.Relationships.findFirst({
where: (rel, { and, eq }) =>
and(eq(rel.ownerId, user1.id), eq(rel.subjectId, user2.id)),
});
const relationship2 = await db.query.Relationships.findFirst({
where: (rel, { and, eq }) =>
and(eq(rel.ownerId, user2.id), eq(rel.subjectId, user1.id)),
});
if (!relationship1 && createIfNotExists) {
await createNewRelationship(user1, user2);
}
if (!relationship2 && createIfNotExists) {
await createNewRelationship(user2, user1);
}
return !!relationship1 && !!relationship2;
};
/**
* Converts the relationship to an API-friendly format.
* @returns The API-friendly relationship.
*/
export const relationshipToApi = (rel: Relationship): ApiRelationship => {
return {
blocked_by: rel.blockedBy,
blocking: rel.blocking,
domain_blocking: rel.domainBlocking,
endorsed: rel.endorsed,
followed_by: rel.followedBy,
following: rel.following,
id: rel.subjectId,
muting: rel.muting,
muting_notifications: rel.mutingNotifications,
notifying: rel.notifying,
requested: rel.requested,
requested_by: rel.requestedBy,
showing_reblogs: rel.showingReblogs,
note: rel.note,
};
};

View file

@ -4,13 +4,11 @@ import type {
FollowReject,
} from "@lysand-org/federation/types";
import { config } from "config-manager";
import { type InferSelectModel, and, eq, sql } from "drizzle-orm";
import { type InferSelectModel, eq, sql } from "drizzle-orm";
import { db } from "~/drizzle/db";
import {
Applications,
type Instances,
Notifications,
Relationships,
type Roles,
Tokens,
type Users,
@ -18,11 +16,6 @@ import {
import type { EmojiWithInstance } from "~/packages/database-interface/emoji";
import { User } from "~/packages/database-interface/user";
import type { Application } from "./application";
import {
type Relationship,
checkForBidirectionalRelationships,
createNewRelationship,
} from "./relationship";
import type { Token } from "./token";
export type UserType = InferSelectModel<typeof Users>;
@ -119,85 +112,6 @@ export const getFromHeader = async (value: string): Promise<AuthData> => {
return { user, token, application };
};
export const followRequestUser = async (
follower: User,
followee: User,
relationshipId: string,
reblogs = false,
notify = false,
languages: string[] = [],
): Promise<Relationship> => {
const isRemote = followee.isRemote();
await db
.update(Relationships)
.set({
following: isRemote ? false : !followee.data.isLocked,
requested: isRemote ? true : followee.data.isLocked,
showingReblogs: reblogs,
notifying: notify,
languages: languages,
})
.where(eq(Relationships.id, relationshipId));
// Set requested_by on other side
await db
.update(Relationships)
.set({
requestedBy: isRemote ? true : followee.data.isLocked,
followedBy: isRemote ? false : followee.data.isLocked,
})
.where(
and(
eq(Relationships.ownerId, followee.id),
eq(Relationships.subjectId, follower.id),
),
);
const updatedRelationship = await db.query.Relationships.findFirst({
where: (rel, { eq }) => eq(rel.id, relationshipId),
});
if (!updatedRelationship) {
throw new Error("Failed to update relationship");
}
if (isRemote) {
const { ok } = await follower.federateToUser(
followRequestToLysand(follower, followee),
followee,
);
if (!ok) {
await db
.update(Relationships)
.set({
following: false,
requested: false,
})
.where(eq(Relationships.id, relationshipId));
const result = await db.query.Relationships.findFirst({
where: (rel, { eq }) => eq(rel.id, relationshipId),
});
if (!result) {
throw new Error("Failed to update relationship");
}
return result;
}
} else {
await db.insert(Notifications).values({
accountId: follower.id,
type: followee.data.isLocked ? "follow_request" : "follow",
notifiedId: followee.id,
});
}
return updatedRelationship;
};
export const sendFollowAccept = async (follower: User, followee: User) => {
await follower.federateToUser(
followAcceptToLysand(follower, followee),
@ -344,36 +258,6 @@ export const retrieveToken = async (
);
};
/**
* Gets the relationship to another user.
* @param other The other user to get the relationship to.
* @returns The relationship to the other user.
*/
export const getRelationshipToOtherUser = async (
user: User,
other: User,
): Promise<Relationship> => {
await checkForBidirectionalRelationships(user, other);
const foundRelationship = await db.query.Relationships.findFirst({
where: (relationship, { and, eq }) =>
and(
eq(relationship.ownerId, user.id),
eq(relationship.subjectId, other.id),
),
});
if (!foundRelationship) {
// Create new relationship
const newRelationship = await createNewRelationship(user, other);
return newRelationship;
}
return foundRelationship;
};
export const followRequestToLysand = (
follower: User,
followee: User,