Skip to content

Commit

Permalink
Merge branch 'main' into customValidatorTest
Browse files Browse the repository at this point in the history
  • Loading branch information
icemedia001 authored Oct 28, 2024
2 parents bd41f23 + 611bba7 commit 860fd25
Show file tree
Hide file tree
Showing 53 changed files with 1,463 additions and 828 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"apollo-server-fastify": "^3.13.0",
"arweave": "^1.15.1",
"axios": "^1.3.1",
"cache-manager": "^3.6.1",
"cache-manager": "^4.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cron": "^2.3.1",
Expand All @@ -81,6 +81,7 @@
"got": "^12.5.3",
"graphql": "^16.3.0",
"graphql-request": "^4.0.0",
"graphql-subscriptions": "^2.0.0",
"graphql-tag": "^2.12.6",
"graphql-upload": "^13.0.0",
"handlebars": "^4.7.7",
Expand Down
225 changes: 131 additions & 94 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/App/Activities/dto/activity.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ArgsType, Field, Int } from '@nestjs/graphql'
import { Validate } from 'class-validator'
import PaginationArgs from '../../pagination.args'
import ValidStringParams from '../../utils/customValidator'
import { ValidStringParams } from '../../utils/customValidator'
import { ActivityType } from '../../general.args'

@ArgsType()
Expand Down
2 changes: 1 addition & 1 deletion src/App/Blog/blog.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ import MirrorApiService from './mirrorApi.service'
@Module({
imports: [ConfigModule, HttpModule],
providers: [BlogService, BlogResolver, MirrorApiService],
exports: [BlogService],
exports: [BlogService, MirrorApiService],
})
export default class BlogModule {}
12 changes: 11 additions & 1 deletion src/App/Blog/blog.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Resolver, Query, Args } from '@nestjs/graphql'
import { Resolver, Query, Args, Int } from '@nestjs/graphql'
import BlogService from './blog.service'
import { Blog } from './blog.dto'

Expand All @@ -17,6 +17,16 @@ class BlogResolver {
): Promise<Blog | null> {
return this.blogService.getBlogByDigest(digest)
}

@Query(() => [Blog])
async getBlogSuggestions(
@Args('limit', { type: () => Int }) limit: number,
): Promise<Blog[]> {
if (limit < 1 || limit > 3) {
throw new Error('Limit must be between 1 and 3')
}
return this.blogService.getBlogSuggestions(limit)
}
}

export default BlogResolver
278 changes: 278 additions & 0 deletions src/App/Blog/blog.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
import { Test, TestingModule } from '@nestjs/testing'
import { CACHE_MANAGER } from '@nestjs/common'
import { Cache } from 'cache-manager'
import { ConfigService } from '@nestjs/config'
import BlogService from './blog.service'
import MirrorApiService from './mirrorApi.service'
import { Blog } from './blog.dto'

describe('BlogService', () => {
let blogService: BlogService
let cacheManager: Cache
// let configService: ConfigService
let mirrorApiService: MirrorApiService

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
BlogService,
{
provide: CACHE_MANAGER,
useValue: {
get: jest.fn(),
set: jest.fn(),
},
},
{
provide: ConfigService,
useValue: {
get: jest.fn().mockImplementation((key) => {
if (key === 'EVERIPEDIA_BLOG_ACCOUNT2') return 'account2'
if (key === 'EVERIPEDIA_BLOG_ACCOUNT3') return 'account3'
return null
}),
},
},
{
provide: MirrorApiService,
useValue: {
getBlogs: jest.fn().mockResolvedValue([
{
title: 'title',
slug: 'slug',
body: 'body',
digest: 'digest',
contributor: 'contributor',
transaction: 'transaction',
timestamp: 1234567890,
cover_image: 'https://example.com/image.jpg',
image_sizes: 50,
},
]),
getBlog: jest.fn().mockResolvedValue({
title: 'title',
slug: 'slug',
body: 'body',
digest: 'digest',
contributor: 'contributor',
transaction: 'transaction',
timestamp: 1234567890,
cover_image: 'https://example.com/image.jpg',
image_sizes: 50,
}),
},
},
],
}).compile()

blogService = module.get<BlogService>(BlogService)
cacheManager = module.get<Cache>(CACHE_MANAGER)
// configService = module.get<ConfigService>(ConfigService)
mirrorApiService = module.get<MirrorApiService>(MirrorApiService)
})

it('should be defined', () => {
expect(blogService).toBeDefined()
})

describe('formatEntry', () => {
it('should format a blog entry with all provided fields', async () => {
const blog: Partial<Blog> = {
title: 'title',
body: 'This is a test blog body.\n\n![Image](http://example.com/image.jpg)',
digest: 'digest',
contributor: 'contributor',
}
const transactionId = '12345'
const timestamp = 1627849200

const result = await blogService.formatEntry(
blog,
transactionId,
timestamp,
)

expect(result).toEqual({
title: 'title',
slug: 'title',
body: 'This is a test blog body.\n\n![Image](http://example.com/image.jpg)',
digest: 'digest',
contributor: 'contributor',
transaction: transactionId,
cover_image: '',
timestamp,
image_sizes: 50,
})
})
it('should handle missing blog title gracefully', async () => {
const blog: Partial<Blog> = {
body: 'This is a test blog body.\n\n![Image](http://example.com/image.jpg)',
digest: 'digest',
contributor: 'contributor',
}
const transactionId = '12345'
const timestamp = 1627849200

const result = await blogService.formatEntry(
blog,
transactionId,
timestamp,
)

expect(result).toEqual({
title: '',
slug: '',
body: 'This is a test blog body.\n\n![Image](http://example.com/image.jpg)',
digest: 'digest',
contributor: 'contributor',
transaction: transactionId,
cover_image: '',
timestamp,
image_sizes: 50,
})
})
})

