diff --git a/README.md b/README.md index 004d7ec..071095c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Provides a basic blog backend for Medusa. +[Documentation](https://pevey.com/medusa-plugin-blog) + If you are not familiar with Medusa, you can learn more on [the project web site](https://www.medusajs.com/). > Medusa is a set of commerce modules and tools that allow you to build rich, reliable, and performant commerce applications without reinventing core commerce logic. The modules can be customized and used to build advanced ecommerce stores, marketplaces, or any product that needs foundational commerce primitives. All modules are open-source and freely available on npm. diff --git a/src/api/index.ts b/src/api/index.ts index e4072ea..4114b88 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -7,242 +7,242 @@ import { z } from "zod" export default (rootDirectory: string): Router | Router[] => { - const config = configLoader(rootDirectory) - const storeCorsOptions = { origin: config.projectConfig.store_cors.split(","), credentials: true, } - const adminCorsOptions = { origin: config.projectConfig.admin_cors.split(","), credentials: true, } + const config = configLoader(rootDirectory) + const storeCorsOptions = { origin: config.projectConfig.store_cors.split(","), credentials: true, } + const adminCorsOptions = { origin: config.projectConfig.admin_cors.split(","), credentials: true, } - const router = Router() + const router = Router() - // GET ALL BLOG POSTS - router.get("/store/blog/posts", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogPosts().then((blog_posts) => { - return res.json(blog_posts) - }) - }) + // GET ALL BLOG POSTS + router.get("/store/blog/posts", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogPosts().then((blog_posts) => { + return res.json(blog_posts) + }) + }) - // GET ALL BLOG POSTS BY CATEGORY - router.get("/store/blog/categories/:handle/posts", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogPostsByCategoryHandle(req.params.handle).then((blog_posts) => { - return res.json(blog_posts) - }) - }) + // GET ALL BLOG POSTS BY CATEGORY + router.get("/store/blog/categories/:handle/posts", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogPostsByCategoryHandle(req.params.handle).then((blog_posts) => { + return res.json(blog_posts) + }) + }) - // GET A SINGLE BLOG POST BY HANDLE - router.get("/store/blog/posts/:handle", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogPostByHandle(req.params.handle).then((blog_post) => { - return res.json(blog_post) - }) - }) + // GET A SINGLE BLOG POST BY HANDLE + router.get("/store/blog/posts/:handle", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogPostByHandle(req.params.handle).then((blog_post) => { + return res.json(blog_post) + }) + }) - // GET ALL BLOG CATEGORIES - router.get("/store/blog/categories", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogCategories().then((blog_categories) => { - return res.json(blog_categories) - }) - }) + // GET ALL BLOG CATEGORIES + router.get("/store/blog/categories", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogCategories().then((blog_categories) => { + return res.json(blog_categories) + }) + }) - // GET A BLOG CATEGORY BY HANDLE - router.get("/store/blog/categories/:handle", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogCategoryByHandle(req.params.handle).then((blog_category) => { - return res.json(blog_category) - }) - }) + // GET A BLOG CATEGORY BY HANDLE + router.get("/store/blog/categories/:handle", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogCategoryByHandle(req.params.handle).then((blog_category) => { + return res.json(blog_category) + }) + }) - // GET ALL BLOG TAGS - router.get("/store/blog/tags", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogTags().then((blog_tags) => { - return res.json(blog_tags) - }) - }) + // GET ALL BLOG TAGS + router.get("/store/blog/tags", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogTags().then((blog_tags) => { + return res.json(blog_tags) + }) + }) - // GET ALL BLOG POSTS TAGGED WITH A TAG OR AN ARRAY OF TAGS - // Ex: /store/blog/tags/posts?tag=tag1&tag=tag2&tag=tag3 - router.get("/store/blog/tags/posts", cors(storeCorsOptions), async (req, res) => { - if (!req.query.tag) { return res.json([]) } - const tag_ids = (typeof req.query.tag === "string")? [req.query.tag] : req.query.tag - const blogService = req.scope.resolve("blogService") - blogService.getBlogPostsByTag(tag_ids).then((blog_posts) => { - return res.json(blog_posts) - }) - }) + // GET ALL BLOG POSTS TAGGED WITH A TAG OR AN ARRAY OF TAGS + // Ex: /store/blog/tags/posts?tag=tag1&tag=tag2&tag=tag3 + router.get("/store/blog/tags/posts", cors(storeCorsOptions), async (req, res) => { + if (!req.query.tag) { return res.json([]) } + const tag_ids = (typeof req.query.tag === "string")? [req.query.tag] : req.query.tag + const blogService = req.scope.resolve("blogService") + blogService.getBlogPostsByTag(tag_ids).then((blog_posts) => { + return res.json(blog_posts) + }) + }) - // GET ALL BLOG POSTS TAGGED WITH A PRODUCT - router.get("/store/blog/products/:id", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogPostsByProduct(req.params.id).then((blog_posts) => { - return res.json(blog_posts) - }) - }) + // GET ALL BLOG POSTS TAGGED WITH A PRODUCT + router.get("/store/blog/products/:id", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogPostsByProduct(req.params.id).then((blog_posts) => { + return res.json(blog_posts) + }) + }) - // GET ALL BLOG POSTS TAGGED WITH A COLLECTION - router.get("/store/blog/collections/:id", cors(storeCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.getBlogPostsByCollection(req.params.id).then((blog_posts) => { - return res.json(blog_posts) - }) - }) + // GET ALL BLOG POSTS TAGGED WITH A COLLECTION + router.get("/store/blog/collections/:id", cors(storeCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.getBlogPostsByCollection(req.params.id).then((blog_posts) => { + return res.json(blog_posts) + }) + }) - // ADD A BLOG CATEGORY - router.use("/admin/blog/categories", bodyParser.json()) - router.post("/admin/blog/categories", cors(adminCorsOptions), async (req, res) => { - const schema = z.object({ - handle: z.string().min(1), - title: z.string().min(1), - description: z.string().optional(), - keywords: z.string().array().optional(), - metadata: z.object({}).passthrough() as z.ZodObject<{}>, - }) - /* @ts-ignore */ - const { success, error, data } = schema.safeParse(req.body) - if (!success) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error) - } - const blogService = req.scope.resolve("blogService") - blogService.addBlogCategory(data).then((blog_category) => { - return res.json(blog_category) - }) - }) + // ADD A BLOG CATEGORY + router.use("/admin/blog/categories", bodyParser.json()) + router.post("/admin/blog/categories", cors(adminCorsOptions), async (req, res) => { + const schema = z.object({ + handle: z.string().min(1), + title: z.string().min(1), + description: z.string().optional(), + keywords: z.string().array().optional(), + metadata: z.object({}).passthrough() as z.ZodObject<{}>, + }) + /* @ts-ignore */ + const { success, error, data } = schema.safeParse(req.body) + if (!success) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error) + } + const blogService = req.scope.resolve("blogService") + blogService.addBlogCategory(data).then((blog_category) => { + return res.json(blog_category) + }) + }) - // UPDATE A BLOG CATEGORY - router.use("/admin/blog/categories/:id", bodyParser.json()) - router.post("/admin/blog/categories/:id", cors(adminCorsOptions), async (req, res) => { - const schema = z.object({ - handle: z.string().min(1), - title: z.string().min(1), - description: z.string().optional(), - keywords: z.string().array().optional(), - metadata: z.object({}).passthrough() as z.ZodObject<{}>, - }) - /* @ts-ignore */ - const { success, error, data } = schema.safeParse(req.body) - if (!success) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error) - } - const blogService = req.scope.resolve("blogService") - blogService.updateBlogCategory(req.params.id, data).then((blog_category) => { - return res.json(blog_category) - }) - }) + // UPDATE A BLOG CATEGORY + router.use("/admin/blog/categories/:id", bodyParser.json()) + router.post("/admin/blog/categories/:id", cors(adminCorsOptions), async (req, res) => { + const schema = z.object({ + handle: z.string().min(1), + title: z.string().min(1), + description: z.string().optional(), + keywords: z.string().array().optional(), + metadata: z.object({}).passthrough() as z.ZodObject<{}>, + }) + /* @ts-ignore */ + const { success, error, data } = schema.safeParse(req.body) + if (!success) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error) + } + const blogService = req.scope.resolve("blogService") + blogService.updateBlogCategory(req.params.id, data).then((blog_category) => { + return res.json(blog_category) + }) + }) - // DELETE A BLOG CATEGORY - router.delete("/admin/blog/categories/:id", cors(adminCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.deleteBlogCategory(req.params.id).then(() => { - return res.sendStatus(200) - }) - }) + // DELETE A BLOG CATEGORY + router.delete("/admin/blog/categories/:id", cors(adminCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.deleteBlogCategory(req.params.id).then(() => { + return res.sendStatus(200) + }) + }) - // ADD A BLOG POST - router.use("/admin/blog/posts", bodyParser.json()) - router.post("/admin/blog/posts", cors(adminCorsOptions), async (req, res) => { - const schema = z.object({ - handle: z.string().optional(), - title: z.string().min(1), - author: z.string().optional(), - published: z.boolean().default(false), - content: z.string().optional(), - description: z.string().optional(), - keywords: z.string().array().optional(), - category_id: z.string().optional(), - tag_ids: z.string().array().optional(), - product_ids: z.string().array().optional(), - collection_ids: z.string().array().optional(), - metadata: z.object({}).passthrough() as z.ZodObject<{}> - }) - /* @ts-ignore */ - const { success, error, data } = schema.safeParse(req.body) - if (!success) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error) - } - const blogService = req.scope.resolve("blogService") - blogService.addBlogPost(data).then((blog_post) => { - return res.json(blog_post) - }) - }) + // ADD A BLOG POST + router.use("/admin/blog/posts", bodyParser.json()) + router.post("/admin/blog/posts", cors(adminCorsOptions), async (req, res) => { + const schema = z.object({ + handle: z.string().optional(), + title: z.string().min(1), + author: z.string().optional(), + published: z.boolean().default(false), + content: z.string().optional(), + description: z.string().optional(), + keywords: z.string().array().optional(), + category_id: z.string().optional(), + tag_ids: z.string().array().optional(), + product_ids: z.string().array().optional(), + collection_ids: z.string().array().optional(), + metadata: z.object({}).passthrough() as z.ZodObject<{}> + }) + /* @ts-ignore */ + const { success, error, data } = schema.safeParse(req.body) + if (!success) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error) + } + const blogService = req.scope.resolve("blogService") + blogService.addBlogPost(data).then((blog_post) => { + return res.json(blog_post) + }) + }) - // UPDATE A BLOG POST - router.use("/admin/blog/posts/:id", bodyParser.json()) - router.post("/admin/blog/posts/:id", cors(adminCorsOptions), async (req, res) => { - const schema = z.object({ - handle: z.string().optional(), - title: z.string().min(1), - author: z.string().optional(), - published: z.boolean().default(false), - content: z.string().optional(), - description: z.string().optional(), - keywords: z.string().array().optional(), - category_id: z.string().optional(), - tag_ids: z.string().array().optional(), - product_ids: z.string().array().optional(), - collection_ids: z.string().array().optional(), - metadata: z.object({}).passthrough() as z.ZodObject<{}> - }) - /* @ts-ignore */ - const { success, error, data } = schema.safeParse(req.body) - if (!success) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error) - } - const blogService = req.scope.resolve("blogService") - blogService.updateBlogPost(req.params.id, data).then((blog_post) => { - return res.json(blog_post) - }) - }) + // UPDATE A BLOG POST + router.use("/admin/blog/posts/:id", bodyParser.json()) + router.post("/admin/blog/posts/:id", cors(adminCorsOptions), async (req, res) => { + const schema = z.object({ + handle: z.string().optional(), + title: z.string().min(1), + author: z.string().optional(), + published: z.boolean().default(false), + content: z.string().optional(), + description: z.string().optional(), + keywords: z.string().array().optional(), + category_id: z.string().optional(), + tag_ids: z.string().array().optional(), + product_ids: z.string().array().optional(), + collection_ids: z.string().array().optional(), + metadata: z.object({}).passthrough() as z.ZodObject<{}> + }) + /* @ts-ignore */ + const { success, error, data } = schema.safeParse(req.body) + if (!success) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error) + } + const blogService = req.scope.resolve("blogService") + blogService.updateBlogPost(req.params.id, data).then((blog_post) => { + return res.json(blog_post) + }) + }) - // DELETE A BLOG POST - router.delete("/admin/blog/posts/:id", cors(adminCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.deleteBlogPost(req.params.id).then(() => { - return res.sendStatus(200) - }) - }) + // DELETE A BLOG POST + router.delete("/admin/blog/posts/:id", cors(adminCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.deleteBlogPost(req.params.id).then(() => { + return res.sendStatus(200) + }) + }) - // ADD A BLOG TAG - router.use("/admin/blog/tags", bodyParser.json()) - router.post("/admin/blog/tags", cors(adminCorsOptions), async (req, res) => { - const schema = z.object({ - value: z.string().min(1) - }) - /* @ts-ignore */ - const { success, error, data } = schema.safeParse(req.body) - if (!success) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error) - } - const blogService = req.scope.resolve("blogService") - blogService.addBlogTag(data.value).then((blog_tag) => { - return res.json(blog_tag) - }) - }) + // ADD A BLOG TAG + router.use("/admin/blog/tags", bodyParser.json()) + router.post("/admin/blog/tags", cors(adminCorsOptions), async (req, res) => { + const schema = z.object({ + value: z.string().min(1) + }) + /* @ts-ignore */ + const { success, error, data } = schema.safeParse(req.body) + if (!success) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error) + } + const blogService = req.scope.resolve("blogService") + blogService.addBlogTag(data.value).then((blog_tag) => { + return res.json(blog_tag) + }) + }) - // UPDATE A BLOG TAG - router.use("/admin/blog/tags/:id", bodyParser.json()) - router.post("/admin/blog/tags/:id", cors(adminCorsOptions), async (req, res) => { - const schema = z.object({ - value: z.string().min(1) - }) - /* @ts-ignore */ - const { success, error, data } = schema.safeParse(req.body) - if (!success) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error) - } - const blogService = req.scope.resolve("blogService") - blogService.updateBlogTag(req.params.id, data.value).then((blog_tag) => { - return res.json(blog_tag) - }) - }) + // UPDATE A BLOG TAG + router.use("/admin/blog/tags/:id", bodyParser.json()) + router.post("/admin/blog/tags/:id", cors(adminCorsOptions), async (req, res) => { + const schema = z.object({ + value: z.string().min(1) + }) + /* @ts-ignore */ + const { success, error, data } = schema.safeParse(req.body) + if (!success) { + throw new MedusaError(MedusaError.Types.INVALID_DATA, error) + } + const blogService = req.scope.resolve("blogService") + blogService.updateBlogTag(req.params.id, data.value).then((blog_tag) => { + return res.json(blog_tag) + }) + }) - // DELETE A BLOG TAG - router.delete("/admin/blog/tags/:id", cors(adminCorsOptions), async (req, res) => { - const blogService = req.scope.resolve("blogService") - blogService.deleteBlogTag(req.params.id).then(() => { - return res.sendStatus(200) - }) - }) + // DELETE A BLOG TAG + router.delete("/admin/blog/tags/:id", cors(adminCorsOptions), async (req, res) => { + const blogService = req.scope.resolve("blogService") + blogService.deleteBlogTag(req.params.id).then(() => { + return res.sendStatus(200) + }) + }) - return router + return router } \ No newline at end of file diff --git a/src/migrations/1684173263726-Blog.ts b/src/migrations/1684173263726-Blog.ts index 16eb89c..bd5d941 100644 --- a/src/migrations/1684173263726-Blog.ts +++ b/src/migrations/1684173263726-Blog.ts @@ -3,114 +3,114 @@ import { MigrationInterface, QueryRunner, TableForeignKey } from "typeorm" export class Blog1684173263726 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE IF NOT EXISTS "blog_category" ("id" character varying NOT NULL, - "handle" character varying UNIQUE NOT NULL, - "title" character varying NOT NULL, - "description" character varying, - "keywords" varchar array, - "metadata" jsonb, - "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), - "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now())` - ) - await queryRunner.createPrimaryKey("blog_category", ["id"]) + await queryRunner.query( + `CREATE TABLE IF NOT EXISTS "blog_category" ("id" character varying NOT NULL, + "handle" character varying UNIQUE NOT NULL, + "title" character varying NOT NULL, + "description" character varying, + "keywords" varchar array, + "metadata" jsonb, + "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now())` + ) + await queryRunner.createPrimaryKey("blog_category", ["id"]) - await queryRunner.query( - `CREATE TABLE IF NOT EXISTS "blog_post" ("id" character varying NOT NULL, - "handle" character varying UNIQUE NOT NULL, - "title" character varying NOT NULL, - "author" character varying, - "published" boolean NOT NULL DEFAULT false, - "content" character varying, - "description" character varying, - "keywords" varchar array, - "category_id" character varying, - "metadata" jsonb, - "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), - "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now())` - ) - await queryRunner.createPrimaryKey("blog_post", ["id"]) - await queryRunner.createForeignKey("blog_post", new TableForeignKey({ - columnNames: ["category_id"], - referencedColumnNames: ["id"], - referencedTableName: "blog_category", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) + await queryRunner.query( + `CREATE TABLE IF NOT EXISTS "blog_post" ("id" character varying NOT NULL, + "handle" character varying UNIQUE NOT NULL, + "title" character varying NOT NULL, + "author" character varying, + "published" boolean NOT NULL DEFAULT false, + "content" character varying, + "description" character varying, + "keywords" varchar array, + "category_id" character varying, + "metadata" jsonb, + "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now())` + ) + await queryRunner.createPrimaryKey("blog_post", ["id"]) + await queryRunner.createForeignKey("blog_post", new TableForeignKey({ + columnNames: ["category_id"], + referencedColumnNames: ["id"], + referencedTableName: "blog_category", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) - await queryRunner.query( - `CREATE TABLE IF NOT EXISTS "blog_tag" ("id" character varying NOT NULL, - "value" character varying NOT NULL, - "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), - "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now())` - ) - await queryRunner.createPrimaryKey("blog_tag", ["id"]) + await queryRunner.query( + `CREATE TABLE IF NOT EXISTS "blog_tag" ("id" character varying NOT NULL, + "value" character varying NOT NULL, + "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now())` + ) + await queryRunner.createPrimaryKey("blog_tag", ["id"]) - await queryRunner.query( - `CREATE TABLE IF NOT EXISTS "blog_tags" ("post_id" character varying NOT NULL, - "tag_id" character varying NOT NULL)` - ) - await queryRunner.createForeignKey("blog_tags", new TableForeignKey({ - columnNames: ["post_id"], - referencedColumnNames: ["id"], - referencedTableName: "blog_post", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) - await queryRunner.createForeignKey("blog_tags", new TableForeignKey({ - columnNames: ["tag_id"], - referencedColumnNames: ["id"], - referencedTableName: "blog_tag", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) + await queryRunner.query( + `CREATE TABLE IF NOT EXISTS "blog_tags" ("post_id" character varying NOT NULL, + "tag_id" character varying NOT NULL)` + ) + await queryRunner.createForeignKey("blog_tags", new TableForeignKey({ + columnNames: ["post_id"], + referencedColumnNames: ["id"], + referencedTableName: "blog_post", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) + await queryRunner.createForeignKey("blog_tags", new TableForeignKey({ + columnNames: ["tag_id"], + referencedColumnNames: ["id"], + referencedTableName: "blog_tag", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) - await queryRunner.query( - `CREATE TABLE IF NOT EXISTS "blog_product_tags" ("post_id" character varying NOT NULL, - "product_id" character varying NOT NULL)` - ) - await queryRunner.createForeignKey("blog_product_tags", new TableForeignKey({ - columnNames: ["post_id"], - referencedColumnNames: ["id"], - referencedTableName: "blog_post", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) - await queryRunner.createForeignKey("blog_product_tags", new TableForeignKey({ - columnNames: ["product_id"], - referencedColumnNames: ["id"], - referencedTableName: "product", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) + await queryRunner.query( + `CREATE TABLE IF NOT EXISTS "blog_product_tags" ("post_id" character varying NOT NULL, + "product_id" character varying NOT NULL)` + ) + await queryRunner.createForeignKey("blog_product_tags", new TableForeignKey({ + columnNames: ["post_id"], + referencedColumnNames: ["id"], + referencedTableName: "blog_post", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) + await queryRunner.createForeignKey("blog_product_tags", new TableForeignKey({ + columnNames: ["product_id"], + referencedColumnNames: ["id"], + referencedTableName: "product", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) - await queryRunner.query( - `CREATE TABLE IF NOT EXISTS "blog_collection_tags" ("post_id" character varying NOT NULL, - "collection_id" character varying NOT NULL)` - ) - await queryRunner.createForeignKey("blog_collection_tags", new TableForeignKey({ - columnNames: ["post_id"], - referencedColumnNames: ["id"], - referencedTableName: "blog_post", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) - await queryRunner.createForeignKey("blog_collection_tags", new TableForeignKey({ - columnNames: ["collection_id"], - referencedColumnNames: ["id"], - referencedTableName: "product_collection", - onDelete: "CASCADE", - onUpdate: "CASCADE" - })) + await queryRunner.query( + `CREATE TABLE IF NOT EXISTS "blog_collection_tags" ("post_id" character varying NOT NULL, + "collection_id" character varying NOT NULL)` + ) + await queryRunner.createForeignKey("blog_collection_tags", new TableForeignKey({ + columnNames: ["post_id"], + referencedColumnNames: ["id"], + referencedTableName: "blog_post", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) + await queryRunner.createForeignKey("blog_collection_tags", new TableForeignKey({ + columnNames: ["collection_id"], + referencedColumnNames: ["id"], + referencedTableName: "product_collection", + onDelete: "CASCADE", + onUpdate: "CASCADE" + })) } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable("blog_tags", true) - await queryRunner.dropTable("blog_product_tags", true) - await queryRunner.dropTable("blog_collection_tags", true) - await queryRunner.dropTable("blog_tag", true) - await queryRunner.dropTable("blog_post", true) - await queryRunner.dropTable("blog_category", true) + await queryRunner.dropTable("blog_tags", true) + await queryRunner.dropTable("blog_product_tags", true) + await queryRunner.dropTable("blog_collection_tags", true) + await queryRunner.dropTable("blog_tag", true) + await queryRunner.dropTable("blog_post", true) + await queryRunner.dropTable("blog_category", true) } } diff --git a/src/models/blog-category.ts b/src/models/blog-category.ts index ca5b683..dd6bf89 100644 --- a/src/models/blog-category.ts +++ b/src/models/blog-category.ts @@ -6,27 +6,27 @@ import { BlogPost } from "./blog-post" @Entity() export class BlogCategory extends BaseEntity { - @Index({ unique: true }) - @Column({ type: "varchar", nullable: false }) - handle: string | null + @Index({ unique: true }) + @Column({ type: "varchar", nullable: false }) + handle: string | null - @Column({ type: "varchar", nullable: false }) - title: string + @Column({ type: "varchar", nullable: false }) + title: string - @Column({ type: "text", nullable: true }) - description: string | null + @Column({ type: "text", nullable: true }) + description: string | null - @Column({ type: "text", nullable: true, array: true }) - keywords: string | null + @Column({ type: "text", nullable: true, array: true }) + keywords: string | null - @Column({ type: "jsonb", nullable: true }) - metadata: Record | null + @Column({ type: "jsonb", nullable: true }) + metadata: Record | null - @OneToMany(() => BlogPost, post => post.category) - posts: BlogPost[] + @OneToMany(() => BlogPost, post => post.category) + posts: BlogPost[] - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "bcat") - } + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "bcat") + } } \ No newline at end of file diff --git a/src/models/blog-post.ts b/src/models/blog-post.ts index d691b36..1d2a273 100644 --- a/src/models/blog-post.ts +++ b/src/models/blog-post.ts @@ -7,82 +7,82 @@ import { BlogTag } from "./blog-tag" @Entity() export class BlogPost extends BaseEntity { - @Index({ unique: true }) - @Column({ type: "varchar", nullable: false }) - handle: string | null + @Index({ unique: true }) + @Column({ type: "varchar", nullable: false }) + handle: string | null - @Column({ type: "varchar", nullable: false }) - title: string + @Column({ type: "varchar", nullable: false }) + title: string - @Column({ type: "varchar", nullable: true }) - author: string | null + @Column({ type: "varchar", nullable: true }) + author: string | null - @Column({ type: "boolean", nullable: false }) - published: boolean + @Column({ type: "boolean", nullable: false }) + published: boolean - @Column({ type: "text", nullable: true }) - content: string | null - - @Column({ type: "text", nullable: true }) - description: string | null + @Column({ type: "text", nullable: true }) + content: string | null + + @Column({ type: "text", nullable: true }) + description: string | null - @Column({ type: "text", nullable: true, array: true }) - keywords: string[] | null + @Column({ type: "text", nullable: true, array: true }) + keywords: string[] | null - @Column({ type: "varchar", nullable: true }) - category_id: string - - @ManyToOne(() => BlogCategory) - @JoinColumn({ name: "category_id" }) - category: BlogCategory + @Column({ type: "varchar", nullable: true }) + category_id: string + + @ManyToOne(() => BlogCategory) + @JoinColumn({ name: "category_id" }) + category: BlogCategory - @ManyToMany(() => BlogTag) - @JoinTable({ - name: "blog_tags", - joinColumn: { - name: "post_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "tag_id", - referencedColumnName: "id", - }, - }) - tags: BlogTag[] - - @ManyToMany(() => Product) - @JoinTable({ - name: "blog_product_tags", - joinColumn: { - name: "post_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - }) - products: Product[] + @ManyToMany(() => BlogTag) + @JoinTable({ + name: "blog_tags", + joinColumn: { + name: "post_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "tag_id", + referencedColumnName: "id", + }, + }) + tags: BlogTag[] + + @ManyToMany(() => Product) + @JoinTable({ + name: "blog_product_tags", + joinColumn: { + name: "post_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "product_id", + referencedColumnName: "id", + }, + }) + products: Product[] - @ManyToMany(() => ProductCollection) - @JoinTable({ - name: "blog_collection_tags", - joinColumn: { - name: "post_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "collection_id", - referencedColumnName: "id", - }, - }) - collections: ProductCollection[] + @ManyToMany(() => ProductCollection) + @JoinTable({ + name: "blog_collection_tags", + joinColumn: { + name: "post_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "collection_id", + referencedColumnName: "id", + }, + }) + collections: ProductCollection[] - @Column({ type: "jsonb", nullable: true }) - metadata: Record | null + @Column({ type: "jsonb", nullable: true }) + metadata: Record | null - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "post") - } + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "post") + } } \ No newline at end of file diff --git a/src/models/blog-tag.ts b/src/models/blog-tag.ts index ce888e4..2bdbd93 100644 --- a/src/models/blog-tag.ts +++ b/src/models/blog-tag.ts @@ -5,11 +5,11 @@ import { BeforeInsert, Column, Entity } from "typeorm" @Entity() export class BlogTag extends BaseEntity { - @Column({ type: "varchar", nullable: false }) - value: string + @Column({ type: "varchar", nullable: false }) + value: string - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "btag") - } + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "btag") + } } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 153f8aa..39f1eb7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "lib": ["es2020"], "target": "es2020", "outDir": "./", + "rootDir": "./src", "esModuleInterop": true, "declaration": false, "module": "commonjs",