mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 22:09:16 +01:00
refactor: ♻️ Rewrite relationship system
This commit is contained in:
parent
62b68a64ac
commit
3baac85cf7
23 changed files with 2634 additions and 596 deletions
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue