fix highlight tests

This commit is contained in:
Hongbo Wu 2023-09-07 16:43:24 +08:00
parent b036149fe2
commit 4b95b732cf
34 changed files with 489 additions and 429 deletions

View file

@ -1,4 +1,5 @@
import { DeepPartial } from 'typeorm'
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'
import { entityManager } from '.'
import { Highlight } from '../entity/highlight'
import { unescapeHtml } from '../utils/helpers'
@ -26,15 +27,22 @@ export const highlightRepository = entityManager
})
},
createAndSave(
highlight: DeepPartial<Highlight>,
libraryItemId: string,
userId: string
createAndSave(highlight: DeepPartial<Highlight>) {
return this.save(unescapeHighlight(highlight))
},
updateAndSave(
highlightId: string,
highlight: QueryDeepPartialEntity<Highlight>
) {
return this.save({
...unescapeHighlight(highlight),
user: { id: userId },
libraryItem: { id: libraryItemId },
return this.update(highlightId, {
...highlight,
annotation: highlight.annotation
? unescapeHtml(highlight.annotation.toString())
: undefined,
quote: highlight.quote
? unescapeHtml(highlight.quote.toString())
: undefined,
})
},
})

View file

@ -57,7 +57,7 @@ export const labelRepository = entityManager.getRepository(Label).extend({
.getMany()
},
findByIds(labelIds: string[]) {
findLabelsById(labelIds: string[]) {
return this.find({
where: { id: In(labelIds) },
select: ['id', 'name', 'color', 'description', 'createdAt'],

View file

@ -56,7 +56,11 @@ export const createHighlightResolver = authorized<
>(async (_, { input }, { log, pubsub, uid }) => {
try {
const newHighlight = await createHighlight(
input,
{
...input,
user: { id: uid },
libraryItem: { id: input.articleId },
},
input.articleId,
uid,
pubsub
@ -132,6 +136,8 @@ export const mergeHighlightResolver = authorized<
mergedAnnotations.length > 0 ? mergedAnnotations.join('\n') : null,
labels: mergedLabels,
color,
user: { id: uid },
libraryItem: { id: input.articleId },
}
const newHighlight = await mergeHighlights(
@ -171,7 +177,11 @@ export const updateHighlightResolver = authorized<
try {
const updatedHighlight = await updateHighlight(
input.highlightId,
input,
{
annotation: input.annotation,
html: input.html,
quote: input.quote,
},
uid,
pubsub
)

View file

@ -19,11 +19,11 @@ import {
SetIntegrationSuccess,
} from '../../generated/graphql'
import {
createIntegration,
findIntegration,
findIntegrations,
getIntegrationService,
removeIntegration,
saveIntegration,
updateIntegration,
} from '../../services/integrations'
import { analytics } from '../../utils/analytics'
@ -54,11 +54,6 @@ export const setIntegrationResolver = authorized<
errorCodes: [SetIntegrationErrorCode.NotFound],
}
}
if (existingIntegration.user.id !== uid) {
return {
errorCodes: [SetIntegrationErrorCode.Unauthorized],
}
}
integrationToSave.id = existingIntegration.id
integrationToSave.taskName = existingIntegration.taskName
@ -76,7 +71,7 @@ export const setIntegrationResolver = authorized<
}
// save integration
const integration = await createIntegration(integrationToSave, uid)
const integration = await saveIntegration(integrationToSave, uid)
if (
integrationToSave.type === IntegrationType.Export &&

View file

@ -96,7 +96,7 @@ export const createLabelResolver = authorized<
} catch (error) {
log.error('createLabelResolver', error)
return {
errorCodes: [CreateLabelErrorCode.BadRequest],
errorCodes: [CreateLabelErrorCode.LabelAlreadyExists],
}
}
})
@ -168,13 +168,8 @@ export const setLabelsResolver = authorized<
} else if (labelIds && labelIds.length > 0) {
// for old clients that send labelIds
labelsSet = await authTrx(async (tx) => {
return tx.withRepository(labelRepository).findByIds(labelIds)
return tx.withRepository(labelRepository).findLabelsById(labelIds)
})
if (labelsSet.length !== labelIds.length) {
return {
errorCodes: [SetLabelsErrorCode.NotFound],
}
}
}
// save labels in the library item
await saveLabelsInLibraryItem(labelsSet, pageId, uid, pubsub)
@ -195,7 +190,7 @@ export const setLabelsResolver = authorized<
} catch (error) {
log.error('setLabelsResolver error', error)
return {
errorCodes: [SetLabelsErrorCode.BadRequest],
errorCodes: [SetLabelsErrorCode.NotFound],
}
}
}
@ -230,7 +225,7 @@ export const updateLabelResolver = authorized<
if (!result.affected) {
log.error('failed to update')
return {
errorCodes: [UpdateLabelErrorCode.BadRequest],
errorCodes: [UpdateLabelErrorCode.NotFound],
}
}
@ -268,7 +263,7 @@ export const setLabelsForHighlightResolver = authorized<
} else if (labelIds && labelIds.length > 0) {
// for old clients that send labelIds
labelsSet = await authTrx(async (tx) => {
return tx.withRepository(labelRepository).findByIds(labelIds)
return tx.withRepository(labelRepository).findLabelsById(labelIds)
})
if (labelsSet.length !== labelIds.length) {
return {
@ -296,7 +291,7 @@ export const setLabelsForHighlightResolver = authorized<
} catch (error) {
log.error('setLabelsForHighlightResolver error', error)
return {
errorCodes: [SetLabelsErrorCode.BadRequest],
errorCodes: [SetLabelsErrorCode.NotFound],
}
}
})

View file

@ -12,6 +12,7 @@ import {
NewsletterEmailsErrorCode,
NewsletterEmailsSuccess,
} from '../../generated/graphql'
import { getRepository } from '../../repository'
import {
createNewsletterEmail,
deleteNewsletterEmail,
@ -78,7 +79,7 @@ export const deleteNewsletterEmailResolver = authorized<
DeleteNewsletterEmailSuccess,
DeleteNewsletterEmailError,
MutationDeleteNewsletterEmailArgs
>(async (_parent, args, { authTrx, uid, log }) => {
>(async (_parent, args, { uid, log }) => {
analytics.track({
userId: uid,
event: 'newsletter_email_address_deleted',
@ -88,14 +89,13 @@ export const deleteNewsletterEmailResolver = authorized<
})
try {
const newsletterEmail = await authTrx((t) =>
t.getRepository(NewsletterEmail).findOne({
where: {
id: args.newsletterEmailId,
},
relations: ['user', 'subscriptions'],
})
)
const newsletterEmail = await getRepository(NewsletterEmail).findOne({
where: {
id: args.newsletterEmailId,
user: { id: uid },
},
relations: ['user', 'subscriptions'],
})
if (!newsletterEmail) {
return {
@ -120,8 +120,8 @@ export const deleteNewsletterEmailResolver = authorized<
errorCodes: [DeleteNewsletterEmailErrorCode.NotFound],
}
}
} catch (e) {
log.info(e)
} catch (error) {
log.error('deleteNewsletterEmailResolver', error)
return {
errorCodes: [DeleteNewsletterEmailErrorCode.BadRequest],

View file

@ -67,7 +67,7 @@ export const saveUrlResolver = authorized<
return { errorCodes: [SaveErrorCode.Unauthorized] }
}
return saveUrl(ctx, user, input)
return saveUrl(input, user)
})
export const saveFileResolver = authorized<

View file

@ -7,7 +7,10 @@ import { readPushSubscription } from '../../pubsub'
import { authTrx } from '../../repository'
import { libraryItemRepository } from '../../repository/library_item'
import { updateLibraryItem } from '../../services/library_item'
import { setFileUploadComplete } from '../../services/upload_file'
import {
findUploadFileById,
setFileUploadComplete,
} from '../../services/upload_file'
import { logger } from '../../utils/logger'
interface UpdateContentMessage {
@ -54,18 +57,27 @@ export function contentServiceRouter() {
return
}
const libraryItem = await authTrx(async (tx) =>
tx
.withRepository(libraryItemRepository)
.createQueryBuilder('item')
.innerJoinAndSelect('item.user', 'user')
.innerJoinAndSelect('item.uploadFile', 'file')
.where('item.fileId = :fileId', { fileId })
.getOne()
const uploadFile = await findUploadFileById(fileId)
if (!uploadFile) {
logger.info('No file found')
res.status(404).send('No file found')
return
}
const libraryItem = await authTrx(
async (tx) =>
tx
.withRepository(libraryItemRepository)
.createQueryBuilder('item')
.innerJoinAndSelect('item.uploadFile', 'file')
.where('file.id = :fileId', { fileId })
.getOne(),
undefined,
uploadFile.user.id
)
if (!libraryItem) {
logger.info('No upload file found for id:', fileId)
res.status(400).send('Bad Request')
res.status(404).send('Bad Request')
return
}
@ -82,7 +94,7 @@ export function contentServiceRouter() {
try {
const uploadFileData = await setFileUploadComplete(
fileId,
libraryItem.user.id
uploadFile.user.id
)
logger.info('updated uploadFileData', uploadFileData)
} catch (error) {
@ -92,7 +104,7 @@ export function contentServiceRouter() {
const result = await updateLibraryItem(
libraryItem.id,
itemToUpdate,
libraryItem.user.id
uploadFile.user.id
)
logger.info(
'Updating library item text',

View file

@ -61,14 +61,17 @@ export function emailAttachmentRouter() {
})
try {
const uploadFileData = await authTrx((tx) =>
tx.getRepository(UploadFile).save({
url: '',
userId: user.id,
fileName: fileName,
status: UploadFileStatus.Initialized,
contentType: contentType,
})
const uploadFileData = await authTrx(
(tx) =>
tx.getRepository(UploadFile).save({
url: '',
userId: user.id,
fileName: fileName,
status: UploadFileStatus.Initialized,
contentType: contentType,
}),
undefined,
user.id
)
if (uploadFileData.id) {
@ -165,7 +168,7 @@ export function emailAttachmentRouter() {
const pageId = await createLibraryItem(articleToSave, user.id)
// update received email type
await updateReceivedEmail(receivedEmailId, 'article')
await updateReceivedEmail(receivedEmailId, 'article', user.id)
res.send({ id: pageId })
} catch (err) {

View file

@ -5,12 +5,15 @@ import { stringify } from 'csv-stringify'
import express from 'express'
import { DateTime } from 'luxon'
import { v4 as uuidv4 } from 'uuid'
import { Integration, IntegrationType } from '../../entity/integration'
import { IntegrationType } from '../../entity/integration'
import { LibraryItem } from '../../entity/library_item'
import { EntityType, readPushSubscription } from '../../pubsub'
import { getRepository } from '../../repository'
import { Claims } from '../../resolvers/types'
import { getIntegrationService } from '../../services/integrations'
import {
findIntegration,
getIntegrationService,
updateIntegration,
} from '../../services/integrations'
import {
findLibraryItemById,
searchLibraryItems,
@ -65,12 +68,14 @@ export function integrationsServiceRouter() {
return
}
const integration = await getRepository(Integration).findOneBy({
user: { id: userId },
name: req.params.integrationName.toUpperCase(),
type: IntegrationType.Export,
enabled: true,
})
const integration = await findIntegration(
{
name: req.params.integrationName.toUpperCase(),
type: IntegrationType.Export,
enabled: true,
},
userId
)
if (!integration) {
logger.info('No active integration found for user', { userId })
res.status(200).send('No integration found')
@ -158,9 +163,13 @@ export function integrationsServiceRouter() {
}
}
// delete task name if completed
await getRepository(Integration).update(integration.id, {
taskName: null,
})
await updateIntegration(
integration.id,
{
taskName: null,
},
userId
)
} else {
logger.info('unknown action', { action })
res.status(200).send('Unknown action')
@ -197,12 +206,14 @@ export function integrationsServiceRouter() {
let writeStream: NodeJS.WritableStream | undefined
try {
const userId = claims.uid
const integration = await getRepository(Integration).findOneBy({
user: { id: userId },
id: req.body.integrationId,
enabled: true,
type: IntegrationType.Import,
})
const integration = await findIntegration(
{
id: req.body.integrationId,
enabled: true,
type: IntegrationType.Import,
},
userId
)
if (!integration) {
logger.info('No active integration found for user', { userId })
return res.status(200).send('No integration found')
@ -270,10 +281,14 @@ export function integrationsServiceRouter() {
}
// update the integration's syncedAt and remove taskName
await getRepository(Integration).update(integration.id, {
syncedAt: new Date(syncedAt),
taskName: null,
})
await updateIntegration(
integration.id,
{
syncedAt: new Date(syncedAt),
taskName: null,
},
userId
)
} catch (err) {
logger.error('import pages from integration failed', err)
return res.status(500).send(err)

View file

@ -1,6 +1,6 @@
import express from 'express'
import { SubscriptionStatus } from '../../generated/graphql'
import { createPubSubClient, readPushSubscription } from '../../pubsub'
import { readPushSubscription } from '../../pubsub'
import {
findNewsletterEmail,
updateConfirmationCode,
@ -111,16 +111,12 @@ export function newsletterServiceRouter() {
return res.status(200).send('Not Found')
}
const saveCtx = {
pubsub: createPubSubClient(),
uid: newsletterEmail.user.id,
}
if (isUrl(data.title)) {
// save url if the title is a parsable url
const result = await saveUrlFromEmail(
saveCtx,
data.title,
data.receivedEmailId
data.receivedEmailId,
newsletterEmail.user.id
)
if (!result) {
return res.status(500).send('Error saving url from email')
@ -146,7 +142,11 @@ export function newsletterServiceRouter() {
}
// update received email type
await updateReceivedEmail(data.receivedEmailId, 'article')
await updateReceivedEmail(
data.receivedEmailId,
'article',
newsletterEmail.user.id
)
} catch (e) {
logger.error(e)
if (e instanceof SyntaxError) {

View file

@ -1,12 +1,3 @@
import { MulticastMessage } from 'firebase-admin/messaging'
import { appDataSource } from '../../data_source'
import { updatePage } from '../../elastic/pages'
import { UserDeviceToken } from '../../entity/user_device_tokens'
import { homePageURL } from '../../env'
import { ContentReader } from '../../generated/graphql'
import { createPubSubClient } from '../../pubsub'
import { setClaims } from '../../repository'
interface PageToNotify {
title: string
url: string

View file

@ -5,7 +5,7 @@ import axios, { Method } from 'axios'
import express from 'express'
import { Webhook } from '../../entity/webhook'
import { readPushSubscription } from '../../pubsub'
import { getRepository } from '../../repository'
import { authTrx } from '../../repository'
import { logger } from '../../utils/logger'
export function webhooksServiceRouter() {
@ -38,12 +38,18 @@ export function webhooksServiceRouter() {
// example: PAGE_CREATED
const eventType = `${type}_${req.params.action}`.toUpperCase()
const webhooks = await getRepository(Webhook)
.createQueryBuilder()
.where('user_id = :userId', { userId })
.andWhere(':eventType = ANY(event_types)', { eventType })
.andWhere('enabled = true')
.getMany()
const webhooks = await authTrx(
(t) =>
t
.getRepository(Webhook)
.createQueryBuilder()
.where('user_id = :userId', { userId })
.andWhere(':eventType = ANY(event_types)', { eventType })
.andWhere('enabled = true')
.getMany(),
undefined,
userId
)
if (webhooks.length <= 0) {
logger.info(

View file

@ -2,9 +2,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import cors from 'cors'
import express from 'express'
import { getRepository } from '../repository'
import { User } from '../entity/user'
import { env } from '../env'
import { userRepository } from '../repository/user'
import { getClaimsByToken, getTokenByRequest } from '../utils/auth'
import { corsConfig } from '../utils/corsConfig'
import { logger } from '../utils/logger'
@ -40,7 +39,7 @@ export function userRouter() {
return
}
try {
const user = await getRepository(User).findOneBy({ id: claims.uid })
const user = await userRepository.findOneBy({ id: claims.uid })
if (!user) {
res.status(400).send('Bad Request')
return

View file

@ -1,12 +1,15 @@
import { diff_match_patch } from 'diff-match-patch'
import { DeepPartial } from 'typeorm'
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'
import { Highlight } from '../entity/highlight'
import { homePageURL } from '../env'
import { createPubSubClient, EntityType } from '../pubsub'
import { authTrx } from '../repository'
import { highlightRepository } from '../repository/highlight'
type HighlightEvent = DeepPartial<Highlight> & { pageId: string }
type HighlightEvent = { id: string; pageId: string }
type CreateHighlightEvent = DeepPartial<Highlight> & HighlightEvent
type UpdateHighlightEvent = QueryDeepPartialEntity<Highlight> & HighlightEvent
export const getHighlightLocation = (patch: string): number | undefined => {
const dmp = new diff_match_patch()
@ -24,16 +27,13 @@ export const createHighlight = async (
pubsub = createPubSubClient()
) => {
const newHighlight = await authTrx(
async (tx) => {
return tx
.withRepository(highlightRepository)
.createAndSave(highlight, libraryItemId, userId)
},
async (tx) =>
tx.withRepository(highlightRepository).createAndSave(highlight),
undefined,
userId
)
await pubsub.entityCreated<HighlightEvent>(
await pubsub.entityCreated<CreateHighlightEvent>(
EntityType.HIGHLIGHT,
{ ...newHighlight, pageId: libraryItemId },
userId
@ -54,10 +54,10 @@ export const mergeHighlights = async (
await highlightRepo.delete(highlightsToRemove)
return highlightRepo.createAndSave(highlightToAdd, libraryItemId, userId)
return highlightRepo.createAndSave(highlightToAdd)
})
await pubsub.entityCreated<HighlightEvent>(
await pubsub.entityCreated<CreateHighlightEvent>(
EntityType.HIGHLIGHT,
{ ...newHighlight, pageId: libraryItemId },
userId
@ -68,23 +68,20 @@ export const mergeHighlights = async (
export const updateHighlight = async (
highlightId: string,
highlight: DeepPartial<Highlight>,
highlight: QueryDeepPartialEntity<Highlight>,
userId: string,
pubsub = createPubSubClient()
) => {
const updatedHighlight = await authTrx(async (tx) => {
const highlightRepo = tx.withRepository(highlightRepository)
await highlightRepo.save({
...highlight,
id: highlightId,
})
await highlightRepo.updateAndSave(highlightId, highlight)
return highlightRepo.findOneByOrFail({
id: highlightId,
})
})
await pubsub.entityUpdated<HighlightEvent>(
await pubsub.entityUpdated<UpdateHighlightEvent>(
EntityType.HIGHLIGHT,
{ ...highlight, id: highlightId, pageId: updatedHighlight.libraryItem.id },
userId

View file

@ -62,7 +62,7 @@ export const findIntegrations = async (
)
}
export const createIntegration = async (
export const saveIntegration = async (
integration: DeepPartial<Integration>,
userId: string
) => {

View file

@ -5,7 +5,7 @@ import {
CreateNewsletterEmailErrorCode,
SubscriptionStatus,
} from '../generated/graphql'
import { authTrx } from '../repository'
import { getRepository } from '../repository'
import { userRepository } from '../repository/user'
import addressparser = require('nodemailer/lib/addressparser')
@ -33,44 +33,34 @@ export const createNewsletterEmail = async (
// generate a random email address with username prefix
const emailAddress = createRandomEmailAddress(user.profile.username, 8)
return authTrx(
(t) =>
t.getRepository(NewsletterEmail).save({
address: emailAddress,
user,
confirmationCode,
}),
undefined,
userId
)
return getRepository(NewsletterEmail).save({
address: emailAddress,
user,
confirmationCode,
})
}
export const getNewsletterEmails = async (
userId: string
): Promise<NewsletterEmail[]> => {
return authTrx((t) =>
t
.getRepository(NewsletterEmail)
.createQueryBuilder('newsletter_email')
.leftJoinAndSelect('newsletter_email.user', 'user')
.leftJoinAndSelect(
'newsletter_email.subscriptions',
'subscriptions',
'subscriptions.status = :status',
{
status: SubscriptionStatus.Active,
}
)
.where('newsletter_email.user = :userId', { userId })
.orderBy('newsletter_email.createdAt', 'DESC')
.getMany()
)
return getRepository(NewsletterEmail)
.createQueryBuilder('newsletter_email')
.leftJoinAndSelect('newsletter_email.user', 'user')
.leftJoinAndSelect(
'newsletter_email.subscriptions',
'subscriptions',
'subscriptions.status = :status',
{
status: SubscriptionStatus.Active,
}
)
.where('newsletter_email.user = :userId', { userId })
.orderBy('newsletter_email.createdAt', 'DESC')
.getMany()
}
export const deleteNewsletterEmail = async (id: string): Promise<boolean> => {
const result = await authTrx((t) =>
t.getRepository(NewsletterEmail).delete(id)
)
const result = await getRepository(NewsletterEmail).delete(id)
return !!result.affected
}
@ -80,16 +70,13 @@ export const updateConfirmationCode = async (
confirmationCode: string
): Promise<boolean> => {
const address = parsedAddress(emailAddress)
const result = await authTrx((t) =>
t
.getRepository(NewsletterEmail)
.createQueryBuilder()
.where('address ILIKE :address', { address })
.update({
confirmationCode: confirmationCode,
})
.execute()
)
const result = await getRepository(NewsletterEmail)
.createQueryBuilder()
.where('address ILIKE :address', { address })
.update({
confirmationCode: confirmationCode,
})
.execute()
return !!result.affected
}
@ -98,14 +85,11 @@ export const findNewsletterEmail = async (
emailAddress: string
): Promise<NewsletterEmail | null> => {
const address = parsedAddress(emailAddress)
return authTrx((t) =>
t
.getRepository(NewsletterEmail)
.createQueryBuilder('newsletter_email')
.innerJoinAndSelect('newsletter_email.user', 'user')
.where('address ILIKE :address', { address })
.getOne()
)
return getRepository(NewsletterEmail)
.createQueryBuilder('newsletter_email')
.innerJoinAndSelect('newsletter_email.user', 'user')
.where('address ILIKE :address', { address })
.getOne()
}
const createRandomEmailAddress = (userName: string, length: number): string => {
@ -126,9 +110,5 @@ export const getNewsletterEmailById = async (
id: string,
userId: string
): Promise<NewsletterEmail | null> => {
return authTrx(
(t) => t.getRepository(NewsletterEmail).findOneBy({ id }),
undefined,
userId
)
return getRepository(NewsletterEmail).findOneBy({ id, user: { id: userId } })
}

View file

@ -10,22 +10,46 @@ export const saveReceivedEmail = async (
userId: string,
type: 'article' | 'non-article' = 'non-article'
): Promise<ReceivedEmail> => {
return authTrx((t) =>
t.getRepository(ReceivedEmail).save({
from,
to,
subject,
text,
html,
type,
user: { id: userId },
})
return authTrx(
(t) =>
t.getRepository(ReceivedEmail).save({
from,
to,
subject,
text,
html,
type,
user: { id: userId },
}),
undefined,
userId
)
}
export const updateReceivedEmail = async (
id: string,
type: 'article' | 'non-article'
type: 'article' | 'non-article',
userId?: string
) => {
return authTrx((t) => t.getRepository(ReceivedEmail).update(id, { type }))
return authTrx(
(t) => t.getRepository(ReceivedEmail).update(id, { type }),
undefined,
userId
)
}
export const deleteReceivedEmail = async (id: string, userId?: string) => {
return authTrx(
(t) => t.getRepository(ReceivedEmail).delete(id),
undefined,
userId
)
}
export const findReceivedEmailById = async (id: string, userId?: string) => {
return authTrx(
(t) => t.getRepository(ReceivedEmail).findOneBy({ id }),
undefined,
userId
)
}

View file

@ -1,26 +1,18 @@
import { User } from '../entity/user'
import { homePageURL } from '../env'
import { SaveErrorCode, SaveResult, SaveUrlInput } from '../generated/graphql'
import { PubsubClient } from '../pubsub'
import { userRepository } from '../repository/user'
import { logger } from '../utils/logger'
import { createPageSaveRequest } from './create_page_save_request'
interface SaveContext {
pubsub: PubsubClient
uid: string
}
export const saveUrl = async (
ctx: SaveContext,
user: User,
input: SaveUrlInput
input: SaveUrlInput,
user: User
): Promise<SaveResult> => {
try {
const pageSaveRequest = await createPageSaveRequest({
...input,
userId: ctx.uid,
pubsub: ctx.pubsub,
userId: user.id,
articleSavingRequestId: input.clientRequestId,
state: input.state || undefined,
labels: input.labels || undefined,
@ -46,22 +38,25 @@ export const saveUrl = async (
}
export const saveUrlFromEmail = async (
ctx: SaveContext,
url: string,
clientRequestId: string
clientRequestId: string,
userId: string
): Promise<boolean> => {
const user = await userRepository.findOneBy({
id: ctx.uid,
id: userId,
})
if (!user) {
return false
}
const result = await saveUrl(ctx, user, {
url,
clientRequestId,
source: 'email',
})
const result = await saveUrl(
{
url,
clientRequestId,
source: 'email',
},
user
)
if (result.__typename === 'SaveError') {
return false
}

View file

@ -2,7 +2,12 @@ import { UploadFile } from '../entity/upload_file'
import { authTrx, getRepository } from '../repository'
export const findUploadFileById = async (id: string) => {
return getRepository(UploadFile).findOneBy({ id })
return getRepository(UploadFile).findOne({
where: { id },
relations: {
user: true,
},
})
}
export const setFileUploadComplete = async (id: string, userId?: string) => {

View file

@ -19,10 +19,13 @@ export const findDeviceTokenByToken = async (
export const findDeviceTokensByUserId = async (
userId: string
): Promise<UserDeviceToken[]> => {
return authTrx((t) =>
t.getRepository(UserDeviceToken).findBy({
user: { id: userId },
})
return authTrx(
(t) =>
t.getRepository(UserDeviceToken).findBy({
user: { id: userId },
}),
undefined,
userId
)
}

View file

@ -25,3 +25,19 @@ export const createWebhook = async (
userId
)
}
export const findWebhooks = async (userId?: string) => {
return authTrx(
(tx) => tx.getRepository(Webhook).findBy({ user: { id: userId } }),
undefined,
userId
)
}
export const findWebhookById = async (id: string, userId?: string) => {
return authTrx(
(tx) => tx.getRepository(Webhook).findBy({ id }),
undefined,
userId
)
}

View file

@ -11,8 +11,10 @@ import { getRepository } from '../src/repository'
import { userRepository } from '../src/repository/user'
import { createUser } from '../src/services/create_user'
import { Filter } from "../src/entity/filter"
import { saveLabelsInLibraryItem } from '../src/services/labels'
import { createLibraryItem } from '../src/services/library_item'
import { createDeviceToken } from '../src/services/user_device_tokens'
import { generateFakeUuid } from './util'
const runMigrations = async () => {
const migrationDirectory = __dirname + '/../../db/migrations'
@ -133,10 +135,14 @@ export const createTestLibraryItem = async (
user: { id: userId },
title: 'test title',
originalContent: '<p>test content</p>',
originalUrl: 'https://blog.omnivore.app/test-url',
originalUrl: `https://blog.omnivore.app/test-url-${generateFakeUuid()}`,
slug: 'test-with-omnivore',
labels,
}
return createLibraryItem(item, userId)
const createdItem = await createLibraryItem(item, userId)
if (labels) {
await saveLabelsInLibraryItem(labels, createdItem.id, userId)
}
return createdItem
}

View file

@ -1,16 +1,13 @@
import { createTestLibraryItem, createTestUser } from '../db'
import {
generateFakeUuid,
graphqlRequest,
request,
} from '../util'
import * as chai from 'chai'
import { expect } from 'chai'
import chaiString from 'chai-string'
import 'mocha'
import { User } from '../../src/entity/user'
import chaiString from 'chai-string'
import { createHighlight } from '../../src/services/highlights'
import { updateLibraryItem } from '../../src/services/library_item'
import { deleteUser } from '../../src/services/user'
import { createTestLibraryItem, createTestUser } from '../db'
import { generateFakeUuid, graphqlRequest, request } from '../util'
chai.use(chaiString)
@ -140,7 +137,7 @@ const updateHighlightQuery = ({
describe('Highlights API', () => {
let authToken: string
let user: User
let pageId: string
let itemId: string
before(async () => {
// create test user and login
@ -150,7 +147,7 @@ describe('Highlights API', () => {
.send({ fakeEmail: user.email })
authToken = res.body.authToken
pageId = (await createTestLibraryItem(user.id)).id
itemId = (await createTestLibraryItem(user.id)).id
})
after(async () => {
@ -165,7 +162,7 @@ describe('Highlights API', () => {
const highlightPositionAnchorIndex = 15
const html = '<p>test</p>'
const query = createHighlightQuery(
pageId,
itemId,
highlightId,
shortHighlightId,
highlightPositionPercent,
@ -192,7 +189,7 @@ describe('Highlights API', () => {
const highlightPositionPercent = 50.0
const highlightPositionAnchorIndex = 25
const query = createHighlightQuery(
pageId,
itemId,
newHighlightId,
newShortHighlightId,
highlightPositionPercent,
@ -214,7 +211,7 @@ describe('Highlights API', () => {
// create test highlight
highlightId = generateFakeUuid()
const shortHighlightId = '_short_id_1'
const query = createHighlightQuery(pageId, highlightId, shortHighlightId)
const query = createHighlightQuery(itemId, highlightId, shortHighlightId)
await graphqlRequest(query, authToken).expect(200)
})
@ -224,7 +221,7 @@ describe('Highlights API', () => {
const highlightPositionPercent = 50.0
const highlightPositionAnchorIndex = 25
const query = mergeHighlightQuery(
pageId,
itemId,
newHighlightId,
newShortHighlightId,
[highlightId],
@ -248,23 +245,16 @@ describe('Highlights API', () => {
before(async () => {
// create test highlight
highlightId = generateFakeUuid()
await updateLibraryItem(
pageId,
const highlight = await createHighlight(
{
highlights: [
{
id: highlightId,
shortId: '_short_id_3',
annotation: '',
patch: '',
quote: '',
user,
},
],
libraryItem: { id: itemId },
shortId: '_short_id_3',
user,
},
itemId,
user.id
)
highlightId = highlight.id
})
it('updates the quote when the quote is in HTML format when the annotation has HTML reserved characters', async () => {

View file

@ -6,9 +6,9 @@ import { Integration } from '../../src/entity/integration'
import { User } from '../../src/entity/user'
import { SetIntegrationErrorCode } from '../../src/generated/graphql'
import {
createIntegration,
deleteIntegrations,
findIntegration,
saveIntegration,
updateIntegration,
} from '../../src/services/integrations'
import { READWISE_API_URL } from '../../src/services/integrations/readwise'
@ -168,11 +168,14 @@ describe('Integrations resolvers', () => {
before(async () => {
otherUser = await createTestUser('otherUser')
existingIntegration = await createIntegration({
user: { id: otherUser.id },
name: 'READWISE',
token: 'fakeToken',
}, otherUser.id)
existingIntegration = await saveIntegration(
{
user: { id: otherUser.id },
name: 'READWISE',
token: 'fakeToken',
},
otherUser.id
)
integrationId = existingIntegration.id
})
@ -187,18 +190,21 @@ describe('Integrations resolvers', () => {
authToken
)
expect(res.body.data.setIntegration.errorCodes).to.eql([
SetIntegrationErrorCode.Unauthorized,
SetIntegrationErrorCode.NotFound,
])
})
})
context('when integration belongs to the user', () => {
before(async () => {
existingIntegration = await createIntegration({
user: { id: loginUser.id },
name: 'READWISE',
token: 'fakeToken',
}, loginUser.id)
existingIntegration = await saveIntegration(
{
user: { id: loginUser.id },
name: 'READWISE',
token: 'fakeToken',
},
loginUser.id
)
integrationId = existingIntegration.id
})
@ -294,11 +300,14 @@ describe('Integrations resolvers', () => {
let existingIntegration: Integration
before(async () => {
existingIntegration = await createIntegration({
user: { id: loginUser.id },
name: 'READWISE',
token: 'fakeToken',
}, loginUser.id)
existingIntegration = await saveIntegration(
{
user: { id: loginUser.id },
name: 'READWISE',
token: 'fakeToken',
},
loginUser.id
)
})
after(async () => {
@ -340,12 +349,15 @@ describe('Integrations resolvers', () => {
let existingIntegration: Integration
beforeEach(async () => {
existingIntegration = await createIntegration({
user: { id: loginUser.id },
name: 'READWISE',
token: 'fakeToken',
taskName: 'some task name',
}, loginUser.id)
existingIntegration = await saveIntegration(
{
user: { id: loginUser.id },
name: 'READWISE',
token: 'fakeToken',
taskName: 'some task name',
},
loginUser.id
)
})
it('deletes the integration and cloud task', async () => {
@ -383,11 +395,14 @@ describe('Integrations resolvers', () => {
context('when integration exists', () => {
before(async () => {
existingIntegration = await createIntegration({
user: { id: loginUser.id },
name: 'POCKET',
token: 'fakeToken',
}, loginUser.id)
existingIntegration = await saveIntegration(
{
user: { id: loginUser.id },
name: 'POCKET',
token: 'fakeToken',
},
loginUser.id
)
})
after(async () => {

View file

@ -43,8 +43,8 @@ describe('Labels API', () => {
before(async () => {
// create testing labels
const label1 = await createLabel(user.id, 'label_1', '#ffffff')
const label2 = await createLabel(user.id, 'label_2', '#eeeeee')
const label1 = await createLabel('label_1', '#ffffff', user.id)
const label2 = await createLabel('label_2', '#eeeeee', user.id)
labels = [label1, label2]
})
@ -159,7 +159,7 @@ describe('Labels API', () => {
let existingLabel: Label
before(async () => {
existingLabel = await createLabel(user.id, 'label3', '#ffffff')
existingLabel = await createLabel('label3', '#ffffff', user.id)
name = existingLabel.name
})
@ -219,9 +219,9 @@ describe('Labels API', () => {
context('when label is not used', () => {
before(async () => {
toDeleteLabel = await createLabel(
user.id,
'label not in use',
'#ffffff'
'#ffffff',
user.id
)
labelId = toDeleteLabel.id
})
@ -237,7 +237,7 @@ describe('Labels API', () => {
let item: LibraryItem
before(async () => {
toDeleteLabel = await createLabel(user.id, 'page label', '#ffffff')
toDeleteLabel = await createLabel('page label', '#ffffff', user.id)
labelId = toDeleteLabel.id
item = await createTestLibraryItem(user.id, [toDeleteLabel])
})
@ -261,9 +261,9 @@ describe('Labels API', () => {
before(async () => {
item = await createTestLibraryItem(user.id)
toDeleteLabel = await createLabel(
user.id,
'highlight label',
'#ffffff'
'#ffffff',
user.id
)
labelId = toDeleteLabel.id
const highlight: DeepPartial<Highlight> = {
@ -326,8 +326,8 @@ describe('Labels API', () => {
before(async () => {
// create testing labels
const label1 = await createLabel(user.id, 'label_1', '#ffffff')
const label2 = await createLabel(user.id, 'label_2', '#eeeeee')
const label1 = await createLabel('label_1', '#ffffff', user.id)
const label2 = await createLabel('label_2', '#eeeeee', user.id)
labels = [label1, label2]
item = await createTestLibraryItem(user.id)
})
@ -454,7 +454,7 @@ describe('Labels API', () => {
let toUpdateLabel: Label
before(async () => {
toUpdateLabel = await createLabel(user.id, 'label5', '#ffffff')
toUpdateLabel = await createLabel('label5', '#ffffff', user.id)
labelId = toUpdateLabel.id
name = 'Updated label'
color = '#aabbcc'
@ -529,8 +529,8 @@ describe('Labels API', () => {
before(async () => {
// create testing labels
const label1 = await createLabel(user.id, 'label_1', '#ffffff')
const label2 = await createLabel(user.id, 'label_2', '#eeeeee')
const label1 = await createLabel('label_1', '#ffffff', user.id)
const label2 = await createLabel('label_2', '#eeeeee', user.id)
labels = [label1, label2]
item = await createTestLibraryItem(user.id)
})
@ -572,15 +572,14 @@ describe('Labels API', () => {
context('when labels exists', () => {
before(async () => {
highlightId = generateFakeUuid()
const highlight: DeepPartial<Highlight> = {
id: highlightId,
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
shortId: generateFakeUuid(),
user,
}
await createHighlight(highlight, item.id, user.id)
highlightId = (await createHighlight(highlight, item.id, user.id)).id
labelIds = [labels[0].id, labels[1].id]
})
@ -594,15 +593,13 @@ describe('Labels API', () => {
context('when labels not exist', () => {
before(async () => {
highlightId = generateFakeUuid()
const highlight: DeepPartial<Highlight> = {
id: highlightId,
patch: 'test patch',
quote: 'test quote',
shortId: 'test shortId',
shortId: generateFakeUuid(),
user,
}
await createHighlight(highlight, item.id, user.id)
highlightId = (await createHighlight(highlight, item.id, user.id)).id
labelIds = [generateFakeUuid(), generateFakeUuid()]
})
@ -657,7 +654,7 @@ describe('Labels API', () => {
before(async () => {
// create testing labels
for (let i = 0; i < 5; i++) {
const label = await createLabel(user.id, `label_${i}`, '#ffffff')
const label = await createLabel(`label_${i}`, '#ffffff', user.id)
labels.push(label)
}
})

View file

@ -5,6 +5,11 @@ import { NewsletterEmail } from '../../src/entity/newsletter_email'
import { ReceivedEmail } from '../../src/entity/received_email'
import { User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import {
deleteReceivedEmail,
findReceivedEmailById,
saveReceivedEmail,
} from '../../src/services/received_emails'
import { deleteUser } from '../../src/services/user'
import * as sendEmail from '../../src/utils/sendEmail'
import { createTestUser } from '../db'
@ -66,24 +71,24 @@ describe('Recent Emails Resolver', () => {
describe('recentEmails', () => {
before(async () => {
// create fake emails
const recentEmail = await getRepository(ReceivedEmail).save({
user: { id: user.id },
from: 'fake from',
subject: 'fake subject',
text: 'fake text',
html: 'fake html',
to: newsletterEmail.address,
type: 'article',
})
const recentEmail2 = await getRepository(ReceivedEmail).save({
user: { id: user.id },
from: 'fake from 2',
subject: 'fake subject 2',
text: 'fake text 2',
html: 'fake html 2',
to: newsletterEmail2.address,
type: 'non-article',
})
const recentEmail = await saveReceivedEmail(
'fake from',
newsletterEmail.address,
'fake subject',
'fake text',
'fake html',
user.id,
'article'
)
const recentEmail2 = await saveReceivedEmail(
'fake from 2',
newsletterEmail2.address,
'fake subject 2',
'fake text 2',
'fake html 2',
user.id,
'non-article'
)
recentEmails = [recentEmail, recentEmail2]
})
@ -115,21 +120,21 @@ describe('Recent Emails Resolver', () => {
before(async () => {
// create fake email
recentEmail = await getRepository(ReceivedEmail).save({
user: { id: user.id },
from: 'Omnivore Newsletter <newsletter@omnivore.app>',
subject: 'fake subject 3',
text: 'fake text 3',
html: '<html><body>fake html 3</body></html>',
to: newsletterEmail.address,
type: 'non-article',
})
recentEmail = await saveReceivedEmail(
'Omnivore Newsletter <newsletter@omnivore.app>',
newsletterEmail.address,
'fake subject 3',
'fake text 3',
'fake html 3',
user.id,
'non-article'
)
sinon.replace(sendEmail, 'sendEmail', sinon.fake.resolves(true))
})
after(async () => {
// clean up
await getRepository(ReceivedEmail).delete(recentEmail.id)
await deleteReceivedEmail(recentEmail.id, user.id)
sinon.restore()
})
@ -141,9 +146,7 @@ describe('Recent Emails Resolver', () => {
expect(resp.body.data.markEmailAsItem.success).to.be.true
const updatedRecentEmail = await getRepository(ReceivedEmail).findOneBy({
id: recentEmail.id,
})
const updatedRecentEmail = await findReceivedEmailById(recentEmail.id)
expect(updatedRecentEmail?.type).to.eql('article')
})
})
@ -169,24 +172,26 @@ describe('Recent Emails Resolver', () => {
before(async () => {
// create fake emails
const recentEmail = await getRepository(ReceivedEmail).save({
user: { id: user2.id },
from: 'fake from',
subject: 'fake subject',
text: 'fake text',
html: 'fake html',
to: newsletterEmail.address,
type: 'article',
})
const recentEmail2 = await getRepository(ReceivedEmail).save({
user: { id: user2.id },
from: 'fake from 2',
subject: 'fake subject 2',
text: 'fake text 2',
html: 'fake html 2',
to: newsletterEmail2.address,
type: 'non-article',
})
const recentEmail = await saveReceivedEmail(
'fake from 4',
newsletterEmail.address,
'fake subject 4',
'fake text 4',
'fake html 4',
user2.id,
'article'
)
const recentEmail2 = await saveReceivedEmail(
'fake from 4',
newsletterEmail.address,
'fake subject 4',
'fake text 4',
'fake html 4',
user2.id,
'non-article'
)
recentEmails = [recentEmail, recentEmail2]
})
@ -198,15 +203,15 @@ describe('Recent Emails Resolver', () => {
expect(results[0].id).to.eql(recentEmails[1].id)
expect(results[1].id).to.eql(recentEmails[0].id)
await getRepository(ReceivedEmail).save({
user: { id: user3.id },
from: 'fake from',
subject: 'fake subject',
text: 'fake text',
html: 'fake html',
to: newsletterEmail.address,
type: 'article',
})
await saveReceivedEmail(
'fake from 5',
newsletterEmail.address,
'fake subject 5',
'fake text 5',
'fake html 5',
user3.id,
'article'
)
const res2 = await graphqlRequest(recentEmailsQuery, user2Auth).expect(
200

View file

@ -95,7 +95,7 @@ describe('Rules Resolver', () => {
t.getRepository(Rule).save({
user: { id: user.id },
name: 'test rule',
filter: 'test filter',
filter: 'test filter 2',
actions: [{ type: RuleActionType.SendNotification, params: [] }],
enabled: true,
}),
@ -148,7 +148,7 @@ describe('Rules Resolver', () => {
t.getRepository(Rule).save({
user: { id: user.id },
name: 'test rule',
filter: 'test filter',
filter: 'test filter 3',
actions: [{ type: RuleActionType.SendNotification, params: [] }],
enabled: true,
}),

View file

@ -3,9 +3,13 @@ import 'mocha'
import { User } from '../../src/entity/user'
import { Webhook } from '../../src/entity/webhook'
import { WebhookEvent } from '../../src/generated/graphql'
import { getRepository } from '../../src/repository'
import { deleteUser } from '../../src/services/user'
import { createWebhooks } from '../../src/services/webhook'
import {
createWebhook,
createWebhooks,
findWebhookById,
findWebhooks,
} from '../../src/services/webhook'
import { createTestUser } from '../db'
import { graphqlRequest, request } from '../util'
@ -50,11 +54,14 @@ describe('Webhooks API', () => {
before(async () => {
// create test webhooks
webhook = await getRepository(Webhook).save({
url: 'http://localhost:3000/webhooks/test',
user: { id: user.id },
eventTypes: [WebhookEvent.PageDeleted],
})
webhook = await createWebhook(
{
url: 'http://localhost:3000/webhooks/test',
user: { id: user.id },
eventTypes: [WebhookEvent.PageDeleted],
},
user.id
)
})
it('should return a webhook', async () => {
@ -102,9 +109,7 @@ describe('Webhooks API', () => {
`
const res = await graphqlRequest(query, authToken)
const webhooks = await getRepository(Webhook).findBy({
user: { id: user.id },
})
const webhooks = await findWebhooks(user.id)
expect(res.body.data.webhooks.webhooks).to.eql(
webhooks.map((w) => ({
@ -171,11 +176,15 @@ describe('Webhooks API', () => {
context('when id is there', () => {
before(async () => {
const webhook = await getRepository(Webhook).save({
url: 'http://localhost:3000/webhooks/test',
user: { id: user.id },
eventTypes: [WebhookEvent.HighlightUpdated],
})
const webhook = await createWebhook(
{
url: 'http://localhost:3000/webhooks/test',
user: { id: user.id },
eventTypes: [WebhookEvent.HighlightUpdated],
},
user.id
)
webhookId = webhook.id
webhookUrl = 'http://localhost:3000/webhooks/test_2'
eventTypes = [
@ -219,19 +228,20 @@ describe('Webhooks API', () => {
context('when webhook exists', () => {
before(async () => {
const webhook = await getRepository(Webhook).save({
url: 'http://localhost:3000/webhooks/test',
user: { id: user.id },
eventTypes: [WebhookEvent.LabelCreated],
})
const webhook = await createWebhook(
{
url: 'http://localhost:3000/webhooks/test',
user: { id: user.id },
eventTypes: [WebhookEvent.LabelCreated],
},
user.id
)
webhookId = webhook.id
})
it('should delete a webhook', async () => {
const res = await graphqlRequest(query, authToken)
const webhook = await getRepository(Webhook).findOneBy({
id: webhookId,
})
const webhook = await findWebhookById(webhookId, user.id)
expect(res.body.data.deleteWebhook.webhook).to.be.an('object')
expect(res.body.data.deleteWebhook.webhook.id).to.eql(webhookId)

View file

@ -56,7 +56,7 @@ describe('auth router', () => {
})
afterEach(async () => {
const user = await getRepository(User).findOneBy({ name })
const user = await userRepository.findOneBy({ name })
await deleteUser(user!.id)
})
@ -83,7 +83,7 @@ describe('auth router', () => {
it('creates the user with pending status and correct name', async () => {
await signupRequest(email, password, name, username).expect(302)
const user = await getRepository(User).findOneBy({ name })
const user = await userRepository.findOneBy({ name })
expect(user?.status).to.eql(StatusType.Pending)
expect(user?.name).to.eql(name)

View file

@ -4,8 +4,8 @@ import 'mocha'
import sinon from 'sinon'
import { ReceivedEmail } from '../../src/entity/received_email'
import { User } from '../../src/entity/user'
import { getRepository } from '../../src/repository'
import { createNewsletterEmail } from '../../src/services/newsletters'
import { saveReceivedEmail } from '../../src/services/received_emails'
import { deleteUser } from '../../src/services/user'
import * as parser from '../../src/utils/parser'
import * as sendEmail from '../../src/utils/sendEmail'
@ -30,15 +30,15 @@ describe('Emails Router', () => {
await createNewsletterEmail(user.id, newsletterEmail)
token = process.env.PUBSUB_VERIFICATION_TOKEN!
receivedEmail = await getRepository(ReceivedEmail).save({
user: { id: user.id },
receivedEmail = await saveReceivedEmail(
from,
to,
subject,
text,
html: '',
type: 'non-article',
})
'',
user.id,
'non-article'
)
})
after(async () => {

View file

@ -10,9 +10,12 @@ import { LibraryItem } from '../../src/entity/library_item'
import { User } from '../../src/entity/user'
import { env } from '../../src/env'
import { PubSubRequestBody } from '../../src/pubsub'
import { authTrx, getRepository } from '../../src/repository'
import { createHighlight, getHighlightUrl } from '../../src/services/highlights'
import { deleteIntegrations } from '../../src/services/integrations'
import {
deleteIntegrations,
saveIntegration,
updateIntegration,
} from '../../src/services/integrations'
import { READWISE_API_URL } from '../../src/services/integrations/readwise'
import { deleteLibraryItemById } from '../../src/services/library_item'
import { deleteUser } from '../../src/services/user'
@ -127,14 +130,12 @@ describe('Integrations routers', () => {
let highlightsData: string
before(async () => {
integration = await authTrx(
(t) =>
t.getRepository(Integration).save({
user: { id: user.id },
name: 'READWISE',
token: 'token',
}),
undefined,
integration = await saveIntegration(
{
user: { id: user.id },
name: 'READWISE',
token: 'token',
},
user.id
)
integrationName = integration.name
@ -309,10 +310,14 @@ describe('Integrations routers', () => {
})
.post('/highlights', highlightsData)
.reply(200)
await getRepository(Integration).update(integration.id, {
syncedAt: null,
taskName: 'some task name',
})
await updateIntegration(
integration.id,
{
syncedAt: null,
taskName: 'some task name',
},
user.id
)
})
it('returns 200 with OK', async () => {
@ -334,15 +339,13 @@ describe('Integrations routers', () => {
before(async () => {
token = 'test token'
// create integration
integration = await authTrx(
(t) =>
t.getRepository(Integration).save({
user: { id: user.id },
name: 'POCKET',
token,
type: IntegrationType.Import,
}),
undefined,
integration = await saveIntegration(
{
user: { id: user.id },
name: 'POCKET',
token,
type: IntegrationType.Import,
},
user.id
)

View file

@ -16,12 +16,6 @@ CREATE POLICY integrations_policy on omnivore.integrations
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.integrations TO omnivore_user;
ALTER TABLE omnivore.newsletter_emails ENABLE ROW LEVEL SECURITY;
CREATE POLICY newsletter_emails_policy on omnivore.newsletter_emails
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, DELETE ON omnivore.newsletter_emails TO omnivore_user;
CREATE POLICY labels_policy on omnivore.labels
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
@ -49,12 +43,4 @@ CREATE POLICY user_device_tokens_policy on omnivore.user_device_tokens
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, DELETE ON omnivore.user_device_tokens TO omnivore_user;
ALTER TABLE omnivore.search_history ENABLE ROW LEVEL SECURITY;
CREATE POLICY search_history_policy on omnivore.search_history
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, DELETE ON omnivore.search_history TO omnivore_user;
COMMIT;

View file

@ -10,9 +10,6 @@ DROP POLICY filters_policy on omnivore.filters;
ALTER TABLE omnivore.integrations DISABLE ROW LEVEL SECURITY;
DROP POLICY integrations_policy on omnivore.integrations;
ALTER TABLE omnivore.newsletter_emails DISABLE ROW LEVEL SECURITY;
DROP POLICY newsletter_emails_policy on omnivore.newsletter_emails;
DROP POLICY labels_policy on omnivore.labels;
ALTER TABLE omnivore.received_emails DISABLE ROW LEVEL SECURITY;
@ -26,7 +23,4 @@ DROP POLICY webhooks_policy on omnivore.webhooks;
DROP POLICY user_device_tokens_policy on omnivore.user_device_tokens;
ALTER TABLE omnivore.search_history DISABLE ROW LEVEL SECURITY;
DROP POLICY search_history_policy on omnivore.search_history;
COMMIT;