fix(daily dev): fixed routes and added one new one (#18021)
* add squads * style: auto format * null check * fix: add null checks for items * changes * trigger * use params * fix: add categories --------- Co-authored-by: rjnishant530 <singhnisant530@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
521313ffeb
commit
238955b5fe
|
|
@ -3,16 +3,18 @@ import { getData, getList } from './utils';
|
|||
|
||||
export const route: Route = {
|
||||
path: '/',
|
||||
categories: ['programming'],
|
||||
radar: [
|
||||
{
|
||||
source: ['alistapart.com/articles/'],
|
||||
target: '',
|
||||
target: '/',
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
name: 'Home Feed',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'alistapart.com/articles/',
|
||||
example: '/alistapart',
|
||||
};
|
||||
|
||||
async function handler() {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const route: Route = {
|
|||
radar: [
|
||||
{
|
||||
source: ['alistapart.com/blog/topic/:topic'],
|
||||
target: '/:topic',
|
||||
},
|
||||
],
|
||||
name: 'Topics',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Route } from '@/types';
|
||||
import { baseUrl, getData, getList } from './utils.js';
|
||||
import { Route, ViewType } from '@/types';
|
||||
import { baseUrl, getData, getList, variables } from './utils.js';
|
||||
|
||||
const query = `
|
||||
query MostDiscussedFeed(
|
||||
|
|
@ -52,8 +52,9 @@ const query = `
|
|||
`;
|
||||
|
||||
export const route: Route = {
|
||||
path: '/discussed',
|
||||
example: '/daily/discussed',
|
||||
path: '/discussed/:period?/:innerSharedContent?/:dateSort?',
|
||||
example: '/daily/discussed/30',
|
||||
view: ViewType.Articles,
|
||||
radar: [
|
||||
{
|
||||
source: ['app.daily.dev/discussed'],
|
||||
|
|
@ -63,19 +64,52 @@ export const route: Route = {
|
|||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'app.daily.dev/discussed',
|
||||
parameters: {
|
||||
innerSharedContent: {
|
||||
description: 'Where to Fetch inner Shared Posts instead of original',
|
||||
default: 'false',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
dateSort: {
|
||||
description: 'Sort posts by publication date instead of popularity',
|
||||
default: 'true',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
period: {
|
||||
description: 'Period of Lookup',
|
||||
default: '7',
|
||||
options: [
|
||||
{ value: '7', label: 'Last Week' },
|
||||
{ value: '30', label: 'Last Month' },
|
||||
{ value: '365', label: 'Last Year' },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20;
|
||||
const link = `${baseUrl}/discussed`;
|
||||
const innerSharedContent = ctx.req.param('innerSharedContent') ? JSON.parse(ctx.req.param('innerSharedContent')) : false;
|
||||
const dateSort = ctx.req.param('dateSort') ? JSON.parse(ctx.req.param('dateSort')) : true;
|
||||
const period = ctx.req.param('period') ? Number.parseInt(ctx.req.param('period'), 10) : 7;
|
||||
|
||||
const link = `${baseUrl}/posts/discussed`;
|
||||
|
||||
const data = await getData({
|
||||
query,
|
||||
variables: {
|
||||
...variables,
|
||||
first: limit,
|
||||
period,
|
||||
},
|
||||
});
|
||||
const items = getList(data);
|
||||
const items = getList(data, innerSharedContent, dateSort);
|
||||
|
||||
return {
|
||||
title: 'Real-time discussions in the developer community | daily.dev',
|
||||
|
|
|
|||
|
|
@ -1,101 +0,0 @@
|
|||
import { Route } from '@/types';
|
||||
import { baseUrl, getData, getList } from './utils.js';
|
||||
|
||||
const variables = {
|
||||
version: 11,
|
||||
ranking: 'POPULARITY',
|
||||
first: 15,
|
||||
};
|
||||
|
||||
const query = `
|
||||
query AnonymousFeed(
|
||||
$first: Int
|
||||
$ranking: Ranking
|
||||
$version: Int
|
||||
$supportedTypes: [String!] = ["article","share","freeform"]
|
||||
) {
|
||||
page: anonymousFeed(
|
||||
first: $first
|
||||
ranking: $ranking
|
||||
version: $version
|
||||
supportedTypes: $supportedTypes
|
||||
) {
|
||||
...FeedPostConnection
|
||||
}
|
||||
}
|
||||
|
||||
fragment FeedPostConnection on PostConnection {
|
||||
edges {
|
||||
node {
|
||||
...FeedPost
|
||||
contentHtml
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment FeedPost on Post {
|
||||
...SharedPostInfo
|
||||
}
|
||||
|
||||
fragment SharedPostInfo on Post {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
summary
|
||||
createdAt
|
||||
numUpvotes
|
||||
numComments
|
||||
author {
|
||||
...UserShortInfo
|
||||
}
|
||||
tags
|
||||
}
|
||||
|
||||
fragment UserShortInfo on User {
|
||||
id
|
||||
name
|
||||
image
|
||||
permalink
|
||||
username
|
||||
bio
|
||||
}
|
||||
`;
|
||||
|
||||
const graphqlQuery = {
|
||||
query,
|
||||
variables,
|
||||
};
|
||||
|
||||
export const route: Route = {
|
||||
path: '/',
|
||||
example: '/daily',
|
||||
radar: [
|
||||
{
|
||||
source: ['app.daily.dev/popular'],
|
||||
},
|
||||
],
|
||||
name: 'Popular',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'app.daily.dev/popular',
|
||||
};
|
||||
|
||||
async function handler() {
|
||||
const link = `${baseUrl}/popular`;
|
||||
|
||||
const data = await getData(graphqlQuery);
|
||||
const items = getList(data);
|
||||
|
||||
return {
|
||||
title: 'Popular posts on daily.dev',
|
||||
link,
|
||||
item: items,
|
||||
description: 'daily.dev is the easiest way to stay updated on the latest programming news. Get the best content from the top tech publications on any topic you want.',
|
||||
logo: `${baseUrl}/favicon-32x32.png`,
|
||||
icon: `${baseUrl}/favicon-32x32.png`,
|
||||
language: 'en-us',
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
import { Route, ViewType } from '@/types';
|
||||
import { baseUrl, getData, getList, variables } from './utils.js';
|
||||
|
||||
const query = `
|
||||
query AnonymousFeed(
|
||||
$loggedIn: Boolean! = false
|
||||
$first: Int
|
||||
$after: String
|
||||
$ranking: Ranking
|
||||
$version: Int
|
||||
$supportedTypes: [String!] = ["article","share","freeform","video:youtube","collection"]
|
||||
) {
|
||||
page: anonymousFeed(
|
||||
first: $first
|
||||
after: $after
|
||||
ranking: $ranking
|
||||
version: $version
|
||||
supportedTypes: $supportedTypes
|
||||
) {
|
||||
...FeedPostConnection
|
||||
}
|
||||
}
|
||||
|
||||
fragment FeedPostConnection on PostConnection {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
...FeedPost
|
||||
contentHtml
|
||||
...UserPost @include(if: $loggedIn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment FeedPost on Post {
|
||||
...FeedPostInfo
|
||||
sharedPost {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
createdAt
|
||||
type
|
||||
tags
|
||||
source {
|
||||
id
|
||||
handle
|
||||
permalink
|
||||
image
|
||||
}
|
||||
slug
|
||||
clickbaitTitleDetected
|
||||
}
|
||||
trending
|
||||
feedMeta
|
||||
collectionSources {
|
||||
handle
|
||||
image
|
||||
}
|
||||
numCollectionSources
|
||||
updatedAt
|
||||
slug
|
||||
}
|
||||
|
||||
|
||||
fragment FeedPostInfo on Post {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
createdAt
|
||||
commented
|
||||
bookmarked
|
||||
views
|
||||
numUpvotes
|
||||
numComments
|
||||
summary
|
||||
bookmark {
|
||||
remindAt
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
username
|
||||
permalink
|
||||
}
|
||||
type
|
||||
tags
|
||||
source {
|
||||
id
|
||||
handle
|
||||
name
|
||||
permalink
|
||||
image
|
||||
type
|
||||
}
|
||||
userState {
|
||||
vote
|
||||
flags {
|
||||
feedbackDismiss
|
||||
}
|
||||
}
|
||||
slug
|
||||
clickbaitTitleDetected
|
||||
}
|
||||
|
||||
fragment UserPost on Post {
|
||||
read
|
||||
upvoted
|
||||
commented
|
||||
bookmarked
|
||||
downvoted
|
||||
}
|
||||
`;
|
||||
|
||||
export const route: Route = {
|
||||
path: '/popular/:innerSharedContent?/:dateSort?',
|
||||
example: '/daily/popular',
|
||||
view: ViewType.Articles,
|
||||
radar: [
|
||||
{
|
||||
source: ['app.daily.dev/popular'],
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
innerSharedContent: {
|
||||
description: 'Where to Fetch inner Shared Posts instead of original',
|
||||
default: 'false',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
dateSort: {
|
||||
description: 'Sort posts by publication date instead of popularity',
|
||||
default: 'true',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
},
|
||||
name: 'Popular',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'app.daily.dev/popular',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const link = `${baseUrl}/posts`;
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 15;
|
||||
const innerSharedContent = ctx.req.param('innerSharedContent') ? JSON.parse(ctx.req.param('innerSharedContent')) : false;
|
||||
const dateSort = ctx.req.param('dateSort') ? JSON.parse(ctx.req.param('dateSort')) : true;
|
||||
|
||||
const data = await getData({
|
||||
query,
|
||||
variables: {
|
||||
...variables,
|
||||
ranking: 'POPULARITY',
|
||||
first: limit,
|
||||
},
|
||||
});
|
||||
const items = getList(data, innerSharedContent, dateSort);
|
||||
|
||||
return {
|
||||
title: 'Popular posts on daily.dev',
|
||||
link,
|
||||
item: items,
|
||||
description: 'daily.dev is the easiest way to stay updated on the latest programming news. Get the best content from the top tech publications on any topic you want.',
|
||||
logo: `${baseUrl}/favicon-32x32.png`,
|
||||
icon: `${baseUrl}/favicon-32x32.png`,
|
||||
language: 'en-us',
|
||||
};
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Route } from '@/types';
|
||||
import { DataItem, Route } from '@/types';
|
||||
import { baseUrl, getBuildId, getData, getList } from './utils';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import cache from '@/utils/cache';
|
||||
|
|
@ -125,10 +125,18 @@ fragment UserPost on Post {
|
|||
}`;
|
||||
|
||||
export const route: Route = {
|
||||
path: '/source/:sourceId',
|
||||
path: '/source/:sourceId/:innerSharedContent?',
|
||||
example: '/daily/source/hn',
|
||||
parameters: {
|
||||
sourceId: 'The source id',
|
||||
innerSharedContent: {
|
||||
description: 'Where to Fetch inner Shared Posts instead of original',
|
||||
default: 'false',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
|
|
@ -144,8 +152,9 @@ export const route: Route = {
|
|||
async function handler(ctx) {
|
||||
const sourceId = ctx.req.param('sourceId');
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 10;
|
||||
const link = `${baseUrl}/sources/${sourceId}`;
|
||||
const innerSharedContent = ctx.req.param('innerSharedContent') ? JSON.parse(ctx.req.param('innerSharedContent')) : false;
|
||||
|
||||
const link = `${baseUrl}/sources/${sourceId}`;
|
||||
const buildId = await getBuildId();
|
||||
|
||||
const userData = (await cache.tryGet(`daily:source:${sourceId}`, async () => {
|
||||
|
|
@ -167,7 +176,7 @@ async function handler(ctx) {
|
|||
loggedIn: false,
|
||||
},
|
||||
});
|
||||
return getList(edges);
|
||||
return getList(edges, innerSharedContent, true);
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
|
|
@ -177,7 +186,7 @@ async function handler(ctx) {
|
|||
title: `${userData.name} posts on daily.dev`,
|
||||
description: userData.description,
|
||||
link,
|
||||
item: items,
|
||||
item: items as DataItem[],
|
||||
image: userData.image,
|
||||
logo: userData.image,
|
||||
icon: userData.image,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,266 @@
|
|||
import { Route, ViewType } from '@/types';
|
||||
import { baseUrl, getData, getList, variables } from './utils.js';
|
||||
|
||||
const sourceQuery = `
|
||||
query Source($handle: ID!) {
|
||||
source(id: $handle) {
|
||||
...SquadBaseInfo
|
||||
moderationPostCount
|
||||
}
|
||||
}
|
||||
fragment SquadBaseInfo on Source {
|
||||
...SourceBaseInfo
|
||||
referralUrl
|
||||
createdAt
|
||||
flags {
|
||||
featured
|
||||
totalPosts
|
||||
totalViews
|
||||
totalUpvotes
|
||||
}
|
||||
category {
|
||||
id
|
||||
title
|
||||
slug
|
||||
}
|
||||
...PrivilegedMembers
|
||||
}
|
||||
fragment SourceBaseInfo on Source {
|
||||
id
|
||||
active
|
||||
handle
|
||||
name
|
||||
permalink
|
||||
public
|
||||
type
|
||||
description
|
||||
image
|
||||
membersCount
|
||||
currentMember {
|
||||
...CurrentMember
|
||||
}
|
||||
memberPostingRole
|
||||
memberInviteRole
|
||||
moderationRequired
|
||||
}
|
||||
fragment CurrentMember on SourceMember {
|
||||
user {
|
||||
id
|
||||
}
|
||||
permissions
|
||||
role
|
||||
referralToken
|
||||
flags {
|
||||
hideFeedPosts
|
||||
collapsePinnedPosts
|
||||
}
|
||||
}
|
||||
fragment PrivilegedMembers on Source {
|
||||
privilegedMembers {
|
||||
user {
|
||||
id
|
||||
name
|
||||
image
|
||||
permalink
|
||||
username
|
||||
bio
|
||||
reputation
|
||||
companies {
|
||||
name
|
||||
image
|
||||
}
|
||||
contentPreference {
|
||||
status
|
||||
}
|
||||
}
|
||||
role
|
||||
}
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
const query = `
|
||||
query SourceFeed(
|
||||
$source: ID!
|
||||
$loggedIn: Boolean! = false
|
||||
$first: Int
|
||||
$after: String
|
||||
$ranking: Ranking
|
||||
$supportedTypes: [String!]
|
||||
) {
|
||||
page: sourceFeed(
|
||||
source: $source
|
||||
first: $first
|
||||
after: $after
|
||||
ranking: $ranking
|
||||
supportedTypes: $supportedTypes
|
||||
) {
|
||||
...FeedPostConnection
|
||||
}
|
||||
}
|
||||
|
||||
fragment FeedPostConnection on PostConnection {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
...FeedPost
|
||||
pinnedAt contentHtml
|
||||
...UserPost @include(if: $loggedIn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment FeedPost on Post {
|
||||
...FeedPostInfo
|
||||
sharedPost {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
createdAt
|
||||
type
|
||||
tags
|
||||
source {
|
||||
id
|
||||
handle
|
||||
permalink
|
||||
image
|
||||
}
|
||||
slug
|
||||
clickbaitTitleDetected
|
||||
}
|
||||
trending
|
||||
feedMeta
|
||||
collectionSources {
|
||||
handle
|
||||
image
|
||||
}
|
||||
numCollectionSources
|
||||
updatedAt
|
||||
slug
|
||||
}
|
||||
|
||||
fragment FeedPostInfo on Post {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
createdAt
|
||||
commented
|
||||
bookmarked
|
||||
views
|
||||
numUpvotes
|
||||
numComments
|
||||
summary
|
||||
bookmark {
|
||||
remindAt
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
username
|
||||
permalink
|
||||
}
|
||||
type
|
||||
tags
|
||||
source {
|
||||
id
|
||||
handle
|
||||
name
|
||||
permalink
|
||||
image
|
||||
type
|
||||
}
|
||||
userState {
|
||||
vote
|
||||
flags {
|
||||
feedbackDismiss
|
||||
}
|
||||
}
|
||||
slug
|
||||
clickbaitTitleDetected
|
||||
}
|
||||
|
||||
|
||||
|
||||
fragment UserPost on Post {
|
||||
read
|
||||
upvoted
|
||||
commented
|
||||
bookmarked
|
||||
downvoted
|
||||
}
|
||||
`;
|
||||
|
||||
export const route: Route = {
|
||||
path: '/squads/:squads/:innerSharedContent?',
|
||||
example: '/daily/squads/watercooler',
|
||||
view: ViewType.Articles,
|
||||
parameters: {
|
||||
innerSharedContent: {
|
||||
description: 'Where to Fetch inner Shared Posts instead of original',
|
||||
default: 'false',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['app.daily.dev/squads/:squads'],
|
||||
},
|
||||
],
|
||||
name: 'Squads',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'app.daily.dev/squads/discover',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20;
|
||||
const innerSharedContent = ctx.req.param('innerSharedContent') ? JSON.parse(ctx.req.param('innerSharedContent')) : false;
|
||||
const squads = ctx.req.param('squads');
|
||||
|
||||
const link = `${baseUrl}/squads/${squads}`;
|
||||
|
||||
const { id, description, name } = await getData(
|
||||
{
|
||||
query: sourceQuery,
|
||||
variables: {
|
||||
handle: squads,
|
||||
},
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
const data = await getData({
|
||||
query,
|
||||
variables: {
|
||||
...variables,
|
||||
source: id,
|
||||
ranking: 'TIME',
|
||||
supportedTypes: ['article', 'share', 'freeform', 'video:youtube', 'collection', 'welcome'],
|
||||
first: limit,
|
||||
},
|
||||
});
|
||||
const items = getList(data, innerSharedContent, true);
|
||||
|
||||
return {
|
||||
title: `${name} - daily.dev`,
|
||||
link,
|
||||
item: items,
|
||||
description,
|
||||
logo: `${baseUrl}/favicon-32x32.png`,
|
||||
icon: `${baseUrl}/favicon-32x32.png`,
|
||||
language: 'en-us',
|
||||
};
|
||||
}
|
||||
|
|
@ -1,84 +1,181 @@
|
|||
import { Route } from '@/types';
|
||||
import { baseUrl, getData, getList } from './utils.js';
|
||||
|
||||
const variables = {
|
||||
period: 7,
|
||||
first: 15,
|
||||
};
|
||||
import { Route, ViewType } from '@/types';
|
||||
import { baseUrl, getData, getList, variables } from './utils.js';
|
||||
|
||||
const query = `
|
||||
query MostUpvotedFeed(
|
||||
query MostUpvotedFeed(
|
||||
$loggedIn: Boolean! = false
|
||||
$first: Int
|
||||
$after: String
|
||||
$period: Int
|
||||
$supportedTypes: [String!] = ["article","share","freeform"]
|
||||
$supportedTypes: [String!] = ["article","share","freeform","video:youtube","collection"]
|
||||
$source: ID
|
||||
$tag: String
|
||||
) {
|
||||
page: mostUpvotedFeed(first: $first, period: $period, supportedTypes: $supportedTypes) {
|
||||
page: mostUpvotedFeed(first: $first, after: $after, period: $period, supportedTypes: $supportedTypes, source: $source, tag: $tag) {
|
||||
...FeedPostConnection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fragment FeedPostConnection on PostConnection {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
...FeedPost
|
||||
contentHtml
|
||||
...UserPost @include(if: $loggedIn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fragment FeedPost on Post {
|
||||
...SharedPostInfo
|
||||
...FeedPostInfo
|
||||
sharedPost {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
createdAt
|
||||
type
|
||||
tags
|
||||
source {
|
||||
id
|
||||
handle
|
||||
permalink
|
||||
image
|
||||
}
|
||||
slug
|
||||
clickbaitTitleDetected
|
||||
}
|
||||
trending
|
||||
feedMeta
|
||||
collectionSources {
|
||||
handle
|
||||
image
|
||||
}
|
||||
numCollectionSources
|
||||
updatedAt
|
||||
slug
|
||||
}
|
||||
|
||||
fragment SharedPostInfo on Post {
|
||||
|
||||
fragment FeedPostInfo on Post {
|
||||
id
|
||||
title
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
summary
|
||||
createdAt
|
||||
commented
|
||||
bookmarked
|
||||
views
|
||||
numUpvotes
|
||||
numComments
|
||||
author {
|
||||
...UserShortInfo
|
||||
summary
|
||||
bookmark {
|
||||
remindAt
|
||||
}
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
username
|
||||
permalink
|
||||
}
|
||||
type
|
||||
tags
|
||||
source {
|
||||
id
|
||||
handle
|
||||
name
|
||||
permalink
|
||||
image
|
||||
type
|
||||
}
|
||||
userState {
|
||||
vote
|
||||
flags {
|
||||
feedbackDismiss
|
||||
}
|
||||
}
|
||||
slug
|
||||
clickbaitTitleDetected
|
||||
}
|
||||
|
||||
fragment UserShortInfo on User {
|
||||
id
|
||||
name
|
||||
image
|
||||
permalink
|
||||
username
|
||||
bio
|
||||
|
||||
|
||||
fragment UserPost on Post {
|
||||
read
|
||||
upvoted
|
||||
commented
|
||||
bookmarked
|
||||
downvoted
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
export const route: Route = {
|
||||
path: '/upvoted',
|
||||
example: '/daily/upvoted',
|
||||
path: '/upvoted/:period?/:innerSharedContent?/:dateSort?',
|
||||
example: '/daily/upvoted/7',
|
||||
view: ViewType.Articles,
|
||||
radar: [
|
||||
{
|
||||
source: ['app.daily.dev/upvoted'],
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
innerSharedContent: {
|
||||
description: 'Where to Fetch inner Shared Posts instead of original',
|
||||
default: 'false',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
dateSort: {
|
||||
description: 'Sort posts by publication date instead of popularity',
|
||||
default: 'true',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
period: {
|
||||
description: 'Period of Lookup',
|
||||
default: '7',
|
||||
options: [
|
||||
{ value: '7', label: 'Last Week' },
|
||||
{ value: '30', label: 'Last Month' },
|
||||
{ value: '365', label: 'Last Year' },
|
||||
],
|
||||
},
|
||||
},
|
||||
name: 'Most upvoted',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'app.daily.dev/upvoted',
|
||||
};
|
||||
|
||||
async function handler() {
|
||||
const link = `${baseUrl}/upvoted`;
|
||||
async function handler(ctx) {
|
||||
const link = `${baseUrl}/posts/upvoted`;
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20;
|
||||
const innerSharedContent = ctx.req.param('innerSharedContent') ? JSON.parse(ctx.req.param('innerSharedContent')) : false;
|
||||
const dateSort = ctx.req.param('dateSort') ? JSON.parse(ctx.req.param('dateSort')) : true;
|
||||
const period = ctx.req.param('period') ? Number.parseInt(ctx.req.param('period'), 10) : 7;
|
||||
|
||||
const data = await getData({
|
||||
query,
|
||||
variables,
|
||||
variables: {
|
||||
...variables,
|
||||
period,
|
||||
first: limit,
|
||||
},
|
||||
});
|
||||
const items = getList(data);
|
||||
const items = getList(data, innerSharedContent, dateSort);
|
||||
|
||||
return {
|
||||
title: 'Most upvoted posts for developers | daily.dev',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Route } from '@/types';
|
||||
import { DataItem, Route } from '@/types';
|
||||
import { baseUrl, getBuildId, getData, getList } from './utils';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import cache from '@/utils/cache';
|
||||
|
|
@ -151,13 +151,23 @@ const userPostQuery = `
|
|||
}`;
|
||||
|
||||
export const route: Route = {
|
||||
path: '/user/:userId',
|
||||
path: '/user/:userId/:innerSharedContent?',
|
||||
example: '/daily/user/kramer',
|
||||
radar: [
|
||||
{
|
||||
source: ['app.daily.dev/:userId/posts', 'app.daily.dev/:userId'],
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
innerSharedContent: {
|
||||
description: 'Where to Fetch inner Shared Posts instead of original',
|
||||
default: 'false',
|
||||
options: [
|
||||
{ value: 'false', label: 'False' },
|
||||
{ value: 'true', label: 'True' },
|
||||
],
|
||||
},
|
||||
},
|
||||
name: 'User Posts',
|
||||
maintainers: ['TonyRL'],
|
||||
handler,
|
||||
|
|
@ -167,7 +177,7 @@ export const route: Route = {
|
|||
async function handler(ctx) {
|
||||
const userId = ctx.req.param('userId');
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 7;
|
||||
|
||||
const innerSharedContent = ctx.req.param('innerSharedContent') ? JSON.parse(ctx.req.param('innerSharedContent')) : false;
|
||||
const buildId = await getBuildId();
|
||||
|
||||
const userData = await cache.tryGet(`daily:user:${userId}`, async () => {
|
||||
|
|
@ -191,7 +201,7 @@ async function handler(ctx) {
|
|||
loggedIn: false,
|
||||
},
|
||||
});
|
||||
return getList(edges);
|
||||
return getList(edges, innerSharedContent, true);
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
|
|
@ -201,7 +211,7 @@ async function handler(ctx) {
|
|||
title: `${user.name} | daily.dev`,
|
||||
description: user.bio,
|
||||
link: `${baseUrl}/${userId}/posts`,
|
||||
item: items,
|
||||
item: items as DataItem[],
|
||||
image: user.image,
|
||||
logo: user.image,
|
||||
icon: user.image,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,15 @@ import { config } from '@/config';
|
|||
import { art } from '@/utils/render';
|
||||
import path from 'node:path';
|
||||
import { getCurrentPath } from '@/utils/helpers';
|
||||
import { DataItem } from '@/types';
|
||||
const __dirname = getCurrentPath(import.meta.url);
|
||||
|
||||
export const baseUrl = 'https://app.daily.dev';
|
||||
const gqlUrl = `https://api.daily.dev/graphql`;
|
||||
|
||||
export const variables = {
|
||||
version: 54,
|
||||
loggedIn: false,
|
||||
};
|
||||
export const getBuildId = () =>
|
||||
cache.tryGet(
|
||||
'daily:buildId',
|
||||
|
|
@ -22,30 +26,42 @@ export const getBuildId = () =>
|
|||
false
|
||||
);
|
||||
|
||||
export const getData = async (graphqlQuery) => {
|
||||
export const getData = async (graphqlQuery, source = false) => {
|
||||
const response = await ofetch(gqlUrl, {
|
||||
method: 'POST',
|
||||
body: graphqlQuery,
|
||||
});
|
||||
return response.data.page.edges;
|
||||
return source ? response.data.source : response.data.page.edges;
|
||||
};
|
||||
|
||||
const render = (data) => art(path.join(__dirname, 'templates/posts.art'), data);
|
||||
|
||||
export const getList = (edges) =>
|
||||
edges.map(({ node }) => ({
|
||||
id: node.id,
|
||||
title: node.title,
|
||||
link: node.commentsPermalink ?? node.permalink,
|
||||
guid: node.permalink,
|
||||
description: render({
|
||||
image: node.image,
|
||||
content: node.contentHtml?.replaceAll('\n', '<br>') ?? node.summary,
|
||||
}),
|
||||
author: node.author?.name,
|
||||
itunes_item_image: node.image,
|
||||
pubDate: parseDate(node.createdAt),
|
||||
upvotes: node.numUpvotes,
|
||||
comments: node.numComments,
|
||||
category: node.tags,
|
||||
}));
|
||||
export const getList = (edges, innerSharedContent: boolean, dateSort: boolean) =>
|
||||
edges.map(({ node }) => {
|
||||
let link: string;
|
||||
let title: string;
|
||||
if (innerSharedContent && node.type === 'share') {
|
||||
link = node.sharedPost.permalink;
|
||||
title = node.sharedPost.title;
|
||||
} else {
|
||||
link = node.commentsPermalink ?? node.permalink;
|
||||
title = node.title;
|
||||
}
|
||||
|
||||
return {
|
||||
id: node.id,
|
||||
title,
|
||||
link,
|
||||
guid: node.permalink,
|
||||
description: render({
|
||||
image: node.image,
|
||||
content: node.contentHtml?.replaceAll('\n', '<br>') ?? node.summary,
|
||||
}),
|
||||
author: node.author?.name,
|
||||
itunes_item_image: node.image,
|
||||
pubDate: dateSort ? parseDate(node.createdAt) : '',
|
||||
upvotes: node.numUpvotes,
|
||||
comments: node.numComments,
|
||||
category: node.tags,
|
||||
} as DataItem;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ async function handler() {
|
|||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
if (!item.securityID) {
|
||||
return item;
|
||||
}
|
||||
const info = await getData(`${apiInfo}/${item.securityID}`);
|
||||
item.description = item.description + '<br><br>' + info?.AboutCompanyText;
|
||||
return item;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { DataItem } from '@/types';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
|
|
@ -15,16 +16,20 @@ const getData = (url) =>
|
|||
const getList = (data) =>
|
||||
data.map((value) => {
|
||||
const { ID, Description: title, Date: createdOn, NewsitemSecurities, NewsitemSectors, NewsitemIndustries } = value;
|
||||
const securityID = NewsitemSecurities[0].SecurityID;
|
||||
const securityID = NewsitemSecurities?.[0]?.SecurityID;
|
||||
const securitySlug = NewsitemSecurities?.[0]?.SecuritySlug;
|
||||
const sectors = NewsitemSectors.map((v) => v.SectorName);
|
||||
const industries = NewsitemIndustries.map((v) => v.IndustryName);
|
||||
return {
|
||||
id: ID,
|
||||
title: `${title} [${NewsitemSectors.map((v) => v.SectorName).join(', ')}]`,
|
||||
title: `${title} [${sectors.join(', ')}]`,
|
||||
description: title,
|
||||
securityID,
|
||||
link: `${baseUrl}${NewsitemSecurities[0].SecuritySlug}/${securityID}`,
|
||||
link: NewsitemSecurities?.length === 0 ? '' : `${baseUrl}${securitySlug}/${securityID}?section=news`,
|
||||
guid: NewsitemSecurities?.length === 0 ? ID : `${baseUrl}${securitySlug}/${securityID}`,
|
||||
pubDate: parseDate(createdOn),
|
||||
category: [...NewsitemIndustries.map((v) => v.IndustryName), ...NewsitemSectors.map((v) => v.SectorName)],
|
||||
};
|
||||
category: [...industries, ...sectors],
|
||||
} as DataItem;
|
||||
});
|
||||
|
||||
export { getData, getList };
|
||||
|
|
|
|||
Loading…
Reference in New Issue