mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
fix recommendations
This commit is contained in:
parent
9cf5d2bc4e
commit
0c5ba53c26
8 changed files with 114 additions and 100 deletions
|
|
@ -34,6 +34,10 @@ export const highlightRepository = entityManager
|
|||
return this.save(unescapeHighlight(highlight))
|
||||
},
|
||||
|
||||
createAndSaves(highlights: DeepPartial<Highlight>[]) {
|
||||
return this.save(highlights.map(unescapeHighlight))
|
||||
},
|
||||
|
||||
updateAndSave(
|
||||
highlightId: string,
|
||||
highlight: QueryDeepPartialEntity<Highlight>
|
||||
|
|
|
|||
|
|
@ -46,20 +46,10 @@ export const createGroupResolver = authorized<
|
|||
CreateGroupSuccess,
|
||||
CreateGroupError,
|
||||
MutationCreateGroupArgs
|
||||
>(async (_, { input }, { claims: { uid }, log }) => {
|
||||
log.info('Creating group', {
|
||||
input,
|
||||
labels: {
|
||||
source: 'resolver',
|
||||
resolver: 'createGroupResolver',
|
||||
uid,
|
||||
},
|
||||
})
|
||||
|
||||
>(async (_, { input }, { uid, log }) => {
|
||||
try {
|
||||
const userData = await userRepository.findOne({
|
||||
where: { id: uid },
|
||||
relations: ['profile'],
|
||||
const userData = await userRepository.findOneBy({
|
||||
id: uid,
|
||||
})
|
||||
if (!userData) {
|
||||
return {
|
||||
|
|
@ -106,14 +96,7 @@ export const createGroupResolver = authorized<
|
|||
},
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error creating group', {
|
||||
error,
|
||||
labels: {
|
||||
source: 'resolver',
|
||||
resolver: 'createGroupResolver',
|
||||
uid,
|
||||
},
|
||||
})
|
||||
log.error('Error creating group', error)
|
||||
|
||||
return {
|
||||
errorCodes: [CreateGroupErrorCode.BadRequest],
|
||||
|
|
@ -122,15 +105,7 @@ export const createGroupResolver = authorized<
|
|||
})
|
||||
|
||||
export const groupsResolver = authorized<GroupsSuccess, GroupsError>(
|
||||
async (_, __, { claims: { uid }, log }) => {
|
||||
log.info('Getting groups', {
|
||||
labels: {
|
||||
source: 'resolver',
|
||||
resolver: 'groupsResolver',
|
||||
uid,
|
||||
},
|
||||
})
|
||||
|
||||
async (_, __, { uid, log }) => {
|
||||
try {
|
||||
const user = await userRepository.findOneBy({
|
||||
id: uid,
|
||||
|
|
@ -168,15 +143,6 @@ export const recommendResolver = authorized<
|
|||
RecommendError,
|
||||
MutationRecommendArgs
|
||||
>(async (_, { input }, { uid, log, signToken }) => {
|
||||
log.info('Recommend', {
|
||||
input,
|
||||
labels: {
|
||||
source: 'resolver',
|
||||
resolver: 'recommendResolver',
|
||||
uid,
|
||||
},
|
||||
})
|
||||
|
||||
try {
|
||||
const item = await findLibraryItemById(input.pageId, uid)
|
||||
if (!item) {
|
||||
|
|
@ -208,11 +174,11 @@ export const recommendResolver = authorized<
|
|||
member.user.id,
|
||||
item.id,
|
||||
{
|
||||
group,
|
||||
note: input.note ?? null,
|
||||
recommender: item.user,
|
||||
group: { id: group.id },
|
||||
note: input.note,
|
||||
recommender: { id: uid },
|
||||
createdAt: new Date(),
|
||||
libraryItem: item,
|
||||
libraryItem: { id: item.id },
|
||||
},
|
||||
auth,
|
||||
recommendedHighlightIds
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ export function pageRouter() {
|
|||
return res.status(400).send({ errorCode: 'BAD_DATA' })
|
||||
}
|
||||
|
||||
const item = await findLibraryItemById(itemId, userId)
|
||||
const item = await findLibraryItemById(itemId, claims.uid)
|
||||
if (!item) {
|
||||
return res.status(404).send({ errorCode: 'NOT_FOUND' })
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ export function pageRouter() {
|
|||
const recommendedItem = await addRecommendation(
|
||||
item,
|
||||
recommendation,
|
||||
claims.uid,
|
||||
userId,
|
||||
highlightIds
|
||||
)
|
||||
if (!recommendedItem) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,31 @@ export const getHighlightLocation = (patch: string): number | undefined => {
|
|||
export const getHighlightUrl = (slug: string, highlightId: string): string =>
|
||||
`${homePageURL()}/me/${slug}#${highlightId}`
|
||||
|
||||
export const createHighlights = async (
|
||||
highlights: DeepPartial<Highlight>[],
|
||||
libraryItemId: string,
|
||||
userId: string,
|
||||
pubsub = createPubSubClient()
|
||||
) => {
|
||||
const newHighlights = await authTrx(
|
||||
async (tx) =>
|
||||
tx.withRepository(highlightRepository).createAndSaves(highlights),
|
||||
undefined,
|
||||
userId
|
||||
)
|
||||
|
||||
await pubsub.entityCreated<CreateHighlightEvent[]>(
|
||||
EntityType.HIGHLIGHT,
|
||||
newHighlights.map((highlight) => ({
|
||||
...highlight,
|
||||
pageId: libraryItemId,
|
||||
})),
|
||||
userId
|
||||
)
|
||||
|
||||
return newHighlights
|
||||
}
|
||||
|
||||
export const createHighlight = async (
|
||||
highlight: DeepPartial<Highlight>,
|
||||
libraryItemId: string,
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ export const findLibraryItemById = async (
|
|||
.createQueryBuilder(LibraryItem, 'library_item')
|
||||
.leftJoinAndSelect('library_item.labels', 'labels')
|
||||
.leftJoinAndSelect('library_item.highlights', 'highlights')
|
||||
.leftJoinAndSelect('highlights.user', 'user')
|
||||
.where('library_item.id = :id', { id })
|
||||
.getOne(),
|
||||
undefined,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import { nanoid } from 'nanoid'
|
||||
import { DeepPartial } from 'typeorm'
|
||||
import { LibraryItem } from '../entity/library_item'
|
||||
import { Recommendation } from '../entity/recommendation'
|
||||
import { getRepository } from '../repository'
|
||||
import { logger } from '../utils/logger'
|
||||
import {
|
||||
createLibraryItem,
|
||||
findLibraryItemByUrl,
|
||||
updateLibraryItem,
|
||||
} from './library_item'
|
||||
import { createHighlights } from './highlights'
|
||||
import { createLibraryItem, findLibraryItemByUrl } from './library_item'
|
||||
|
||||
export const addRecommendation = async (
|
||||
item: LibraryItem,
|
||||
|
|
@ -15,65 +14,83 @@ export const addRecommendation = async (
|
|||
highlightIds?: string[]
|
||||
) => {
|
||||
try {
|
||||
const highlights = item.highlights?.filter((highlight) =>
|
||||
highlightIds?.includes(highlight.id)
|
||||
)
|
||||
|
||||
// check if the item is already recommended to the group
|
||||
const existingItem = await findLibraryItemByUrl(item.originalUrl, userId)
|
||||
if (existingItem) {
|
||||
const existingHighlights = existingItem.highlights || []
|
||||
let recommendedItem = await findLibraryItemByUrl(item.originalUrl, userId)
|
||||
// if (existingItem) {
|
||||
// const existingHighlights = existingItem.highlights || []
|
||||
|
||||
// remove duplicates
|
||||
const newHighlights =
|
||||
highlights?.filter(
|
||||
(highlight) =>
|
||||
!existingHighlights.find(
|
||||
(existingHighlight) => existingHighlight.quote === highlight.quote
|
||||
)
|
||||
) || []
|
||||
// // remove duplicates
|
||||
// const newHighlights =
|
||||
// highlights?.filter(
|
||||
// (highlight) =>
|
||||
// !existingHighlights.find(
|
||||
// (existingHighlight) => existingHighlight.quote === highlight.quote
|
||||
// )
|
||||
// ) || []
|
||||
|
||||
const existingRecommendations = existingItem.recommendations || []
|
||||
// return existingItem
|
||||
// }
|
||||
|
||||
// update recommendations in the existing item
|
||||
await updateLibraryItem(
|
||||
existingItem.id,
|
||||
{
|
||||
recommendations: existingRecommendations.concat(recommendation),
|
||||
highlights: existingHighlights.concat(newHighlights),
|
||||
},
|
||||
userId
|
||||
)
|
||||
if (!recommendedItem) {
|
||||
// create a new item
|
||||
const newItem: DeepPartial<LibraryItem> = {
|
||||
user: { id: userId },
|
||||
slug: item.slug,
|
||||
title: item.title,
|
||||
author: item.author,
|
||||
description: item.description,
|
||||
originalUrl: item.originalUrl,
|
||||
originalContent: item.originalContent,
|
||||
contentReader: item.contentReader,
|
||||
directionality: item.directionality,
|
||||
itemLanguage: item.itemLanguage,
|
||||
itemType: item.itemType,
|
||||
readableContent: item.readableContent,
|
||||
siteIcon: item.siteIcon,
|
||||
siteName: item.siteName,
|
||||
thumbnail: item.thumbnail,
|
||||
uploadFile: item.uploadFile,
|
||||
wordCount: item.wordCount,
|
||||
}
|
||||
|
||||
return existingItem
|
||||
recommendedItem = await createLibraryItem(newItem, userId)
|
||||
}
|
||||
|
||||
// create a new item
|
||||
const newItem: DeepPartial<LibraryItem> = {
|
||||
recommendations: [recommendation],
|
||||
user: { id: userId },
|
||||
highlights,
|
||||
slug: item.slug,
|
||||
title: item.title,
|
||||
author: item.author,
|
||||
description: item.description,
|
||||
originalUrl: item.originalUrl,
|
||||
originalContent: item.originalContent,
|
||||
contentReader: item.contentReader,
|
||||
directionality: item.directionality,
|
||||
itemLanguage: item.itemLanguage,
|
||||
itemType: item.itemType,
|
||||
readableContent: item.readableContent,
|
||||
siteIcon: item.siteIcon,
|
||||
siteName: item.siteName,
|
||||
thumbnail: item.thumbnail,
|
||||
uploadFile: item.uploadFile,
|
||||
wordCount: item.wordCount,
|
||||
const highlights = item.highlights
|
||||
?.filter((highlight) => highlightIds?.includes(highlight.id))
|
||||
.map((highlight) => ({
|
||||
shortId: nanoid(8),
|
||||
createdAt: new Date(),
|
||||
libraryItem: { id: recommendedItem?.id },
|
||||
user: { id: userId },
|
||||
quote: highlight.quote,
|
||||
annotation: highlight.annotation,
|
||||
prefix: highlight.prefix,
|
||||
suffix: highlight.suffix,
|
||||
patch: highlight.patch,
|
||||
updatedAt: new Date(),
|
||||
sharedAt: new Date(),
|
||||
html: highlight.html,
|
||||
color: highlight.color,
|
||||
}))
|
||||
if (highlights) {
|
||||
await createHighlights(highlights, recommendedItem.id, userId)
|
||||
}
|
||||
|
||||
return createLibraryItem(newItem, userId)
|
||||
await createRecommendation({
|
||||
...recommendation,
|
||||
libraryItem: { id: recommendedItem.id },
|
||||
})
|
||||
|
||||
return recommendedItem
|
||||
} catch (err) {
|
||||
logger.error('Error adding recommendation', err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const createRecommendation = async (
|
||||
recommendation: DeepPartial<Recommendation>
|
||||
) => {
|
||||
return getRepository(Recommendation).save(recommendation)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { CloudTasksClient, protos } from '@google-cloud/tasks'
|
|||
import { google } from '@google-cloud/tasks/build/protos/protos'
|
||||
import axios from 'axios'
|
||||
import { nanoid } from 'nanoid'
|
||||
import { DeepPartial } from 'typeorm'
|
||||
import { Recommendation } from '../entity/recommendation'
|
||||
import { Subscription } from '../entity/subscription'
|
||||
import { env } from '../env'
|
||||
|
|
@ -443,7 +444,7 @@ export const enqueueTextToSpeech = async ({
|
|||
export const enqueueRecommendation = async (
|
||||
userId: string,
|
||||
itemId: string,
|
||||
recommendation: Partial<Recommendation>,
|
||||
recommendation: DeepPartial<Recommendation>,
|
||||
authToken: string,
|
||||
highlightIds?: string[]
|
||||
): Promise<string> => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from elasticsearch.helpers import async_scan
|
|||
|
||||
PG_HOST = os.getenv('PG_HOST', 'localhost')
|
||||
PG_PORT = os.getenv('PG_PORT', 5432)
|
||||
PG_USER = os.getenv('PG_USER', 'app_user')
|
||||
PG_USER = os.getenv('PG_USER', 'hongbo')
|
||||
PG_PASSWORD = os.getenv('PG_PASSWORD', 'app_pass')
|
||||
PG_DB = os.getenv('PG_DB', 'omnivore')
|
||||
ES_URL = os.getenv('ES_URL', 'http://localhost:9200')
|
||||
|
|
|
|||
Loading…
Reference in a new issue