add endpoint authors
This commit is contained in:
370
src/lib/api/authors.ts
Normal file
370
src/lib/api/authors.ts
Normal file
@@ -0,0 +1,370 @@
|
||||
import { fetchGraphQL } from './graphql-client.js';
|
||||
|
||||
//кэширование
|
||||
import { cache } from '@lib/cache/manager.js';
|
||||
import { CACHE_TTL } from '@lib/cache/cache-ttl';
|
||||
|
||||
export async function getPostsByCoauthorName(coauthorName, first = 14, after = null) {
|
||||
// Создаем уникальный ключ для кэша
|
||||
const cacheKey = `coauthor-posts-known:${coauthorName}:${first}:${after || 'first-page'}`;
|
||||
|
||||
return await cache.wrap(
|
||||
cacheKey,
|
||||
async () => {
|
||||
const query = `
|
||||
query GetPostsByCoauthorName($first: Int!, $after: String, $coauthorName: String!) {
|
||||
# Информация об авторе
|
||||
users(where: {search: $coauthorName}) {
|
||||
nodes {
|
||||
databaseId
|
||||
name
|
||||
nicename
|
||||
email
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
description
|
||||
posts {
|
||||
pageInfo {
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Посты автора
|
||||
contentNodes(
|
||||
first: $first
|
||||
after: $after
|
||||
where: {
|
||||
contentTypes: [PROFILE_ARTICLE, ANEW]
|
||||
coauthorName: $coauthorName
|
||||
orderby: { field: DATE, order: DESC }
|
||||
}
|
||||
) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
nodes {
|
||||
__typename
|
||||
id
|
||||
databaseId
|
||||
uri
|
||||
date
|
||||
|
||||
... on NodeWithTitle {
|
||||
title
|
||||
}
|
||||
|
||||
... on NodeWithFeaturedImage {
|
||||
featuredImage {
|
||||
node {
|
||||
sourceUrl(size: LARGE)
|
||||
altText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Для кастомных типов
|
||||
... on ProfileArticle {
|
||||
categories {
|
||||
nodes {
|
||||
name
|
||||
slug
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
... on ANew {
|
||||
categories {
|
||||
nodes {
|
||||
name
|
||||
slug
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
... on NodeWithAuthor {
|
||||
author {
|
||||
node {
|
||||
name
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Coauthors для ProfileArticle
|
||||
... on ProfileArticle {
|
||||
coauthors {
|
||||
id
|
||||
name
|
||||
firstName
|
||||
lastName
|
||||
url
|
||||
nicename
|
||||
}
|
||||
}
|
||||
|
||||
# Coauthors для ANew
|
||||
... on ANew {
|
||||
coauthors {
|
||||
id
|
||||
name
|
||||
firstName
|
||||
lastName
|
||||
url
|
||||
nicename
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const data = await fetchGraphQL(query, {
|
||||
first,
|
||||
after,
|
||||
coauthorName
|
||||
});
|
||||
|
||||
// Находим автора (первый результат поиска)
|
||||
const author = data.users?.nodes?.[0];
|
||||
|
||||
if (!author) {
|
||||
return {
|
||||
author: null,
|
||||
posts: [],
|
||||
pageInfo: { hasNextPage: false, endCursor: null },
|
||||
totalPosts: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Обрабатываем посты
|
||||
const posts = data.contentNodes?.nodes?.map(node => {
|
||||
// Приводим coauthors к единому формату
|
||||
if (node.coauthors) {
|
||||
node.coauthors = node.coauthors.map(coauthor => ({
|
||||
id: coauthor.id,
|
||||
nickname: coauthor.nickname,
|
||||
name: coauthor.name || '',
|
||||
firstName: coauthor.firstName || '',
|
||||
lastName: coauthor.lastName || '',
|
||||
url: coauthor.url || ''
|
||||
}));
|
||||
}
|
||||
return node;
|
||||
}) || [];
|
||||
|
||||
return {
|
||||
author: {
|
||||
id: author.databaseId,
|
||||
name: author.name,
|
||||
login: author.nicename,
|
||||
email: author.email,
|
||||
avatar: author.avatar?.url,
|
||||
description: author.description,
|
||||
totalPosts: author.posts?.pageInfo?.total || posts.length
|
||||
},
|
||||
posts,
|
||||
pageInfo: data.contentNodes?.pageInfo || {
|
||||
hasNextPage: false,
|
||||
endCursor: null
|
||||
},
|
||||
authorName: coauthorName
|
||||
};
|
||||
},
|
||||
{ ttl: CACHE_TTL.POSTS }
|
||||
);
|
||||
}
|
||||
|
||||
// все посты автора
|
||||
export async function getPostsByCoauthorLogin(login, first = 14, after = null) {
|
||||
// Создаем уникальный ключ для кэша
|
||||
const cacheKey = `coauthor-posts-by-login:${login}:${first}:${after || 'first-page'}`;
|
||||
|
||||
return await cache.wrap(
|
||||
cacheKey,
|
||||
async () => {
|
||||
const query = `
|
||||
query GetPostsByCoauthorLogin($first: Int!, $after: String, $login: String!) {
|
||||
contentNodes(
|
||||
first: $first
|
||||
after: $after
|
||||
where: {
|
||||
contentTypes: [PROFILE_ARTICLE, ANEW]
|
||||
coauthorLogin: $login
|
||||
orderby: { field: DATE, order: DESC }
|
||||
}
|
||||
) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
nodes {
|
||||
__typename
|
||||
id
|
||||
databaseId
|
||||
uri
|
||||
date
|
||||
|
||||
... on NodeWithTitle {
|
||||
title
|
||||
}
|
||||
|
||||
... on NodeWithFeaturedImage {
|
||||
featuredImage {
|
||||
node {
|
||||
sourceUrl(size: LARGE)
|
||||
altText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Для ваших кастомных типов
|
||||
... on ProfileArticle {
|
||||
categories {
|
||||
nodes {
|
||||
name
|
||||
slug
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
... on ANew {
|
||||
categories {
|
||||
nodes {
|
||||
name
|
||||
slug
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
... on NodeWithAuthor {
|
||||
author {
|
||||
node {
|
||||
name
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Coauthors для ProfileArticle
|
||||
... on ProfileArticle {
|
||||
coauthors {
|
||||
id
|
||||
name
|
||||
firstName
|
||||
lastName
|
||||
url
|
||||
nicename # Добавляем nicename (login)
|
||||
}
|
||||
}
|
||||
|
||||
# Coauthors для ANew
|
||||
... on ANew {
|
||||
coauthors {
|
||||
id
|
||||
name
|
||||
firstName
|
||||
lastName
|
||||
url
|
||||
nicename # Добавляем nicename (login)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const data = await fetchGraphQL(query, {
|
||||
first,
|
||||
after,
|
||||
login
|
||||
});
|
||||
|
||||
// Обрабатываем посты
|
||||
const posts = data.contentNodes?.nodes?.map(node => {
|
||||
// Приводим coauthors к единому формату
|
||||
if (node.coauthors) {
|
||||
node.coauthors = node.coauthors.map(author => ({
|
||||
id: author.id,
|
||||
name: author.name || '',
|
||||
firstName: author.firstName || '',
|
||||
lastName: author.lastName || '',
|
||||
url: author.url || '',
|
||||
nicename: author.nicename || '' // Добавляем login
|
||||
}));
|
||||
}
|
||||
|
||||
return node;
|
||||
}) || [];
|
||||
|
||||
return {
|
||||
posts,
|
||||
pageInfo: data.contentNodes?.pageInfo || {
|
||||
hasNextPage: false,
|
||||
endCursor: null
|
||||
},
|
||||
authorLogin: login
|
||||
};
|
||||
},
|
||||
{ ttl: CACHE_TTL.POSTS }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export async function getAuthorData(slug) {
|
||||
const cacheKey = `author-data:slug:${slug}`;
|
||||
|
||||
return await cache.wrap(
|
||||
cacheKey,
|
||||
async () => {
|
||||
const baseUrl = import.meta.env.WP_REST_BASE_URL.replace(/\/$/, '');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${baseUrl}/author/${slug}`);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
return null;
|
||||
}
|
||||
throw new Error(`HTTP error: ${response.status}`);
|
||||
}
|
||||
|
||||
const author = await response.json();
|
||||
|
||||
// Форматируем ответ
|
||||
return {
|
||||
id: author.slug || author.id,
|
||||
name: author.name,
|
||||
firstName: author.firstName,
|
||||
lastName: author.lastName,
|
||||
avatar: author.photo || author.avatar,
|
||||
avatar_sizes: author.photo_sizes || {},
|
||||
bio: author.description,
|
||||
social: author.social || {},
|
||||
url: author.url,
|
||||
type: author.type,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`❌ Failed to fetch author ${slug}:`, error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
{ ttl: CACHE_TTL.AUTHOR }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -398,6 +398,8 @@ export async function getPostsByTag(slug, first = 14, after = null) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//последние новости (кэшированная версия)
|
||||
export async function getLatestAnews(count = 12): Promise<AnewsPost[]> {
|
||||
const cacheKey = `latest-anews:${count}`;
|
||||
|
||||
3
src/lib/cache/cache-ttl.ts
vendored
3
src/lib/cache/cache-ttl.ts
vendored
@@ -3,7 +3,8 @@
|
||||
*/
|
||||
export const CACHE_TTL = {
|
||||
TAXONOMY: parseInt(import.meta.env.CACHE_TAXONOMY_TTL || '3600'),
|
||||
POSTS: parseInt(import.meta.env.CACHE_POST_TTL || '1800')
|
||||
POSTS: parseInt(import.meta.env.CACHE_POST_TTL || '1800'),
|
||||
AUTHOR: parseInt(import.meta.env.CACHE_AUTHOR_TTL || '8')
|
||||
} as const;
|
||||
|
||||
// Для отключения кэша
|
||||
|
||||
Reference in New Issue
Block a user