From e270c56f1a80dc8d6a7c8124312f6144ee32e1c8 Mon Sep 17 00:00:00 2001
From: decobot
Date: Wed, 18 Sep 2024 19:09:42 -0300
Subject: [PATCH] feat(blog): extension props
---
.../extensions/BlogpostList/ratings.ts | 22 +++++-
.../extensions/BlogpostList/reviews.ts | 17 ++++-
.../extensions/BlogpostListing/ratings.ts | 24 +++++--
.../extensions/BlogpostListing/reviews.ts | 19 +++--
.../extensions/BlogpostPage/ratings.ts | 17 ++++-
.../extensions/BlogpostPage/reviews.ts | 22 +++++-
blog/sections/Template.tsx | 8 ++-
blog/types.ts | 11 +++
blog/utils/records.ts | 71 +++++++++++++++----
9 files changed, 176 insertions(+), 35 deletions(-)
diff --git a/blog/loaders/extensions/BlogpostList/ratings.ts b/blog/loaders/extensions/BlogpostList/ratings.ts
index 72a9a13ca..bfb5a3731 100644
--- a/blog/loaders/extensions/BlogpostList/ratings.ts
+++ b/blog/loaders/extensions/BlogpostList/ratings.ts
@@ -1,14 +1,25 @@
import { ExtensionOf } from "../../../../website/loaders/extension.ts";
import { AppContext } from "../../../mod.ts";
-import { BlogPost } from "../../../types.ts";
+import { BlogPost, Ignore } from "../../../types.ts";
import { getRatings } from "../../../utils/records.ts";
+interface Props {
+ /**
+ * @description Ignore ratings in the aggregateRating calc
+ */
+ ignoreRatings?: Ignore;
+ /**
+ * @description Return only aggregate rating object
+ */
+ onlyAggregate?: boolean;
+}
+
/**
* @title ExtensionOf BlogPost list: Ratings
* @description It can harm performance. Use wisely
*/
export default function ratingsExt(
- _props: unknown,
+ { ignoreRatings, onlyAggregate }: Props,
_req: Request,
ctx: AppContext,
): ExtensionOf {
@@ -19,7 +30,12 @@ export default function ratingsExt(
const postsWithRatings = await Promise.all(
posts.map(async (post) => {
- const ratings = await getRatings({ post, ctx });
+ const ratings = await getRatings({
+ post,
+ ctx,
+ ignoreRatings,
+ onlyAggregate,
+ });
return { ...post, ...ratings };
}),
);
diff --git a/blog/loaders/extensions/BlogpostList/reviews.ts b/blog/loaders/extensions/BlogpostList/reviews.ts
index bd3fc46ff..83df367fe 100644
--- a/blog/loaders/extensions/BlogpostList/reviews.ts
+++ b/blog/loaders/extensions/BlogpostList/reviews.ts
@@ -1,14 +1,25 @@
import { ExtensionOf } from "../../../../website/loaders/extension.ts";
import { AppContext } from "../../../mod.ts";
-import { BlogPost } from "../../../types.ts";
+import { BlogPost, Ignore } from "../../../types.ts";
import { getReviews } from "../../../utils/records.ts";
+interface Props {
+ /**
+ * @description Ignore specific reviews
+ */
+ ignoreReviews?: Ignore;
+ /**
+ * @description Order By
+ */
+ orderBy?: "date_asc" | "date_desc";
+}
+
/**
* @title ExtensionOf BlogPost list: Reviews
* @description It can harm performance. Use wisely
*/
export default function reviewsExt(
- _props: unknown,
+ { ignoreReviews, orderBy }: Props,
_req: Request,
ctx: AppContext,
): ExtensionOf {
@@ -19,7 +30,7 @@ export default function reviewsExt(
const postsWithReviews = await Promise.all(
posts.map(async (post) => {
- const reviews = await getReviews({ post, ctx });
+ const reviews = await getReviews({ post, ctx, ignoreReviews, orderBy });
return { ...post, ...reviews };
}),
);
diff --git a/blog/loaders/extensions/BlogpostListing/ratings.ts b/blog/loaders/extensions/BlogpostListing/ratings.ts
index abe8ddd6d..2d33e7e21 100644
--- a/blog/loaders/extensions/BlogpostListing/ratings.ts
+++ b/blog/loaders/extensions/BlogpostListing/ratings.ts
@@ -1,14 +1,25 @@
import { ExtensionOf } from "../../../../website/loaders/extension.ts";
import { AppContext } from "../../../mod.ts";
-import { BlogPostListingPage } from "../../../types.ts";
+import { BlogPostListingPage, Ignore } from "../../../types.ts";
import { getRatings } from "../../../utils/records.ts";
+interface Props {
+ /**
+ * @description Ignore ratings in the aggregateRating calc
+ */
+ ignoreRatings?: Ignore;
+ /**
+ * @description Return only aggregate rating object
+ */
+ onlyAggregate?: boolean;
+}
+
/**
- * @title ExtensionOf BlogPostPage: Ratings
+ * @title ExtensionOf BlogPostListing: Ratings
* @description It can harm performance. Use wisely
*/
export default function ratingsExt(
- _props: unknown,
+ { ignoreRatings, onlyAggregate }: Props,
_req: Request,
ctx: AppContext,
): ExtensionOf {
@@ -19,7 +30,12 @@ export default function ratingsExt(
const posts = await Promise.all(
blogpostListingPage.posts.map(async (post) => {
- const ratings = await getRatings({ post, ctx });
+ const ratings = await getRatings({
+ post,
+ ctx,
+ onlyAggregate,
+ ignoreRatings,
+ });
return { ...post, ...ratings };
}),
);
diff --git a/blog/loaders/extensions/BlogpostListing/reviews.ts b/blog/loaders/extensions/BlogpostListing/reviews.ts
index ee5919f5d..f91a84b4b 100644
--- a/blog/loaders/extensions/BlogpostListing/reviews.ts
+++ b/blog/loaders/extensions/BlogpostListing/reviews.ts
@@ -1,14 +1,25 @@
import { ExtensionOf } from "../../../../website/loaders/extension.ts";
import { AppContext } from "../../../mod.ts";
-import { BlogPostListingPage } from "../../../types.ts";
+import { BlogPostListingPage, Ignore } from "../../../types.ts";
import { getReviews } from "../../../utils/records.ts";
+interface Props {
+ /**
+ * @description Ignore specific reviews
+ */
+ ignoreReviews?: Ignore;
+ /**
+ * @description Order By
+ */
+ orderBy?: "date_asc" | "date_desc";
+}
+
/**
- * @title ExtensionOf BlogPostPage: Reviews
+ * @title ExtensionOf BlogPostListing: Reviews
* @description It can harm performance. Use wisely
*/
export default function reviewsExt(
- _props: unknown,
+ { ignoreReviews, orderBy }: Props,
_req: Request,
ctx: AppContext,
): ExtensionOf {
@@ -19,7 +30,7 @@ export default function reviewsExt(
const posts = await Promise.all(
blogpostListingPage.posts.map(async (post) => {
- const reviews = await getReviews({ post, ctx });
+ const reviews = await getReviews({ post, ctx, ignoreReviews, orderBy });
return { ...post, ...reviews };
}),
);
diff --git a/blog/loaders/extensions/BlogpostPage/ratings.ts b/blog/loaders/extensions/BlogpostPage/ratings.ts
index bbd6b385b..bf4f66083 100644
--- a/blog/loaders/extensions/BlogpostPage/ratings.ts
+++ b/blog/loaders/extensions/BlogpostPage/ratings.ts
@@ -1,14 +1,21 @@
import { ExtensionOf } from "../../../../website/loaders/extension.ts";
import { AppContext } from "../../../mod.ts";
-import { BlogPostPage } from "../../../types.ts";
+import { BlogPostPage, Ignore } from "../../../types.ts";
import { getRatings } from "../../../utils/records.ts";
+interface Props {
+ /**
+ * @description Ignore ratings in the aggregateRating calc
+ */
+ ignoreRatings?: Ignore;
+}
+
/**
* @title ExtensionOf BlogPostPage: Ratings
* @description It can harm performance. Use wisely
*/
export default function ratingsExt(
- _props: unknown,
+ { ignoreRatings }: Props,
_req: Request,
ctx: AppContext,
): ExtensionOf {
@@ -16,7 +23,11 @@ export default function ratingsExt(
if (!blogpostPage) {
return null;
}
- const post = await getRatings({ post: blogpostPage.post, ctx });
+ const post = await getRatings({
+ post: blogpostPage.post,
+ ctx,
+ ignoreRatings,
+ });
return { ...blogpostPage, post };
};
}
diff --git a/blog/loaders/extensions/BlogpostPage/reviews.ts b/blog/loaders/extensions/BlogpostPage/reviews.ts
index ca5481142..6b8f08c20 100644
--- a/blog/loaders/extensions/BlogpostPage/reviews.ts
+++ b/blog/loaders/extensions/BlogpostPage/reviews.ts
@@ -1,14 +1,25 @@
import { ExtensionOf } from "../../../../website/loaders/extension.ts";
import { AppContext } from "../../../mod.ts";
-import { BlogPostPage } from "../../../types.ts";
+import { BlogPostPage, Ignore } from "../../../types.ts";
import { getReviews } from "../../../utils/records.ts";
+interface Props {
+ /**
+ * @description Ignore specific reviews
+ */
+ ignoreReviews?: Ignore;
+ /**
+ * @description Order By
+ */
+ orderBy?: "date_asc" | "date_desc";
+}
+
/**
* @title ExtensionOf BlogPostPage: Reviews
* @description It can harm performance. Use wisely
*/
export default function reviewsExt(
- _props: unknown,
+ { ignoreReviews, orderBy }: Props,
_req: Request,
ctx: AppContext,
): ExtensionOf {
@@ -16,7 +27,12 @@ export default function reviewsExt(
if (!blogpostPage) {
return null;
}
- const post = await getReviews({ post: blogpostPage.post, ctx });
+ const post = await getReviews({
+ post: blogpostPage.post,
+ ctx,
+ ignoreReviews,
+ orderBy,
+ });
return { ...blogpostPage, post };
};
}
diff --git a/blog/sections/Template.tsx b/blog/sections/Template.tsx
index 8dcb278fe..4ee094d3b 100644
--- a/blog/sections/Template.tsx
+++ b/blog/sections/Template.tsx
@@ -14,7 +14,7 @@ export default function Template({ post }: Props) {
excerpt = "Excerpt",
date,
image,
- alt
+ alt,
} = post;
return (
@@ -33,7 +33,11 @@ export default function Template({ post }: Props) {
: ""}
{image && (
-
+
)}
diff --git a/blog/types.ts b/blog/types.ts
index 491c0d036..97730a1e1 100644
--- a/blog/types.ts
+++ b/blog/types.ts
@@ -148,3 +148,14 @@ export interface AggregateRating {
/** The lowest value allowed in this rating system. */
worstRating?: number;
}
+
+export interface Ignore {
+ /**
+ * @title Active
+ */
+ active?: boolean;
+ /**
+ * @title When additionalType is marked with:
+ */
+ markedAs?: string[];
+}
diff --git a/blog/utils/records.ts b/blog/utils/records.ts
index 4a3b1340c..d22bbab79 100644
--- a/blog/utils/records.ts
+++ b/blog/utils/records.ts
@@ -1,8 +1,14 @@
import { rating, review } from "../db/schema.ts";
import { AppContext } from "../mod.ts";
import { type Resolvable } from "@deco/deco";
-import { eq } from "https://esm.sh/drizzle-orm@0.30.10";
-import { BlogPost, Rating, Review } from "../types.ts";
+import {
+ and,
+ asc,
+ desc,
+ eq,
+ notInArray,
+} from "https://esm.sh/drizzle-orm@0.30.10";
+import { BlogPost, Ignore, Rating, Review } from "../types.ts";
import { logger } from "@deco/deco/o11y";
export async function getRecordsByPath(
@@ -49,28 +55,44 @@ export async function getRatingsBySlug(
}
export async function getRatings(
- { ctx, post }: { ctx: AppContext; post: BlogPost },
+ { ctx, post, ignoreRatings, onlyAggregate }: {
+ ctx: AppContext;
+ post: BlogPost;
+ ignoreRatings?: Ignore;
+ onlyAggregate?: boolean;
+ },
): Promise {
const contentRating = await getRatingsBySlug({
ctx,
slug: post.slug,
});
- const ratingValue = contentRating.length === 0 ? 0 : contentRating.reduce(
- (acc, rating) => acc = acc + rating!.ratingValue!,
- 0,
- ) / contentRating.length;
+ const { ratingCount, ratingTotal } = contentRating.length === 0
+ ? { ratingCount: 0, ratingTotal: 0 }
+ : contentRating.reduce(
+ (acc, { ratingValue, additionalType }) =>
+ ignoreRatings?.active && additionalType &&
+ ignoreRatings.markedAs?.includes(additionalType)
+ ? acc
+ : {
+ ratingCount: acc.ratingCount + 1,
+ ratingTotal: acc.ratingTotal + (ratingValue ?? 0),
+ },
+ { ratingCount: 0, ratingTotal: 0 },
+ );
+
+ const ratingValue = ratingTotal / ratingCount;
return {
...post,
- contentRating,
+ contentRating: onlyAggregate ? undefined : contentRating,
aggregateRating: {
...post.aggregateRating,
"@type": "AggregateRating",
- ratingCount: contentRating.length,
+ ratingCount,
+ ratingValue: isNaN(ratingValue) ? 0 : ratingValue,
bestRating: 5,
worstRating: 1,
- ratingValue,
},
};
}
@@ -103,9 +125,26 @@ export const getReviewById = async (
};
export async function getReviewsBySlug(
- { ctx, slug }: { ctx: AppContext; slug: string },
+ { ctx, slug, ignoreReviews, orderBy = "date_desc" }: {
+ ctx: AppContext;
+ slug: string;
+ ignoreReviews?: Ignore;
+ orderBy?: "date_asc" | "date_desc";
+ },
): Promise {
const records = await ctx.invoke.records.loaders.drizzle();
+
+ const whereClause = ignoreReviews?.active && ignoreReviews?.markedAs &&
+ ignoreReviews?.markedAs?.length > 0
+ ? and(
+ eq(review.itemReviewed, slug),
+ notInArray(review.additionalType, ignoreReviews.markedAs),
+ )
+ : eq(review.itemReviewed, slug);
+ const orderClause = orderBy.endsWith("desc")
+ ? desc(review.datePublished)
+ : asc(review.datePublished);
+
try {
const currentComments = await records.select({
itemReviewed: review.itemReviewed,
@@ -118,7 +157,7 @@ export async function getReviewsBySlug(
additionalType: review.additionalType,
id: review.id,
})
- .from(review).where(eq(review.itemReviewed, slug)) as
+ .from(review).where(whereClause).orderBy(orderClause) as
| Review[]
| undefined;
@@ -130,11 +169,17 @@ export async function getReviewsBySlug(
}
export async function getReviews(
- { ctx, post }: { ctx: AppContext; post: BlogPost },
+ { ctx, post, ...rest }: {
+ ctx: AppContext;
+ post: BlogPost;
+ ignoreReviews?: Ignore;
+ orderBy?: "date_asc" | "date_desc";
+ },
): Promise {
const review = await getReviewsBySlug({
ctx,
slug: post.slug,
+ ...rest,
});
return {