feat(api): Add requested_by to relationships

This commit is contained in:
Jesse Wierzbinski 2024-06-11 12:32:38 -10:00
parent ffcf01e3cd
commit 20d1a5f39e
No known key found for this signature in database
4 changed files with 95 additions and 51 deletions

View file

@ -4,7 +4,9 @@ import { Relationships } from "~/drizzle/schema";
import type { User } from "~/packages/database-interface/user"; import type { User } from "~/packages/database-interface/user";
import type { Relationship as APIRelationship } from "~/types/mastodon/relationship"; import type { Relationship as APIRelationship } from "~/types/mastodon/relationship";
export type Relationship = InferSelectModel<typeof Relationships>; export type Relationship = InferSelectModel<typeof Relationships> & {
requestedBy: boolean;
};
/** /**
* Creates a new relationship between two users. * Creates a new relationship between two users.
@ -16,7 +18,8 @@ export const createNewRelationship = async (
owner: User, owner: User,
other: User, other: User,
): Promise<Relationship> => { ): Promise<Relationship> => {
return ( return {
...(
await db await db
.insert(Relationships) .insert(Relationships)
.values({ .values({
@ -38,7 +41,9 @@ export const createNewRelationship = async (
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}) })
.returning() .returning()
)[0]; )[0],
requestedBy: false,
};
}; };
export const checkForBidirectionalRelationships = async ( export const checkForBidirectionalRelationships = async (
@ -81,6 +86,7 @@ export const relationshipToAPI = (rel: Relationship): APIRelationship => {
muting_notifications: rel.mutingNotifications, muting_notifications: rel.mutingNotifications,
notifying: rel.notifying, notifying: rel.notifying,
requested: rel.requested, requested: rel.requested,
requested_by: rel.requestedBy,
showing_reblogs: rel.showingReblogs, showing_reblogs: rel.showingReblogs,
note: rel.note, note: rel.note,
}; };

View file

@ -17,7 +17,7 @@ import { LogLevel } from "~/packages/log-manager";
import type { Application } from "./Application"; import type { Application } from "./Application";
import type { EmojiWithInstance } from "./Emoji"; import type { EmojiWithInstance } from "./Emoji";
import { objectToInboxRequest } from "./Federation"; import { objectToInboxRequest } from "./Federation";
import { createNewRelationship } from "./Relationship"; import { type Relationship, createNewRelationship } from "./Relationship";
import type { Token } from "./Token"; import type { Token } from "./Token";
export type UserType = InferSelectModel<typeof Users>; export type UserType = InferSelectModel<typeof Users>;
@ -121,10 +121,9 @@ export const followRequestUser = async (
reblogs = false, reblogs = false,
notify = false, notify = false,
languages: string[] = [], languages: string[] = [],
): Promise<InferSelectModel<typeof Relationships>> => { ): Promise<Relationship> => {
const isRemote = followee.isRemote(); const isRemote = followee.isRemote();
const updatedRelationship = (
await db await db
.update(Relationships) .update(Relationships)
.set({ .set({
@ -134,9 +133,21 @@ export const followRequestUser = async (
notifying: notify, notifying: notify,
languages: languages, languages: languages,
}) })
.where(eq(Relationships.id, relationshipId)) .where(eq(Relationships.id, relationshipId));
.returning()
)[0]; const updatedRelationship = await db.query.Relationships.findFirst({
where: (rel, { eq }) => eq(rel.id, relationshipId),
extras: {
requestedBy:
sql<boolean>`(SELECT "requested" FROM "Relationships" WHERE "Relationships"."ownerId" = ${followee.id} AND "Relationships"."subjectId" = ${follower.id})`.as(
"requested_by",
),
},
});
if (!updatedRelationship) {
throw new Error("Failed to update relationship");
}
if (isRemote) { if (isRemote) {
// Federate // Federate
@ -165,16 +176,29 @@ export const followRequestUser = async (
} to ${followee.getUri()}`, } to ${followee.getUri()}`,
); );
return (
await db await db
.update(Relationships) .update(Relationships)
.set({ .set({
following: false, following: false,
requested: false, requested: false,
}) })
.where(eq(Relationships.id, relationshipId)) .where(eq(Relationships.id, relationshipId));
.returning()
)[0]; const result = await db.query.Relationships.findFirst({
where: (rel, { eq }) => eq(rel.id, relationshipId),
extras: {
requestedBy:
sql<boolean>`(SELECT "requested" FROM "Relationships" WHERE "Relationships"."ownerId" = ${followee.id} AND "Relationships"."subjectId" = ${follower.id})`.as(
"requested_by",
),
},
});
if (!result) {
throw new Error("Failed to update relationship");
}
return result;
} }
} else { } else {
await db.insert(Notifications).values({ await db.insert(Notifications).values({
@ -458,13 +482,19 @@ export const retrieveToken = async (
export const getRelationshipToOtherUser = async ( export const getRelationshipToOtherUser = async (
user: User, user: User,
other: User, other: User,
): Promise<InferSelectModel<typeof Relationships>> => { ): Promise<Relationship> => {
const foundRelationship = await db.query.Relationships.findFirst({ const foundRelationship = await db.query.Relationships.findFirst({
where: (relationship, { and, eq }) => where: (relationship, { and, eq }) =>
and( and(
eq(relationship.ownerId, user.id), eq(relationship.ownerId, user.id),
eq(relationship.subjectId, other.id), eq(relationship.subjectId, other.id),
), ),
extras: {
requestedBy:
sql<boolean>`(SELECT "requested" FROM "Relationships" WHERE "Relationships"."ownerId" = ${other.id} AND "Relationships"."subjectId" = ${user.id})`.as(
"requested_by",
),
},
}); });
if (!foundRelationship) { if (!foundRelationship) {

View file

@ -1,6 +1,7 @@
import { applyConfig, auth, handleZodError, qsQuery } from "@/api"; import { applyConfig, auth, handleZodError, qsQuery } from "@/api";
import { errorResponse, jsonResponse } from "@/response"; import { errorResponse, jsonResponse } from "@/response";
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { sql } from "drizzle-orm";
import type { Hono } from "hono"; import type { Hono } from "hono";
import { z } from "zod"; import { z } from "zod";
import { import {
@ -8,7 +9,7 @@ import {
relationshipToAPI, relationshipToAPI,
} from "~/database/entities/Relationship"; } from "~/database/entities/Relationship";
import { db } from "~/drizzle/db"; import { db } from "~/drizzle/db";
import { RolePermissions } from "~/drizzle/schema"; import { Relationships, RolePermissions } from "~/drizzle/schema";
import { User } from "~/packages/database-interface/user"; import { User } from "~/packages/database-interface/user";
export const meta = applyConfig({ export const meta = applyConfig({
@ -54,6 +55,12 @@ export default (app: Hono) =>
inArray(relationship.subjectId, ids), inArray(relationship.subjectId, ids),
eq(relationship.ownerId, self.id), eq(relationship.ownerId, self.id),
), ),
extras: {
requestedBy:
sql<boolean>`(SELECT "requested" FROM "Relationships" WHERE "Relationships"."ownerId" = ${Relationships.id} AND "Relationships"."subjectId" = ${self.id})`.as(
"requested_by",
),
},
}); });
const missingIds = ids.filter( const missingIds = ids.filter(

View file

@ -7,6 +7,7 @@ export type Relationship = {
muting: boolean; muting: boolean;
muting_notifications: boolean; muting_notifications: boolean;
requested: boolean; requested: boolean;
requested_by: boolean;
domain_blocking: boolean; domain_blocking: boolean;
showing_reblogs: boolean; showing_reblogs: boolean;
endorsed: boolean; endorsed: boolean;