Show Reddit post age in conversations
This commit is contained in:
1 parent
7db60e8839
commit
50f9f8a6aa
14 files changed
+65
-11
No files matched your search
@@ -5,6 +5,32 @@ export interface OriginPost {
|
|||||||
url: string;
|
url: string;
|
||||||
imageUrl?: string | null;
|
imageUrl?: string | null;
|
||||||
subreddit?: string;
|
subreddit?: string;
|
||||||
|
postedAt?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatPostAge(postedAt: number, now = Date.now()): string {
|
||||||
|
const elapsedSeconds = Math.max(0, Math.floor((now - postedAt) / 1000));
|
||||||
|
if (elapsedSeconds < 60) return 'now';
|
||||||
|
const elapsedMinutes = Math.floor(elapsedSeconds / 60);
|
||||||
|
if (elapsedMinutes < 60) return `${elapsedMinutes}m ago`;
|
||||||
|
const elapsedHours = Math.floor(elapsedMinutes / 60);
|
||||||
|
if (elapsedHours < 24) return `${elapsedHours}h ago`;
|
||||||
|
const elapsedDays = Math.floor(elapsedHours / 24);
|
||||||
|
if (elapsedDays < 30) return `${elapsedDays}d ago`;
|
||||||
|
const elapsedMonths = Math.floor(elapsedDays / 30);
|
||||||
|
if (elapsedMonths < 12) return `${elapsedMonths}mo ago`;
|
||||||
|
return `${Math.floor(elapsedMonths / 12)}y ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PostOriginMeta({ post }: { post: OriginPost }) {
|
||||||
|
return (
|
||||||
|
<small>
|
||||||
|
Started from {post.subreddit ? `r/${post.subreddit}` : 'Reddit'}
|
||||||
|
{post.postedAt ? (
|
||||||
|
<> · <time dateTime={new Date(post.postedAt).toISOString()} title={new Date(post.postedAt).toLocaleString()}>{formatPostAge(post.postedAt)}</time></>
|
||||||
|
) : null}
|
||||||
|
</small>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OriginPostCard({ post }: { post: OriginPost }) {
|
export function OriginPostCard({ post }: { post: OriginPost }) {
|
||||||
@@ -21,7 +47,7 @@ export function OriginPostCard({ post }: { post: OriginPost }) {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<a aria-label={post.title} className="origin-post-copy" href={post.url} rel="noreferrer" target="_blank">
|
<a aria-label={post.title} className="origin-post-copy" href={post.url} rel="noreferrer" target="_blank">
|
||||||
<small>Started from {post.subreddit ? `r/${post.subreddit}` : 'Reddit'}</small>
|
<PostOriginMeta post={post} />
|
||||||
<strong>{post.title}</strong>
|
<strong>{post.title}</strong>
|
||||||
<span>Open original post</span>
|
<span>Open original post</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -69,7 +95,7 @@ export function OriginPostButton({ children, post }: { children: ReactNode; post
|
|||||||
</div>
|
</div>
|
||||||
{post.imageUrl ? <img alt={`Source post: ${post.title}`} loading="lazy" src={post.imageUrl} /> : null}
|
{post.imageUrl ? <img alt={`Source post: ${post.title}`} loading="lazy" src={post.imageUrl} /> : null}
|
||||||
<div className="origin-post-dialog-copy">
|
<div className="origin-post-dialog-copy">
|
||||||
{post.subreddit ? <small>r/{post.subreddit}</small> : null}
|
<PostOriginMeta post={post} />
|
||||||
<h2 id="origin-post-dialog-title">{post.title}</h2>
|
<h2 id="origin-post-dialog-title">{post.title}</h2>
|
||||||
<a className="button primary" href={post.url} rel="noreferrer" target="_blank">Open Reddit post</a>
|
<a className="button primary" href={post.url} rel="noreferrer" target="_blank">Open Reddit post</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ export function ConversationDetail({ conversationId, onClose }: ConversationDeta
|
|||||||
url: conversation.triggeringPost.url,
|
url: conversation.triggeringPost.url,
|
||||||
imageUrl: conversation.triggeringPost.imageUrl,
|
imageUrl: conversation.triggeringPost.imageUrl,
|
||||||
subreddit: conversation.triggeringPost.subreddit,
|
subreddit: conversation.triggeringPost.subreddit,
|
||||||
|
postedAt: conversation.triggeringPost.postedAt,
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export const ConversationDetailResponseSchema = ActiveChatSchema.extend({
|
|||||||
title: z.string().optional(),
|
title: z.string().optional(),
|
||||||
url: z.string(),
|
url: z.string(),
|
||||||
imageUrl: z.string().nullable().optional(),
|
imageUrl: z.string().nullable().optional(),
|
||||||
|
postedAt: z.number().optional(),
|
||||||
sentAt: z.number(),
|
sentAt: z.number(),
|
||||||
}).nullable(),
|
}).nullable(),
|
||||||
automation: z.strictObject({
|
automation: z.strictObject({
|
||||||
|
|||||||
@@ -172,7 +172,8 @@ describe('dashboard endpoint contracts', () => {
|
|||||||
...chat,
|
...chat,
|
||||||
triggeringPost: {
|
triggeringPost: {
|
||||||
id: 'post-1', subreddit: 'example', title: 'Example',
|
id: 'post-1', subreddit: 'example', title: 'Example',
|
||||||
url: 'https://www.reddit.com/r/example/comments/post-1/', imageUrl: 'https://i.redd.it/example.jpg', sentAt: 1_700_000_000_000,
|
url: 'https://www.reddit.com/r/example/comments/post-1/', imageUrl: 'https://i.redd.it/example.jpg',
|
||||||
|
postedAt: 1_699_999_000_000, sentAt: 1_700_000_000_000,
|
||||||
},
|
},
|
||||||
automation: { turnsUsed: 1, remainingTurns: 2, status: 'active', handoffReason: null },
|
automation: { turnsUsed: 1, remainingTurns: 2, status: 'active', handoffReason: null },
|
||||||
syncInProgress: null,
|
syncInProgress: null,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export function runMigrations(db: Database.Database): void {
|
|||||||
image_url TEXT,
|
image_url TEXT,
|
||||||
image_analysis TEXT,
|
image_analysis TEXT,
|
||||||
generated_message TEXT,
|
generated_message TEXT,
|
||||||
|
post_created_at INTEGER,
|
||||||
processed_at INTEGER NOT NULL,
|
processed_at INTEGER NOT NULL,
|
||||||
message_sent INTEGER DEFAULT 0,
|
message_sent INTEGER DEFAULT 0,
|
||||||
error TEXT
|
error TEXT
|
||||||
@@ -272,6 +273,9 @@ export function runMigrations(db: Database.Database): void {
|
|||||||
CREATE INDEX IF NOT EXISTS idx_ai_usage_model ON ai_usage(actual_model, requested_model, created_at DESC);
|
CREATE INDEX IF NOT EXISTS idx_ai_usage_model ON ai_usage(actual_model, requested_model, created_at DESC);
|
||||||
CREATE INDEX IF NOT EXISTS idx_ai_usage_account ON ai_usage(account_id, created_at DESC);
|
CREATE INDEX IF NOT EXISTS idx_ai_usage_account ON ai_usage(account_id, created_at DESC);
|
||||||
`),
|
`),
|
||||||
|
() => {
|
||||||
|
addColumnIfNotExists(db, 'processed_posts', 'post_created_at', 'INTEGER');
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let currentVersion = db.pragma('user_version', { simple: true }) as number;
|
let currentVersion = db.pragma('user_version', { simple: true }) as number;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface ProcessedPostRecord {
|
|||||||
imageUrl: string | null;
|
imageUrl: string | null;
|
||||||
imageAnalysis: string | null;
|
imageAnalysis: string | null;
|
||||||
generatedMessage: string | null;
|
generatedMessage: string | null;
|
||||||
|
postCreatedAt: number | null;
|
||||||
processedAt: number;
|
processedAt: number;
|
||||||
messageSent: boolean;
|
messageSent: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
@@ -43,6 +44,7 @@ export interface SentMessageRecord {
|
|||||||
postUrl?: string;
|
postUrl?: string;
|
||||||
postImageUrl?: string;
|
postImageUrl?: string;
|
||||||
postImageAnalysis?: string;
|
postImageAnalysis?: string;
|
||||||
|
postCreatedAt?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SuccessfulMessageRecord {
|
export interface SuccessfulMessageRecord {
|
||||||
@@ -418,8 +420,9 @@ export class PostsRepository {
|
|||||||
private readonly accountId: string = LEGACY_UNASSIGNED_ACCOUNT_ID,
|
private readonly accountId: string = LEGACY_UNASSIGNED_ACCOUNT_ID,
|
||||||
) {
|
) {
|
||||||
this.insertStmt = db.prepare(`
|
this.insertStmt = db.prepare(`
|
||||||
INSERT INTO processed_posts (account_id, id, subreddit, author, title, post_url, image_url, processed_at)
|
INSERT INTO processed_posts (
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
account_id, id, subreddit, author, title, post_url, image_url, post_created_at, processed_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
this.existsStmt = db.prepare(`SELECT 1 FROM processed_posts WHERE account_id = ? AND id = ?`);
|
this.existsStmt = db.prepare(`SELECT 1 FROM processed_posts WHERE account_id = ? AND id = ?`);
|
||||||
@@ -462,6 +465,7 @@ export class PostsRepository {
|
|||||||
title: string;
|
title: string;
|
||||||
postUrl?: string | null;
|
postUrl?: string | null;
|
||||||
imageUrl: string | null;
|
imageUrl: string | null;
|
||||||
|
postCreatedAt?: number | null;
|
||||||
processedAt: number;
|
processedAt: number;
|
||||||
}): void {
|
}): void {
|
||||||
this.insertStmt.run(
|
this.insertStmt.run(
|
||||||
@@ -472,6 +476,7 @@ export class PostsRepository {
|
|||||||
post.title,
|
post.title,
|
||||||
post.postUrl ?? null,
|
post.postUrl ?? null,
|
||||||
post.imageUrl,
|
post.imageUrl,
|
||||||
|
post.postCreatedAt ?? null,
|
||||||
post.processedAt
|
post.processedAt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -501,6 +506,7 @@ export class PostsRepository {
|
|||||||
imageUrl: row.image_url as string | null,
|
imageUrl: row.image_url as string | null,
|
||||||
imageAnalysis: row.image_analysis as string | null,
|
imageAnalysis: row.image_analysis as string | null,
|
||||||
generatedMessage: row.generated_message as string | null,
|
generatedMessage: row.generated_message as string | null,
|
||||||
|
postCreatedAt: (row.post_created_at as number | null) ?? null,
|
||||||
processedAt: row.processed_at as number,
|
processedAt: row.processed_at as number,
|
||||||
messageSent: Boolean(row.message_sent),
|
messageSent: Boolean(row.message_sent),
|
||||||
error: row.error as string | null,
|
error: row.error as string | null,
|
||||||
@@ -518,6 +524,7 @@ export class PostsRepository {
|
|||||||
imageUrl: row.image_url as string | null,
|
imageUrl: row.image_url as string | null,
|
||||||
imageAnalysis: row.image_analysis as string | null,
|
imageAnalysis: row.image_analysis as string | null,
|
||||||
generatedMessage: row.generated_message as string | null,
|
generatedMessage: row.generated_message as string | null,
|
||||||
|
postCreatedAt: (row.post_created_at as number | null) ?? null,
|
||||||
processedAt: row.processed_at as number,
|
processedAt: row.processed_at as number,
|
||||||
messageSent: Boolean(row.message_sent),
|
messageSent: Boolean(row.message_sent),
|
||||||
error: row.error as string | null,
|
error: row.error as string | null,
|
||||||
@@ -556,7 +563,7 @@ export class MessagesRepository {
|
|||||||
|
|
||||||
this.getByChatRoomIdStmt = db.prepare(`
|
this.getByChatRoomIdStmt = db.prepare(`
|
||||||
SELECT sm.*, pp.subreddit, pp.title AS post_title, pp.post_url, pp.image_url AS post_image_url,
|
SELECT sm.*, pp.subreddit, pp.title AS post_title, pp.post_url, pp.image_url AS post_image_url,
|
||||||
pp.image_analysis AS post_image_analysis
|
pp.image_analysis AS post_image_analysis, pp.post_created_at AS post_created_at
|
||||||
FROM sent_messages sm
|
FROM sent_messages sm
|
||||||
LEFT JOIN processed_posts pp ON sm.account_id = pp.account_id AND sm.post_id = pp.id
|
LEFT JOIN processed_posts pp ON sm.account_id = pp.account_id AND sm.post_id = pp.id
|
||||||
WHERE sm.account_id = ? AND sm.chat_room_id = ?
|
WHERE sm.account_id = ? AND sm.chat_room_id = ?
|
||||||
@@ -568,7 +575,7 @@ export class MessagesRepository {
|
|||||||
|
|
||||||
this.getLatestByRecipientStmt = db.prepare(`
|
this.getLatestByRecipientStmt = db.prepare(`
|
||||||
SELECT sm.*, pp.subreddit, pp.title AS post_title, pp.post_url, pp.image_url AS post_image_url,
|
SELECT sm.*, pp.subreddit, pp.title AS post_title, pp.post_url, pp.image_url AS post_image_url,
|
||||||
pp.image_analysis AS post_image_analysis
|
pp.image_analysis AS post_image_analysis, pp.post_created_at AS post_created_at
|
||||||
FROM sent_messages sm
|
FROM sent_messages sm
|
||||||
LEFT JOIN processed_posts pp ON sm.account_id = pp.account_id AND sm.post_id = pp.id
|
LEFT JOIN processed_posts pp ON sm.account_id = pp.account_id AND sm.post_id = pp.id
|
||||||
WHERE sm.account_id = ? AND sm.recipient = ? COLLATE NOCASE
|
WHERE sm.account_id = ? AND sm.recipient = ? COLLATE NOCASE
|
||||||
@@ -578,7 +585,7 @@ export class MessagesRepository {
|
|||||||
|
|
||||||
this.getRecentStmt = db.prepare(`
|
this.getRecentStmt = db.prepare(`
|
||||||
SELECT sm.*, pp.subreddit, pp.title AS post_title, pp.post_url, pp.image_url AS post_image_url,
|
SELECT sm.*, pp.subreddit, pp.title AS post_title, pp.post_url, pp.image_url AS post_image_url,
|
||||||
pp.image_analysis AS post_image_analysis
|
pp.image_analysis AS post_image_analysis, pp.post_created_at AS post_created_at
|
||||||
FROM sent_messages sm
|
FROM sent_messages sm
|
||||||
LEFT JOIN processed_posts pp ON sm.account_id = pp.account_id AND sm.post_id = pp.id
|
LEFT JOIN processed_posts pp ON sm.account_id = pp.account_id AND sm.post_id = pp.id
|
||||||
WHERE sm.account_id = ?
|
WHERE sm.account_id = ?
|
||||||
@@ -909,6 +916,7 @@ export class MessagesRepository {
|
|||||||
postUrl: (row.post_url as string) || undefined,
|
postUrl: (row.post_url as string) || undefined,
|
||||||
postImageUrl: (row.post_image_url as string) || undefined,
|
postImageUrl: (row.post_image_url as string) || undefined,
|
||||||
postImageAnalysis: (row.post_image_analysis as string) || undefined,
|
postImageAnalysis: (row.post_image_analysis as string) || undefined,
|
||||||
|
postCreatedAt: (row.post_created_at as number) || undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ export async function runMainLoop(app: AppContainer): Promise<void> {
|
|||||||
title: post.title,
|
title: post.title,
|
||||||
postUrl,
|
postUrl,
|
||||||
imageUrl: postImageUrl,
|
imageUrl: postImageUrl,
|
||||||
|
postCreatedAt: post.created_utc * 1000,
|
||||||
processedAt: Date.now(),
|
processedAt: Date.now(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ export class MonitorService {
|
|||||||
title: post.title,
|
title: post.title,
|
||||||
postUrl: this.redditApi.getPostUrl(post),
|
postUrl: this.redditApi.getPostUrl(post),
|
||||||
imageUrl: subredditType === 'image' ? this.redditApi.getImageUrl(post) : null,
|
imageUrl: subredditType === 'image' ? this.redditApi.getImageUrl(post) : null,
|
||||||
|
postCreatedAt: post.created_utc * 1000,
|
||||||
processedAt: Date.now(),
|
processedAt: Date.now(),
|
||||||
});
|
});
|
||||||
this.postsRepo.setError(post.id, reason);
|
this.postsRepo.setError(post.id, reason);
|
||||||
|
|||||||
@@ -288,7 +288,8 @@ class AccountRuntimeLoop {
|
|||||||
const imageUrl = isChat ? null : redditApi.getImageUrl(post);
|
const imageUrl = isChat ? null : redditApi.getImageUrl(post);
|
||||||
postsRepo.insert({
|
postsRepo.insert({
|
||||||
id: post.id, subreddit: post.subreddit, author: post.author, title: post.title,
|
id: post.id, subreddit: post.subreddit, author: post.author, title: post.title,
|
||||||
postUrl: redditApi.getPostUrl(post), imageUrl, processedAt: Date.now(),
|
postUrl: redditApi.getPostUrl(post), imageUrl,
|
||||||
|
postCreatedAt: post.created_utc * 1000, processedAt: Date.now(),
|
||||||
});
|
});
|
||||||
// Seller screening is performed once by the shared MonitorService before
|
// Seller screening is performed once by the shared MonitorService before
|
||||||
// assignment. Do not repeat its profile request for every recipient.
|
// assignment. Do not repeat its profile request for every recipient.
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ export function createConversationsRouter(ctx: WebContext): Router {
|
|||||||
title?: string;
|
title?: string;
|
||||||
url: string;
|
url: string;
|
||||||
imageUrl: string | null;
|
imageUrl: string | null;
|
||||||
|
postedAt?: number;
|
||||||
sentAt: number;
|
sentAt: number;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
let automatedOpener: string | null = null;
|
let automatedOpener: string | null = null;
|
||||||
@@ -188,6 +189,7 @@ export function createConversationsRouter(ctx: WebContext): Router {
|
|||||||
title: sent.postTitle,
|
title: sent.postTitle,
|
||||||
url,
|
url,
|
||||||
imageUrl: sent.postImageUrl ?? null,
|
imageUrl: sent.postImageUrl ?? null,
|
||||||
|
...(sent.postCreatedAt ? { postedAt: sent.postCreatedAt } : {}),
|
||||||
sentAt: sent.sentAt,
|
sentAt: sent.sentAt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ function detailFixture(chat = alice) {
|
|||||||
title: 'Looking for a chat',
|
title: 'Looking for a chat',
|
||||||
url: 'https://reddit.com/r/casualconversation/comments/post-1',
|
url: 'https://reddit.com/r/casualconversation/comments/post-1',
|
||||||
imageUrl: 'https://i.redd.it/source-post.jpg',
|
imageUrl: 'https://i.redd.it/source-post.jpg',
|
||||||
|
postedAt: Date.now() - (2 * 60 * 60 * 1000),
|
||||||
sentAt: 1_785_999_800_000,
|
sentAt: 1_785_999_800_000,
|
||||||
},
|
},
|
||||||
automation: { turnsUsed: 0, remainingTurns: 3, status: 'active', handoffReason: null },
|
automation: { turnsUsed: 0, remainingTurns: 3, status: 'active', handoffReason: null },
|
||||||
@@ -142,6 +143,7 @@ describe('ConversationsPage', () => {
|
|||||||
'src',
|
'src',
|
||||||
'https://i.redd.it/source-post.jpg',
|
'https://i.redd.it/source-post.jpg',
|
||||||
);
|
);
|
||||||
|
expect(screen.getByText('2h ago')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('img', { name: 'Source post: Looking for a chat' })).toHaveClass('is-blurred');
|
expect(screen.getByRole('img', { name: 'Source post: Looking for a chat' })).toHaveClass('is-blurred');
|
||||||
await user.click(screen.getByRole('button', { name: 'Reveal original image' }));
|
await user.click(screen.getByRole('button', { name: 'Reveal original image' }));
|
||||||
expect(screen.getByRole('img', { name: 'Source post: Looking for a chat' })).not.toHaveClass('is-blurred');
|
expect(screen.getByRole('img', { name: 'Source post: Looking for a chat' })).not.toHaveClass('is-blurred');
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ describe('Database Client', () => {
|
|||||||
DROP TABLE conversation_automation_claims;
|
DROP TABLE conversation_automation_claims;
|
||||||
DROP TABLE ai_usage;
|
DROP TABLE ai_usage;
|
||||||
`);
|
`);
|
||||||
db.pragma(`user_version = ${latestVersion - 2}`);
|
db.pragma(`user_version = ${latestVersion - 3}`);
|
||||||
runMigrations(db);
|
runMigrations(db);
|
||||||
|
|
||||||
expect(db.prepare('SELECT recipient, reason FROM recipient_suppressions ORDER BY recipient COLLATE NOCASE').all())
|
expect(db.prepare('SELECT recipient, reason FROM recipient_suppressions ORDER BY recipient COLLATE NOCASE').all())
|
||||||
@@ -176,6 +176,7 @@ describe('Database Client', () => {
|
|||||||
expect(columnMap.get('subreddit')?.notnull).toBe(1);
|
expect(columnMap.get('subreddit')?.notnull).toBe(1);
|
||||||
expect(columnMap.get('author')?.notnull).toBe(1);
|
expect(columnMap.get('author')?.notnull).toBe(1);
|
||||||
expect(columnMap.get('title')?.notnull).toBe(1);
|
expect(columnMap.get('title')?.notnull).toBe(1);
|
||||||
|
expect(columnMap.get('post_created_at')).toBeDefined();
|
||||||
expect(columnMap.get('processed_at')?.notnull).toBe(1);
|
expect(columnMap.get('processed_at')?.notnull).toBe(1);
|
||||||
expect(columnMap.get('message_sent')).toBeDefined();
|
expect(columnMap.get('message_sent')).toBeDefined();
|
||||||
expect(columnMap.get('error')).toBeDefined();
|
expect(columnMap.get('error')).toBeDefined();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ describe('PostsRepository', () => {
|
|||||||
title: 'Test Post',
|
title: 'Test Post',
|
||||||
postUrl: 'https://www.reddit.com/r/test/comments/post1/test_post/',
|
postUrl: 'https://www.reddit.com/r/test/comments/post1/test_post/',
|
||||||
imageUrl: 'http://example.com/img.jpg',
|
imageUrl: 'http://example.com/img.jpg',
|
||||||
|
postCreatedAt: 1_700_000_000_000,
|
||||||
processedAt: Date.now(),
|
processedAt: Date.now(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ describe('PostsRepository', () => {
|
|||||||
expect(post!.title).toBe('Test Post');
|
expect(post!.title).toBe('Test Post');
|
||||||
expect(post!.postUrl).toBe('https://www.reddit.com/r/test/comments/post1/test_post/');
|
expect(post!.postUrl).toBe('https://www.reddit.com/r/test/comments/post1/test_post/');
|
||||||
expect(post!.imageUrl).toBe('http://example.com/img.jpg');
|
expect(post!.imageUrl).toBe('http://example.com/img.jpg');
|
||||||
|
expect(post!.postCreatedAt).toBe(1_700_000_000_000);
|
||||||
expect(post!.messageSent).toBe(false);
|
expect(post!.messageSent).toBe(false);
|
||||||
expect(post!.imageAnalysis).toBeNull();
|
expect(post!.imageAnalysis).toBeNull();
|
||||||
expect(post!.error).toBeNull();
|
expect(post!.error).toBeNull();
|
||||||
@@ -314,6 +316,7 @@ describe('MessagesRepository', () => {
|
|||||||
title: 'Second post',
|
title: 'Second post',
|
||||||
postUrl: 'https://www.reddit.com/r/gonewild/comments/post-b/second_post/',
|
postUrl: 'https://www.reddit.com/r/gonewild/comments/post-b/second_post/',
|
||||||
imageUrl: null,
|
imageUrl: null,
|
||||||
|
postCreatedAt: 1_700_000_000_000,
|
||||||
processedAt: Date.now(),
|
processedAt: Date.now(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -327,6 +330,7 @@ describe('MessagesRepository', () => {
|
|||||||
expect(latest!.subreddit).toBe('gonewild');
|
expect(latest!.subreddit).toBe('gonewild');
|
||||||
expect(latest!.postTitle).toBe('Second post');
|
expect(latest!.postTitle).toBe('Second post');
|
||||||
expect(latest!.postUrl).toBe('https://www.reddit.com/r/gonewild/comments/post-b/second_post/');
|
expect(latest!.postUrl).toBe('https://www.reddit.com/r/gonewild/comments/post-b/second_post/');
|
||||||
|
expect(latest!.postCreatedAt).toBe(1_700_000_000_000);
|
||||||
expect(messagesRepo.getByChatRoomId('room-b')).toMatchObject({ postId: 'post-b', postTitle: 'Second post' });
|
expect(messagesRepo.getByChatRoomId('room-b')).toMatchObject({ postId: 'post-b', postTitle: 'Second post' });
|
||||||
|
|
||||||
expect(messagesRepo.getLatestByRecipient('ALICE')).toBeDefined();
|
expect(messagesRepo.getLatestByRecipient('ALICE')).toBeDefined();
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ describe('conversations route', () => {
|
|||||||
chatRoomId: 'room-alice', subreddit: 'example', postTitle: 'Exact source post',
|
chatRoomId: 'room-alice', subreddit: 'example', postTitle: 'Exact source post',
|
||||||
postUrl: 'https://www.reddit.com/r/example/comments/post-exact/exact_source_post/',
|
postUrl: 'https://www.reddit.com/r/example/comments/post-exact/exact_source_post/',
|
||||||
postImageUrl: 'https://i.redd.it/exact-source.jpg',
|
postImageUrl: 'https://i.redd.it/exact-source.jpg',
|
||||||
|
postCreatedAt: 8,
|
||||||
};
|
};
|
||||||
const latestRecipientOrigin = { ...roomOrigin, postId: 'wrong-latest-post', postTitle: 'Wrong post' };
|
const latestRecipientOrigin = { ...roomOrigin, postId: 'wrong-latest-post', postTitle: 'Wrong post' };
|
||||||
const context = {
|
const context = {
|
||||||
@@ -318,7 +319,7 @@ describe('conversations route', () => {
|
|||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
expect(body.triggeringPost).toEqual({
|
expect(body.triggeringPost).toEqual({
|
||||||
id: 'post-exact', subreddit: 'example', title: 'Exact source post',
|
id: 'post-exact', subreddit: 'example', title: 'Exact source post',
|
||||||
url: roomOrigin.postUrl, imageUrl: roomOrigin.postImageUrl, sentAt: 9,
|
url: roomOrigin.postUrl, imageUrl: roomOrigin.postImageUrl, postedAt: 8, sentAt: 9,
|
||||||
});
|
});
|
||||||
expect(body.messages[0]).toMatchObject({ text: 'Hello', isAi: true });
|
expect(body.messages[0]).toMatchObject({ text: 'Hello', isAi: true });
|
||||||
expect(context.repos.messages.getLatestByRecipient).not.toHaveBeenCalled();
|
expect(context.repos.messages.getLatestByRecipient).not.toHaveBeenCalled();
|
||||||
|
|||||||
Reference in new issue
Block a user