mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 16:38:19 +01:00
refactor: ♻️ Rewrite relationship system
This commit is contained in:
parent
62b68a64ac
commit
3baac85cf7
|
|
@ -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,
|
||||
|
|
|
|||
3
drizzle/migrations/0031_mature_demogoblin.sql
Normal file
3
drizzle/migrations/0031_mature_demogoblin.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "Relationships" DROP COLUMN IF EXISTS "followed_by";--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" DROP COLUMN IF EXISTS "blocked_by";--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" DROP COLUMN IF EXISTS "requested_by";
|
||||
2126
drizzle/migrations/meta/0031_snapshot.json
Normal file
2126
drizzle/migrations/meta/0031_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -218,6 +218,13 @@
|
|||
"when": 1721223331975,
|
||||
"tag": "0030_curvy_vulture",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 31,
|
||||
"version": "7",
|
||||
"when": 1722100203904,
|
||||
"tag": "0031_mature_demogoblin",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,13 +181,10 @@ export const Relationships = pgTable("Relationships", {
|
|||
following: boolean("following").notNull(),
|
||||
showingReblogs: boolean("showing_reblogs").notNull(),
|
||||
notifying: boolean("notifying").notNull(),
|
||||
followedBy: boolean("followed_by").notNull(),
|
||||
blocking: boolean("blocking").notNull(),
|
||||
blockedBy: boolean("blocked_by").notNull(),
|
||||
muting: boolean("muting").notNull(),
|
||||
mutingNotifications: boolean("muting_notifications").notNull(),
|
||||
requested: boolean("requested").notNull(),
|
||||
requestedBy: boolean("requested_by").notNull().default(false),
|
||||
domainBlocking: boolean("domain_blocking").notNull(),
|
||||
endorsed: boolean("endorsed").notNull(),
|
||||
languages: text("languages").array(),
|
||||
|
|
|
|||
295
packages/database-interface/relationship.ts
Normal file
295
packages/database-interface/relationship.ts
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
import type { Relationship as APIRelationship } from "@lysand-org/client/types";
|
||||
import {
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
type SQL,
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
inArray,
|
||||
} from "drizzle-orm";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships } from "~/drizzle/schema";
|
||||
import { BaseInterface } from "./base";
|
||||
import type { User } from "./user";
|
||||
|
||||
export type RelationshipType = InferSelectModel<typeof Relationships>;
|
||||
|
||||
export type RelationshipWithOpposite = RelationshipType & {
|
||||
followedBy: boolean;
|
||||
blockedBy: boolean;
|
||||
requestedBy: boolean;
|
||||
};
|
||||
|
||||
export class Relationship extends BaseInterface<
|
||||
typeof Relationships,
|
||||
RelationshipWithOpposite
|
||||
> {
|
||||
async reload(): Promise<void> {
|
||||
const reloaded = await Relationship.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload relationship");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(
|
||||
id: string | null,
|
||||
): Promise<Relationship | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Relationship.fromSql(eq(Relationships.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Relationship[]> {
|
||||
return await Relationship.manyFromSql(inArray(Relationships.id, ids));
|
||||
}
|
||||
|
||||
public static async fromOwnerAndSubject(
|
||||
owner: User,
|
||||
subject: User,
|
||||
): Promise<Relationship> {
|
||||
const found = await Relationship.fromSql(
|
||||
and(
|
||||
eq(Relationships.ownerId, owner.id),
|
||||
eq(Relationships.subjectId, subject.id),
|
||||
),
|
||||
);
|
||||
|
||||
if (!found) {
|
||||
// Create a new relationship if one doesn't exist
|
||||
return await Relationship.insert({
|
||||
ownerId: owner.id,
|
||||
subjectId: subject.id,
|
||||
languages: [],
|
||||
following: false,
|
||||
showingReblogs: false,
|
||||
notifying: false,
|
||||
blocking: false,
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
requested: false,
|
||||
domainBlocking: false,
|
||||
endorsed: false,
|
||||
note: "",
|
||||
});
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
public static async fromOwnerAndSubjects(
|
||||
owner: User,
|
||||
subjectIds: string[],
|
||||
): Promise<Relationship[]> {
|
||||
const found = await Relationship.manyFromSql(
|
||||
and(
|
||||
eq(Relationships.ownerId, owner.id),
|
||||
inArray(Relationships.subjectId, subjectIds),
|
||||
),
|
||||
);
|
||||
|
||||
const missingSubjectsIds = subjectIds.filter(
|
||||
(id) => !found.find((rel) => rel.data.subjectId === id),
|
||||
);
|
||||
|
||||
for (const subjectId of missingSubjectsIds) {
|
||||
await Relationship.insert({
|
||||
ownerId: owner.id,
|
||||
subjectId: subjectId,
|
||||
languages: [],
|
||||
following: false,
|
||||
showingReblogs: false,
|
||||
notifying: false,
|
||||
blocking: false,
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
requested: false,
|
||||
domainBlocking: false,
|
||||
endorsed: false,
|
||||
note: "",
|
||||
});
|
||||
}
|
||||
|
||||
return await Relationship.manyFromSql(
|
||||
and(
|
||||
eq(Relationships.ownerId, owner.id),
|
||||
inArray(Relationships.subjectId, subjectIds),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Relationships.id),
|
||||
): Promise<Relationship | null> {
|
||||
const found = await db.query.Relationships.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const opposite = await Relationship.getOpposite(found);
|
||||
|
||||
return new Relationship({
|
||||
...found,
|
||||
followedBy: opposite.following,
|
||||
blockedBy: opposite.blocking,
|
||||
requestedBy: opposite.requested,
|
||||
});
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Relationships.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Relationships.findMany>[0],
|
||||
): Promise<Relationship[]> {
|
||||
const found = await db.query.Relationships.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
const opposites = await Promise.all(
|
||||
found.map((rel) => Relationship.getOpposite(rel)),
|
||||
);
|
||||
|
||||
return found.map((s, i) => {
|
||||
return new Relationship({
|
||||
...s,
|
||||
followedBy: opposites[i].following,
|
||||
blockedBy: opposites[i].blocking,
|
||||
requestedBy: opposites[i].requested,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static async getOpposite(oppositeTo: {
|
||||
subjectId: string;
|
||||
ownerId: string;
|
||||
}): Promise<RelationshipType> {
|
||||
let output = await db.query.Relationships.findFirst({
|
||||
where: (rel, { and, eq }) =>
|
||||
and(
|
||||
eq(rel.ownerId, oppositeTo.subjectId),
|
||||
eq(rel.subjectId, oppositeTo.ownerId),
|
||||
),
|
||||
});
|
||||
|
||||
// If the opposite relationship doesn't exist, create it
|
||||
if (!output) {
|
||||
output = (
|
||||
await db
|
||||
.insert(Relationships)
|
||||
.values({
|
||||
ownerId: oppositeTo.subjectId,
|
||||
subjectId: oppositeTo.ownerId,
|
||||
languages: [],
|
||||
following: false,
|
||||
showingReblogs: false,
|
||||
notifying: false,
|
||||
blocking: false,
|
||||
domainBlocking: false,
|
||||
endorsed: false,
|
||||
note: "",
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
requested: false,
|
||||
})
|
||||
.returning()
|
||||
)[0];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
async update(
|
||||
newRelationship: Partial<RelationshipType>,
|
||||
): Promise<RelationshipWithOpposite> {
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set(newRelationship)
|
||||
.where(eq(Relationships.id, this.id));
|
||||
|
||||
const updated = await Relationship.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update relationship");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
save(): Promise<RelationshipWithOpposite> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
async delete(ids: string[]): Promise<void>;
|
||||
async delete(): Promise<void>;
|
||||
async delete(ids?: unknown): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db
|
||||
.delete(Relationships)
|
||||
.where(inArray(Relationships.id, ids));
|
||||
} else {
|
||||
await db.delete(Relationships).where(eq(Relationships.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Relationships>,
|
||||
): Promise<Relationship> {
|
||||
const inserted = (
|
||||
await db.insert(Relationships).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const relationship = await Relationship.fromId(inserted.id);
|
||||
|
||||
if (!relationship) {
|
||||
throw new Error("Failed to insert relationship");
|
||||
}
|
||||
|
||||
// Create opposite relationship if necessary
|
||||
await Relationship.getOpposite({
|
||||
subjectId: relationship.data.subjectId,
|
||||
ownerId: relationship.data.ownerId,
|
||||
});
|
||||
|
||||
return relationship;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public toApi(): APIRelationship {
|
||||
return {
|
||||
id: this.data.subjectId,
|
||||
blocked_by: this.data.blockedBy,
|
||||
blocking: this.data.blocking,
|
||||
domain_blocking: this.data.domainBlocking,
|
||||
endorsed: this.data.endorsed,
|
||||
followed_by: this.data.followedBy,
|
||||
following: this.data.following,
|
||||
muting_notifications: this.data.mutingNotifications,
|
||||
muting: this.data.muting,
|
||||
note: this.data.note,
|
||||
notifying: this.data.notifying,
|
||||
requested_by: this.data.requestedBy,
|
||||
requested: this.data.requested,
|
||||
showing_reblogs: this.data.showingReblogs,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ import { htmlToText } from "html-to-text";
|
|||
import {
|
||||
type UserWithRelations,
|
||||
findManyUsers,
|
||||
followRequestToLysand,
|
||||
} from "~/classes/functions/user";
|
||||
import { searchManager } from "~/classes/search/search-manager";
|
||||
import { db } from "~/drizzle/db";
|
||||
|
|
@ -41,6 +42,7 @@ import {
|
|||
EmojiToUser,
|
||||
NoteToMentions,
|
||||
Notes,
|
||||
Notifications,
|
||||
type RolePermissions,
|
||||
UserToPinnedNotes,
|
||||
Users,
|
||||
|
|
@ -50,6 +52,7 @@ import { BaseInterface } from "./base";
|
|||
import { Emoji } from "./emoji";
|
||||
import { Instance } from "./instance";
|
||||
import type { Note } from "./note";
|
||||
import { Relationship } from "./relationship";
|
||||
import { Role } from "./role";
|
||||
|
||||
/**
|
||||
|
|
@ -205,6 +208,52 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
|
|||
);
|
||||
}
|
||||
|
||||
public async followRequest(
|
||||
otherUser: User,
|
||||
options?: {
|
||||
reblogs?: boolean;
|
||||
notify?: boolean;
|
||||
languages?: string[];
|
||||
},
|
||||
): Promise<Relationship> {
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
this,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
await foundRelationship.update({
|
||||
following: otherUser.isRemote() ? false : !otherUser.data.isLocked,
|
||||
requested: otherUser.isRemote() ? true : otherUser.data.isLocked,
|
||||
showingReblogs: options?.reblogs,
|
||||
notifying: options?.notify,
|
||||
languages: options?.languages,
|
||||
});
|
||||
|
||||
if (otherUser.isRemote()) {
|
||||
const { ok } = await this.federateToUser(
|
||||
followRequestToLysand(this, otherUser),
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!ok) {
|
||||
await foundRelationship.update({
|
||||
requested: false,
|
||||
following: false,
|
||||
});
|
||||
|
||||
return foundRelationship;
|
||||
}
|
||||
} else {
|
||||
await db.insert(Notifications).values({
|
||||
accountId: this.id,
|
||||
type: otherUser.data.isLocked ? "follow_request" : "follow",
|
||||
notifiedId: otherUser.id,
|
||||
});
|
||||
}
|
||||
|
||||
return foundRelationship;
|
||||
}
|
||||
|
||||
static async webFinger(
|
||||
manager: FederationRequester,
|
||||
username: string,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,22 +52,17 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!foundRelationship.blocking) {
|
||||
foundRelationship.blocking = true;
|
||||
if (!foundRelationship.data.blocking) {
|
||||
await foundRelationship.update({
|
||||
blocking: true,
|
||||
});
|
||||
}
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
blocking: true,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,12 +4,8 @@ import type { Hono } from "@hono/hono";
|
|||
import { zValidator } from "@hono/zod-validator";
|
||||
import ISO6391 from "iso-639-1";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import {
|
||||
followRequestUser,
|
||||
getRelationshipToOtherUser,
|
||||
} from "~/classes/functions/user";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -69,22 +65,19 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
let relationship = await getRelationshipToOtherUser(
|
||||
let relationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!relationship.following) {
|
||||
relationship = await followRequestUser(
|
||||
user,
|
||||
otherUser,
|
||||
relationship.id,
|
||||
if (!relationship.data.following) {
|
||||
relationship = await user.followRequest(otherUser, {
|
||||
reblogs,
|
||||
notify,
|
||||
languages,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(relationship));
|
||||
return jsonResponse(relationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -67,28 +64,17 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!foundRelationship.muting) {
|
||||
foundRelationship.muting = true;
|
||||
}
|
||||
if (notifications ?? true) {
|
||||
foundRelationship.mutingNotifications = true;
|
||||
}
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
muting: true,
|
||||
mutingNotifications: notifications ?? true,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
// TODO: Implement duration
|
||||
await foundRelationship.update({
|
||||
muting: true,
|
||||
mutingNotifications: notifications ?? true,
|
||||
});
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -60,20 +57,15 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
foundRelationship.note = comment ?? "";
|
||||
await foundRelationship.update({
|
||||
note: comment,
|
||||
});
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
note: foundRelationship.note,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,22 +52,15 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!foundRelationship.endorsed) {
|
||||
foundRelationship.endorsed = true;
|
||||
}
|
||||
await foundRelationship.update({
|
||||
endorsed: true,
|
||||
});
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
endorsed: true,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,36 +52,22 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const oppositeRelationship = await Relationship.fromOwnerAndSubject(
|
||||
otherUser,
|
||||
self,
|
||||
);
|
||||
|
||||
if (oppositeRelationship.data.following) {
|
||||
await oppositeRelationship.update({
|
||||
following: false,
|
||||
});
|
||||
}
|
||||
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
self,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (foundRelationship.followedBy) {
|
||||
foundRelationship.followedBy = false;
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
followedBy: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
if (otherUser.isLocal()) {
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
following: false,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.ownerId, otherUser.id),
|
||||
eq(Relationships.subjectId, self.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,22 +52,17 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (foundRelationship.blocking) {
|
||||
foundRelationship.blocking = false;
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
blocking: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
if (foundRelationship.data.blocking) {
|
||||
await foundRelationship.update({
|
||||
blocking: false,
|
||||
});
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,23 +52,17 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
self,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (foundRelationship.following) {
|
||||
foundRelationship.following = false;
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
following: false,
|
||||
requested: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
if (foundRelationship.data.following) {
|
||||
await foundRelationship.update({
|
||||
following: false,
|
||||
});
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,24 +52,18 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
self,
|
||||
user,
|
||||
);
|
||||
|
||||
if (foundRelationship.muting) {
|
||||
foundRelationship.muting = false;
|
||||
foundRelationship.mutingNotifications = false;
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
if (foundRelationship.data.muting) {
|
||||
await foundRelationship.update({
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
});
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { relationshipToApi } from "~/classes/functions/relationship";
|
||||
import { getRelationshipToOtherUser } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -55,22 +52,17 @@ export default (app: Hono) =>
|
|||
return errorResponse("User not found", 404);
|
||||
}
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
self,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (foundRelationship.endorsed) {
|
||||
foundRelationship.endorsed = false;
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
endorsed: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
if (foundRelationship.data.endorsed) {
|
||||
await foundRelationship.update({
|
||||
endorsed: false,
|
||||
});
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ describe(meta.route, () => {
|
|||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
following: false,
|
||||
followed_by: true,
|
||||
followed_by: false,
|
||||
blocking: false,
|
||||
muting: false,
|
||||
muting_notifications: false,
|
||||
|
|
|
|||
|
|
@ -3,13 +3,8 @@ import { errorResponse, jsonResponse } from "@/response";
|
|||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
createNewRelationship,
|
||||
relationshipToApi,
|
||||
} from "~/classes/functions/relationship";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
|
||||
export const meta = applyConfig({
|
||||
allowedMethods: ["GET"],
|
||||
|
|
@ -50,32 +45,17 @@ export default (app: Hono) =>
|
|||
return errorResponse("Unauthorized", 401);
|
||||
}
|
||||
|
||||
const relationships = await db.query.Relationships.findMany({
|
||||
where: (relationship, { inArray, and, eq }) =>
|
||||
and(
|
||||
inArray(relationship.subjectId, ids),
|
||||
eq(relationship.ownerId, self.id),
|
||||
),
|
||||
});
|
||||
|
||||
const missingIds = ids.filter(
|
||||
(id) => !relationships.some((r) => r.subjectId === id),
|
||||
const relationships = await Relationship.fromOwnerAndSubjects(
|
||||
self,
|
||||
ids,
|
||||
);
|
||||
|
||||
for (const id of missingIds) {
|
||||
const user = await User.fromId(id);
|
||||
if (!user) {
|
||||
continue;
|
||||
}
|
||||
const relationship = await createNewRelationship(self, user);
|
||||
|
||||
relationships.push(relationship);
|
||||
}
|
||||
|
||||
relationships.sort(
|
||||
(a, b) => ids.indexOf(a.subjectId) - ids.indexOf(b.subjectId),
|
||||
(a, b) =>
|
||||
ids.indexOf(a.data.subjectId) -
|
||||
ids.indexOf(b.data.subjectId),
|
||||
);
|
||||
|
||||
return jsonResponse(relationships.map((r) => relationshipToApi(r)));
|
||||
return jsonResponse(relationships.map((r) => r.toApi()));
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,18 +2,10 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
checkForBidirectionalRelationships,
|
||||
relationshipToApi,
|
||||
} from "~/classes/functions/relationship";
|
||||
import {
|
||||
getRelationshipToOtherUser,
|
||||
sendFollowAccept,
|
||||
} from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { sendFollowAccept } from "~/classes/functions/user";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -58,52 +50,27 @@ export default (app: Hono) =>
|
|||
return errorResponse("Account not found", 404);
|
||||
}
|
||||
|
||||
// Check if there is a relationship on both sides
|
||||
await checkForBidirectionalRelationships(user, account);
|
||||
const oppositeRelationship = await Relationship.fromOwnerAndSubject(
|
||||
account,
|
||||
user,
|
||||
);
|
||||
|
||||
// Authorize follow request
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
requested: false,
|
||||
following: true,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, user.id),
|
||||
eq(Relationships.ownerId, account.id),
|
||||
),
|
||||
);
|
||||
await oppositeRelationship.update({
|
||||
requested: false,
|
||||
following: true,
|
||||
});
|
||||
|
||||
// Update followedBy for other user
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
followedBy: true,
|
||||
requestedBy: false,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, account.id),
|
||||
eq(Relationships.ownerId, user.id),
|
||||
),
|
||||
);
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
account,
|
||||
);
|
||||
|
||||
if (!foundRelationship) {
|
||||
return errorResponse("Relationship not found", 404);
|
||||
}
|
||||
|
||||
// Check if accepting remote follow
|
||||
if (account.isRemote()) {
|
||||
// Federate follow accept
|
||||
await sendFollowAccept(account, user);
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,18 +2,10 @@ import { applyConfig, auth, handleZodError } from "@/api";
|
|||
import { errorResponse, jsonResponse } from "@/response";
|
||||
import type { Hono } from "@hono/hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
checkForBidirectionalRelationships,
|
||||
relationshipToApi,
|
||||
} from "~/classes/functions/relationship";
|
||||
import {
|
||||
getRelationshipToOtherUser,
|
||||
sendFollowReject,
|
||||
} from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Relationships, RolePermissions } from "~/drizzle/schema";
|
||||
import { sendFollowReject } from "~/classes/functions/user";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -58,52 +50,27 @@ export default (app: Hono) =>
|
|||
return errorResponse("Account not found", 404);
|
||||
}
|
||||
|
||||
// Check if there is a relationship on both sides
|
||||
await checkForBidirectionalRelationships(user, account);
|
||||
const oppositeRelationship = await Relationship.fromOwnerAndSubject(
|
||||
account,
|
||||
user,
|
||||
);
|
||||
|
||||
// Reject follow request
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
requested: false,
|
||||
following: false,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, user.id),
|
||||
eq(Relationships.ownerId, account.id),
|
||||
),
|
||||
);
|
||||
await oppositeRelationship.update({
|
||||
requested: false,
|
||||
following: false,
|
||||
});
|
||||
|
||||
// Update followedBy for other user
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
followedBy: false,
|
||||
requestedBy: false,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, account.id),
|
||||
eq(Relationships.ownerId, user.id),
|
||||
),
|
||||
);
|
||||
|
||||
const foundRelationship = await getRelationshipToOtherUser(
|
||||
const foundRelationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
account,
|
||||
);
|
||||
|
||||
if (!foundRelationship) {
|
||||
return errorResponse("Relationship not found", 404);
|
||||
}
|
||||
|
||||
// Check if rejecting remote follow
|
||||
if (account.isRemote()) {
|
||||
// Federate follow reject
|
||||
await sendFollowReject(account, user);
|
||||
}
|
||||
|
||||
return jsonResponse(relationshipToApi(foundRelationship));
|
||||
return jsonResponse(foundRelationship.toApi());
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,18 +11,16 @@ import {
|
|||
} from "@lysand-org/federation";
|
||||
import type { Entity } from "@lysand-org/federation/types";
|
||||
import type { SocketAddress } from "bun";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { matches } from "ip-matching";
|
||||
import { z } from "zod";
|
||||
import { type ValidationError, isValidationError } from "zod-validation-error";
|
||||
import {
|
||||
getRelationshipToOtherUser,
|
||||
sendFollowAccept,
|
||||
} from "~/classes/functions/user";
|
||||
import { sendFollowAccept } from "~/classes/functions/user";
|
||||
import { db } from "~/drizzle/db";
|
||||
import { Notes, Notifications, Relationships } from "~/drizzle/schema";
|
||||
import { Notes, Notifications } from "~/drizzle/schema";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import { Note } from "~/packages/database-interface/note";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
|
||||
export const meta = applyConfig({
|
||||
|
|
@ -228,35 +226,22 @@ export default (app: Hono) =>
|
|||
}
|
||||
|
||||
const foundRelationship =
|
||||
await getRelationshipToOtherUser(account, user);
|
||||
await Relationship.fromOwnerAndSubject(
|
||||
account,
|
||||
user,
|
||||
);
|
||||
|
||||
if (foundRelationship.following) {
|
||||
if (foundRelationship.data.following) {
|
||||
return response("Already following", 200);
|
||||
}
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
following: !user.data.isLocked,
|
||||
requested: user.data.isLocked,
|
||||
showingReblogs: true,
|
||||
notifying: true,
|
||||
languages: [],
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
// Update other user's requested_by
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
requestedBy: user.data.isLocked,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, account.id),
|
||||
eq(Relationships.ownerId, user.id),
|
||||
),
|
||||
);
|
||||
await foundRelationship.update({
|
||||
following: !user.data.isLocked,
|
||||
requested: user.data.isLocked,
|
||||
showingReblogs: true,
|
||||
notifying: true,
|
||||
languages: [],
|
||||
});
|
||||
|
||||
await db.insert(Notifications).values({
|
||||
accountId: account.id,
|
||||
|
|
@ -280,36 +265,22 @@ export default (app: Hono) =>
|
|||
}
|
||||
|
||||
const foundRelationship =
|
||||
await getRelationshipToOtherUser(user, account);
|
||||
await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
account,
|
||||
);
|
||||
|
||||
if (!foundRelationship.requested) {
|
||||
if (!foundRelationship.data.requested) {
|
||||
return response(
|
||||
"There is no follow request to accept",
|
||||
200,
|
||||
);
|
||||
}
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
following: true,
|
||||
requested: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
// Update other user's data
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
followedBy: true,
|
||||
requestedBy: false,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, account.id),
|
||||
eq(Relationships.ownerId, user.id),
|
||||
),
|
||||
);
|
||||
await foundRelationship.update({
|
||||
requested: false,
|
||||
following: true,
|
||||
});
|
||||
|
||||
return response("Follow request accepted", 200);
|
||||
},
|
||||
|
|
@ -321,36 +292,22 @@ export default (app: Hono) =>
|
|||
}
|
||||
|
||||
const foundRelationship =
|
||||
await getRelationshipToOtherUser(user, account);
|
||||
await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
account,
|
||||
);
|
||||
|
||||
if (!foundRelationship.requested) {
|
||||
if (!foundRelationship.data.requested) {
|
||||
return response(
|
||||
"There is no follow request to reject",
|
||||
200,
|
||||
);
|
||||
}
|
||||
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
requested: false,
|
||||
following: false,
|
||||
})
|
||||
.where(eq(Relationships.id, foundRelationship.id));
|
||||
|
||||
// Update other user's data
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set({
|
||||
followedBy: false,
|
||||
requestedBy: false,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(Relationships.subjectId, account.id),
|
||||
eq(Relationships.ownerId, user.id),
|
||||
),
|
||||
);
|
||||
await foundRelationship.update({
|
||||
requested: false,
|
||||
following: false,
|
||||
});
|
||||
|
||||
return response("Follow request rejected", 200);
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue