Files
profile-front/src/lib/api/authors.ts

371 lines
9.5 KiB
TypeScript
Raw Normal View History

2026-03-02 23:10:31 +03:00
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 }
);
}