laconic.com/src/lib/datocms-bypass.ts
2023-04-22 00:47:54 -04:00

819 lines
20 KiB
TypeScript

import cms from 'lib/cms'
import BlogPostRecord from 'lib/cms/generated'
import {
getBlogPosts as serverGetBlogPosts,
getBlogPostsCategories as serverGetBlogPostsCategories
} from 'lib/blog'
import path from 'path';
import { promises as fs } from 'fs';
//-----misc helpers
function datocmsDateToIng(date : string) : number {
let dateInt = 0;
date = date.replace(/\D/g,'');
dateInt = parseInt(date);
if (Number.isInteger(dateInt) !== true) {
dateInt = 0;
}
return dateInt;
}
//-----graphql query interception
export async function datocmsQueryIntercept(query : any) {
let parent = pluckFirstParentFromQuery(query);
let pageQueryWhitelist = getPageQueryBypassWhitelist();
let listingQueryWhitelist = getListingQueryDirectories();
let interceptData = {};
if (listingQueryWhitelist.includes(parent)) {
interceptData = await datocmsListingQueryIntercept(query);
} else if (pageQueryWhitelist.includes(parent)) {
interceptData = await datocmsPageQueryIntercept(query);
} else {
let errorText = 'Unable to intercept datocms query. No viable JSON alternative was defined.';
interceptData = {error: errorText};
}
return interceptData;
}
function getPageQueryBypassWhitelist() : string[] {
//-----stuff that has been (to the best of my knowledge) completley pulled over into JSON
//-----does not include iterative stuff like blog posts or events etc...
//-----this may only end up being scaffolding.
let whitelist : string [] = [];
whitelist.push('aboutPage');
whitelist.push('careersPage');
whitelist.push('communityPage');
whitelist.push('contactPage');
whitelist.push('homePage');
whitelist.push('partnersPage');
whitelist.push('pressPage');
whitelist.push('privacyPage');
whitelist.push('productsPage');
whitelist.push('termsPage');
whitelist.push('header');
whitelist.push('footer');
return whitelist;
}
function getListingQueryDirectories() : string[] {
//-----whitelist the listying types of content...
let directories : string[] = [];
directories.push('allEvents');
directories.push('allPositions');
directories.push('allPressReleases');
directories.push('allTeams');
directories.push('allTestimonials');
return directories;
}
function pluckFirstParentFromQuery(query : any) : string {
//-----only plucks the FIRST parent, if there are multiple parents in the query they will be ignored.
let parent : string = ((query.replace(/[\W_]+/g," ")).trim()).split(" ")[0];
return parent;
}
async function datocmsPageQueryIntercept(query : any) : Promise<any> {
let parent : string = pluckFirstParentFromQuery(query);
let jsonDirectory : string = path.join(process.cwd(), 'json/site_content');
let jsonPath : string = jsonDirectory + '/' + parent + '.json';
let fileRawContents : string = '';
let fileJson : any = {}
let jsonData : any = {}
try {
fileRawContents = await fs.readFile(jsonPath, 'utf8');
fileJson = JSON.parse(fileRawContents);
jsonData = fileJson.data;
} catch (e) {
console.log('Failed to parse JSON for file ' + jsonPath);
console.log('JSON parse attempt resulted in the following error:');
console.log(e);
}
return jsonData;
}
async function datocmsListingQueryIntercept(query : any) : Promise<any> {
let parent : string = pluckFirstParentFromQuery(query);
let jsonData : any = {};
switch(parent) {
case 'allBlogPosts':
//-----blog listing is handled in its own annoyingly special way
//-----could build it out here to be verbose but will not in the intrest of time/budget
//-----might need to add/remove some parent nodes in the JSON returned from getAllBlogPostsJson(); to match the would-be expected format.
//jsonData = await getAllBlogPostsJson();
jsonData = {};
break;
case 'allCategories':
//-----category listing is handled in its own annoyingly special way
//-----could build it out here to be verbose but will not in the intrest of time/budget
//-----might need to add/remove some parent nodes in the JSON returned from getAllBlogCategoriesJson(); to match the would-be expected format.
//jsonData = await getAllBlogCategoriesJson();
jsonData = {};
break;
case 'allEvents':
jsonData = await getAllEventsJson();
break;
case 'allPositions':
jsonData = await getAllPositionsJson();
break;
case 'allPressReleases':
jsonData = await getAllPressReleasesJson();
break;
case 'allTeams':
jsonData = await getAllTeamsJson();
break;
case 'allTestimonials':
jsonData = await getAllTestimonialsJson();
break;
default:
jsonData = {};
break;
}
return jsonData;
}
//-----json traversal
function jsonFilePathIsValid(filePath : string) {
if (filePath.startsWith("_")) {
return false;
}
if (!filePath.endsWith(".json")) {
return false;
}
return true;
}
function jsonNodeExists(jsonData : any, node : string) {
//-----this condition is unneccessary... so THATS what typescript is for XD
//if (typeof node === 'string' || node instanceof String) {
if (node in jsonData === true) {
return true;
}
//}
return false;
}
function jsonNodesExist(jsonData : any, nodes : any) {
//-----permit basic validation of the json we are trying to spit out by checking for existence of first order nodes
let node = '';
let nodeGroup : any = [];
let nodeGroupNode = '';
let nodeGroupValid = false;
for (let i = 0; i < nodes.length; i++) {
node = nodes[i];
if (typeof node === 'string') {
//-----string means that PRIMARY node must exist... no checking for children etc...
if (jsonNodeExists(jsonData, node) === false) {
return false;
}
} else if (Array.isArray(node)) {
//-----array means json is valid if ANY of the nodes in that array exist
nodeGroup = node;
nodeGroupValid = false;
for (let j = 0; j < nodeGroup.length; j++) {
nodeGroupNode = nodeGroup[j];
if (jsonNodeExists(jsonData, nodeGroupNode) === true) {
nodeGroupValid = true;
}
}
if (nodeGroupValid === false) {
//-----none of the nodes in the group exist.
return false;
}
} else {
//-----lets not get too crazy here.
return false;
}
}
return true;
}
export async function getJsonItemsFromDirectory(jsonDirectory : string, pluckerFunction : any, validationNodes : any[]) : Promise<any> {
let jsonFiles = await fs.readdir(jsonDirectory);
let returnJson = [];
for (let i = 0; i < jsonFiles.length; i++) {
let jsonFile = jsonFiles[i];
if (jsonFilePathIsValid(jsonFile) === true) {
let jsonPath = path.join(jsonDirectory, jsonFile);
let fileRawContents = await fs.readFile(jsonPath, 'utf8');
let fileJsonContents = {};
let jsonParseSuccess = false;
try {
fileJsonContents = JSON.parse(fileRawContents);
jsonParseSuccess = true;
} catch (e) {
jsonParseSuccess = false;
console.log('Failed to parse JSON for file ' + jsonPath);
console.log('JSON parse attempt resulted in the following error:');
console.log(e);
}
if (jsonParseSuccess === true) {
fileJsonContents = JSON.parse(fileRawContents);
let jsonData = pluckerFunction(fileJsonContents);
jsonData.sourceFile = jsonFile;
if (jsonNodesExist(jsonData, validationNodes) === true) {
returnJson.push(jsonData);
}
}
}
}
return returnJson;
}
//-----blogPosts
function getBlogJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/blogPost');
}
function pluckBlogPostData(json : any) {
let plucked : BlogPostRecord = {};
if('data' in json){
if('blogPost' in json.data) {
plucked = json.data.blogPost;
}
}
return plucked;
}
function getRequiedBlogPostNodes() : any[] {
let nodes = [];
let contentNodes = [];
contentNodes.push('content');
contentNodes.push('htmlContent');
//-----slug is now set per the JSON filename to avoid mismatches in routing
//nodes.push('slug');
nodes.push('date');
nodes.push('title');
nodes.push(contentNodes);
return nodes;
}
function forceBlogPostsJsonSlugIntegrity(json : any) {
//-----this is used to force the blog post slug to match that of its parent file name.
let returnJson = [];
for (let i = 0; i < json.length; i++) {
let blogPost = json[i];
let sourceFile = blogPost.sourceFile;
let newSlug = path.parse(sourceFile).name;
blogPost.slug = newSlug;
returnJson.push(blogPost);
}
return returnJson;
}
function sortBlogPostsJsonByDate(json : any) {
let sortedJson = json.slice().sort((a : any, b: any) => datocmsDateToIng(b.date) - datocmsDateToIng(a.date));
return sortedJson;
}
function getFakePaginationData(json : any) {
let pagination : any = {};
let totalPosts = json.length;
pagination.nextPage = null;
pagination.page = 1;
pagination.step = totalPosts;
pagination.total = totalPosts;
pagination.totalPages = 1;
return pagination;
}
async function getAllBlogPostsJson() {
let jsonDirectory = getBlogJsonDirectoryPath();
let validationNodes = getRequiedBlogPostNodes();
let blogPosts = await getJsonItemsFromDirectory(jsonDirectory, pluckBlogPostData, validationNodes);
let pagination = getFakePaginationData(blogPosts);
let processedBlogPosts = forceBlogPostsJsonSlugIntegrity(blogPosts);
let sortedBlogPosts = sortBlogPostsJsonByDate(processedBlogPosts);
let allBlogPostsJson = {pagination: pagination, data: sortedBlogPosts};
return allBlogPostsJson;
}
export async function getAllBlogPostsSlugsFromSource() {
let jsonDirectory = getBlogJsonDirectoryPath();
let jsonFiles = await fs.readdir(jsonDirectory);
let slugs = [];
for (let i = 0; i < jsonFiles.length; i++) {
let jsonFile = jsonFiles[i];
if (jsonFilePathIsValid(jsonFile) === true) {
let slug = path.parse(jsonFile).name;
let node = {slug : slug};
slugs.push(node);
}
}
return slugs;
}
export async function getAllBlogPostsFromSource(datocmsFilters : any) : Promise<any> {
let allBlogPostsFromSource : any = {};
if (process.env.NEXT_PUBLIC_DATOCMS_BYPASS_TYPE === "local_json") {
allBlogPostsFromSource = await getAllBlogPostsJson();
} else {
allBlogPostsFromSource = serverGetBlogPosts(datocmsFilters);
}
return allBlogPostsFromSource;
}
async function getSingleBlogPostJsonBySlug(slug : string) : Promise<any> {
let jsonDirectory = getBlogJsonDirectoryPath();
let jsonFile = slug + '.json';
let jsonPath = path.join(jsonDirectory, jsonFile);
let blogPost : any = {};
try {
let fileRawContents = await fs.readFile(jsonPath, 'utf8');
let fileJsonContents = JSON.parse(fileRawContents);
blogPost = pluckBlogPostData(fileJsonContents);
//-----continue to enforce standard set by forceBlogPostsJsonSlugIntegrity()
blogPost.slug = slug;
} catch (e) {
console.log('Failed to open or parse JSON for file ' + jsonPath);
console.log('JSON parse attempt resulted in the following error:');
console.log(e);
}
return blogPost;
}
export async function getSingleBlogPostBySlugFromSource(slug : string) : Promise<any> {
let blogPostJson : any = {};
if (process.env.NEXT_PUBLIC_DATOCMS_BYPASS_TYPE === "local_json") {
try {
//-----old highly inefficent way,
//-----used before we forced slug to be re written per filename via forceBlogPostsJsonSlugIntegrity()
/*
let blogPosts = await getAllBlogPostsJson();
let blogPostsData = blogPosts.data;
let slugMatches = blogPostsData.filter(
function(blogPostsData) {
return blogPostsData.slug == slug;
}
);
blogPostJson = slugMatches[0];
*/
blogPostJson = await getSingleBlogPostJsonBySlug(slug);
} catch (e) {
console.log('Failed pull blog post with slug ' + slug);
console.log('The attempt resulted in the following error:');
console.log(e);
}
} else {
blogPostJson = await (await cms().SingleBlogPost({ slug })).blogPost
}
return blogPostJson;
}
function getBlogPostCategorySlugs(blogPostJson : any) {
let categories = [];
try {
let categoryNode = blogPostJson.category;
for (let i = 0; i < categoryNode.length; i++) {
let category = categoryNode[i].slug;
categories.push(category);
}
} catch (e) {
console.log('Failed pull blog post categories');
console.log('The attempt resulted in the following error:');
console.log(e);
}
return categories;
}
export async function getRelatedBlogPosts(blogPostJson : any, matchCount : number) : Promise<any> {
let relatedBlogPosts = [];
let reservedSlugs = []
let matchedCount = 0;
let matchCategories = getBlogPostCategorySlugs(blogPostJson);
let blogPosts = await getAllBlogPostsJson();
let blogPostsData = blogPosts.data;
let candidateBlogPost : any = {};
let candidateBlogPostSlug = '';
let slug = blogPostJson.slug;
if (matchCategories.length > 0) {
reservedSlugs.push(slug);
for (let i = 0; i < blogPostsData.length; i++) {
candidateBlogPost = blogPostsData[i];
candidateBlogPostSlug = candidateBlogPost.slug;
if (matchedCount >= matchCount) {
break;
}
if (reservedSlugs.includes(candidateBlogPostSlug) === false) {
let candidateCategories = getBlogPostCategorySlugs(candidateBlogPost);
for (let j = 0; j < matchCategories.length; j++) {
let matchCategory = matchCategories[j];
if (candidateCategories.includes(matchCategory) === true && reservedSlugs.includes(candidateBlogPostSlug) === false) {
relatedBlogPosts.push(candidateBlogPost);
reservedSlugs.push(candidateBlogPostSlug)
matchedCount++;
break;
}
}
}
}
}
if (matchedCount < matchCount) {
//-----if not enough matches, pull in anything thats left...
for (let i = 0; i < blogPostsData.length; i++) {
candidateBlogPost = blogPostsData[i];
candidateBlogPostSlug = candidateBlogPost.slug;
if (matchedCount >= matchCount) {
break;
}
if (reservedSlugs.includes(candidateBlogPostSlug) === false) {
relatedBlogPosts.push(candidateBlogPost);
reservedSlugs.push(candidateBlogPostSlug)
matchedCount++;
}
}
}
return relatedBlogPosts;
}
//-----category
function getBlogCategoriesJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/category');
}
function pluckBlogCategoriesData(json : any) {
let plucked = {};
if('data' in json){
if('category' in json.data) {
plucked = json.data.category;
}
}
return plucked;
}
function getRequiedBlogBlogCategoryNodes() {
let nodes = [];
nodes.push('slug');
nodes.push('title');
return nodes;
}
export async function getAllBlogCategoriesJson() : Promise<any> {
let jsonDirectory = getBlogCategoriesJsonDirectoryPath();
let validationNodes = getRequiedBlogBlogCategoryNodes();
let allBlogCategoriesJson = await getJsonItemsFromDirectory(jsonDirectory, pluckBlogCategoriesData, validationNodes)
return allBlogCategoriesJson;
}
export async function getAllBlogPostsCategoriesFromSource() : Promise<any> {
let allBlogPostsCategoriesFromSource = {};
if (process.env.NEXT_PUBLIC_DATOCMS_BYPASS_TYPE === "local_json") {
allBlogPostsCategoriesFromSource = await getAllBlogCategoriesJson();
//let requestResults = await request(AllCategoriesQuery);
//allBlogPostsCategoriesFromSource = requestResults.allCategories;
} else {
allBlogPostsCategoriesFromSource = serverGetBlogPostsCategories();
}
return allBlogPostsCategoriesFromSource;
}
//-----event
function getEventsJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/event');
}
function pluckEventData(json : any) {
let plucked = {};
if('data' in json){
if('event' in json.data) {
plucked = json.data.event;
}
}
return plucked;
}
function getRequiedEventNodes() {
let nodes = [];
nodes.push('title');
nodes.push('eventLocation');
nodes.push('eventStartdate');
nodes.push('eventEnddate');
return nodes;
}
function sortEventsJsonByStartDate(json : any) {
let sortedJson = json.slice().sort((a : any, b: any) => datocmsDateToIng(b.eventStartdate) - datocmsDateToIng(a.eventStartdate));
return sortedJson;
}
async function getAllEventsJson() : Promise<any> {
let jsonDirectory = getEventsJsonDirectoryPath();
let validationNodes = getRequiedEventNodes();
let events = await getJsonItemsFromDirectory(jsonDirectory, pluckEventData, validationNodes);
let sortedEvents = sortEventsJsonByStartDate(events);
let allEventsJson = {allEvents: sortedEvents};
return allEventsJson;
}
//-----position
function getPositionsJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/position');
}
function pluckPositionData(json : any) {
let plucked = {};
if('data' in json){
if('position' in json.data) {
plucked = json.data.position;
}
}
return plucked;
}
function getRequiedPositionNodes() {
let nodes = [];
nodes.push('id');
nodes.push('positionName');
nodes.push('positionLink');
return nodes;
}
function sortPositionsJsonById(json : any) {
let sortedJson = json.slice().sort((a : any, b: any) => parseInt(a.id) - parseInt(b.id));
return sortedJson;
}
async function getAllPositionsJson() : Promise<any> {
let jsonDirectory = getPositionsJsonDirectoryPath();
let validationNodes = getRequiedPositionNodes();
let positions = await getJsonItemsFromDirectory(jsonDirectory, pluckPositionData, validationNodes);
let sortedPositions = sortPositionsJsonById(positions);
let allPositionsJson = {allPositions: sortedPositions};
return allPositionsJson;
}
//-----pressRelease
function getPressReleasesJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/pressRelease');
}
function pluckPressReleaseData(json : any) {
let plucked = {};
if('data' in json){
if('pressRelease' in json.data) {
plucked = json.data.pressRelease;
}
}
return plucked;
}
function getRequiedPressReleaseNodes() {
let nodes = [];
nodes.push('id');
nodes.push('title');
nodes.push('date');
nodes.push('link');
return nodes;
}
function sortPressReleasesJsonByDate(json : any) {
let sortedJson = json.slice().sort((a : any, b: any) => datocmsDateToIng(b.date) - datocmsDateToIng(a.date));
return sortedJson;
}
async function getAllPressReleasesJson() : Promise<any> {
let jsonDirectory = getPressReleasesJsonDirectoryPath();
let validationNodes = getRequiedPressReleaseNodes();
let pressReleases = await getJsonItemsFromDirectory(jsonDirectory, pluckPressReleaseData, validationNodes);
let sortedPressReleases = sortPressReleasesJsonByDate(pressReleases);
let allPressReleasesJson = {allPressReleases: sortedPressReleases};
return allPressReleasesJson;
}
//-----team
function getTeamsJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/team');
}
function pluckTeamData(json : any) {
let plucked = {};
if('data' in json){
if('team' in json.data) {
plucked = json.data.team;
}
}
return plucked;
}
function getRequiedTeamNodes() {
let nodes = [];
nodes.push('id');
nodes.push('memberName');
return nodes;
}
function sortTeamsJsonById(json : any) {
let sortedJson = json.slice().sort((a : any, b: any) => parseInt(a.id) - parseInt(b.id));
return sortedJson;
}
async function getAllTeamsJson() : Promise<any> {
let jsonDirectory = getTeamsJsonDirectoryPath();
let validationNodes = getRequiedTeamNodes();
let teams = await getJsonItemsFromDirectory(jsonDirectory, pluckTeamData, validationNodes);
let sortedTeams = sortTeamsJsonById(teams);
let allTeamsJson = {allTeams: sortedTeams};
return allTeamsJson;
}
//-----testimonial
function getTestimonialsJsonDirectoryPath() {
return path.join(process.cwd(), 'json/site_content/testimonial');
}
function pluckTestimonialData(json : any) {
let plucked = {};
if('data' in json){
if('testimonial' in json.data) {
plucked = json.data.testimonial;
}
}
return plucked;
}
function getRequiedTestimonialNodes() {
let nodes = [];
nodes.push('id');
nodes.push('testimonialImage');
nodes.push('testimonialText');
nodes.push('testimonialUsername');
return nodes;
}
function sortTestimonialsJsonById(json : any) {
let sortedJson = json.slice().sort((a : any, b: any) => parseInt(a.id) - parseInt(b.id));
return sortedJson;
}
async function getAllTestimonialsJson() : Promise<any> {
let jsonDirectory = getTestimonialsJsonDirectoryPath();
let validationNodes = getRequiedTestimonialNodes();
let testimonials = await getJsonItemsFromDirectory(jsonDirectory, pluckTestimonialData, validationNodes);
let sortedTestimonals = sortTestimonialsJsonById(testimonials);
let allTestimonialsJson = {allTestimonials: sortedTestimonals};
return allTestimonialsJson;
}