describe('formatBlog', () => {
it('should format a blog correctly with body', () => {
const blog = {
title: ' Blog',
body: 'This is the body of the blog.\n\nThis is the excerpt.',
digest: 'digest',
publisher: { project: { address: 'John Doe' } },
timestamp: 1234567890,
}

const result = blogService.formatBlog(blog as any, true)

expect(result.body).toBe(
'This is the body of the blog.\n\nThis is the excerpt.',
)
expect(result.excerpt).toBe('This is the excerpt.')
})
it('should handle null or undefined blog input gracefully', () => {
const result = blogService.formatBlog(null)
expect(result.title).toBe('')
expect(result.slug).toBe('')
expect(result.digest).toBe('')
expect(result.contributor).toBe('')
})
})

describe('getBlogsFromAccounts', () => {
it('should return blogs from cache if available', async () => {
const blogs: Blog[] = [
{
title: 'title',
slug: 'slug',
body: '',
digest: '',
contributor: '',
transaction: '',
timestamp: 0,
cover_image: '',
image_sizes: 50,
},
]
jest.spyOn(cacheManager, 'get').mockResolvedValue(blogs)

const result = await blogService.getBlogsFromAccounts()
expect(result).toEqual(blogs)
})

it('should handle empty accounts array gracefully', async () => {
blogService.EVERIPEDIA_BLOG_ACCOUNT2 = null
blogService.EVERIPEDIA_BLOG_ACCOUNT3 = null

const blogs = await blogService.getBlogsFromAccounts()

expect(mirrorApiService.getBlogs).not.toHaveBeenCalled()
expect(blogs).toEqual([])
})
})

describe('getEntryPaths', () => {
it('should correctly map transactions to EntryPath objects when valid transactions are provided', async () => {
const rawTransactions = {
transactions: {
edges: [
{
node: {
id: '1',
block: { timestamp: 1234567890 },
tags: [{ name: 'Original-Content-Digest', value: 'digest1' }],
},
},
{
node: {
id: '2',
block: { timestamp: 1234567891 },
tags: [{ name: 'Original-Content-Digest', value: 'digest2' }],
},
},
],
},
}

const result = await blogService.getEntryPaths(rawTransactions)

expect(result).toEqual([
{ slug: 'digest1', path: '1', timestamp: 1234567890 },
{ slug: 'digest2', path: '2', timestamp: 1234567891 },
])
})

it('should return an empty array when transactions have empty edges array', async () => {
const rawTransactions = {
transactions: {
edges: [],
},
}

const result = await blogService.getEntryPaths(rawTransactions)

expect(result).toEqual([])
})
})

describe('mapEntry', () => {
it('should return an empty array when transactions have empty edges array', async () => {
const rawTransactions = {
transactions: {
edges: [],
},
}

const result = await blogService.getEntryPaths(rawTransactions)

expect(result).toEqual([])
})
})

describe('getBlogEntriesFormatted', () => {
it('should return formatted blog entries sorted by timestamp when entryPaths are provided', async () => {
const entryPaths = [{ path: 'path1' }, { path: 'path2' }]
jest.spyOn(blogService, 'mapEntry').mockImplementation(async (entry) => {
if (entry.path === 'path1') {
return { timestamp: 2, slug: 'slug1' }
} else {
return { timestamp: 1, slug: 'slug2' }
}
})

const result = await blogService.getBlogEntriesFormatted(entryPaths)

expect(result).toEqual([
{ timestamp: 2, slug: 'slug1' },
{ timestamp: 1, slug: 'slug2' },
])
})
it('should return an empty array when entryPaths is empty', async () => {
const entryPaths = []

const result = await blogService.getBlogEntriesFormatted(entryPaths)

expect(result).toEqual([])
})
})
})
10 changes: 10 additions & 0 deletions src/App/Blog/blog.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ class BlogService {
return acc
}, [])
}

async getBlogSuggestions(limit: number): Promise<Blog[]> {
const getAllBlogs = await this.getBlogsFromAccounts()

const randomBlog = getAllBlogs.sort(() => 0.5 - Math.random())

const minMaxLimit = Math.min(Math.max(limit, 1), 3)

return randomBlog.slice(0, minMaxLimit)
}
}

export default BlogService
2 changes: 1 addition & 1 deletion src/App/BrainPass/brainPass.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ArgsType, Field } from '@nestjs/graphql'
import { IsNumber, IsString, Validate } from 'class-validator'
import PaginationArgs from '../pagination.args'
import ValidStringParams from '../utils/customValidator'
import { ValidStringParams } from '../utils/customValidator'

class BrainPassDto {
@IsNumber()
Expand Down
6 changes: 5 additions & 1 deletion src/App/Subscriptions/subscriptions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ class WikiSubscriptionService {
.createQueryBuilder()
.delete()
.from(IqSubscription)
.where(args)
.where('LOWER(userId) = LOWER(:userId)', { userId: args.userId })
.andWhere({
subscriptionType: args.subscriptionType,
auxiliaryId: args.auxiliaryId,
})
.execute()
return true
}
Expand Down
2 changes: 1 addition & 1 deletion src/App/Tag/tag.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ArgsType, Field } from '@nestjs/graphql'
import { Validate } from 'class-validator'
import PaginationArgs from '../pagination.args'
import ValidStringParams from '../utils/customValidator'
import { ValidStringParams } from '../utils/customValidator'
import Tag from '../../Database/Entities/tag.entity'

@ArgsType()
Expand Down
Loading

0 comments on commit 860fd25

Please sign in to comment.