mirror of
https://github.com/Such-Software/medusa-plugin-blog.git
synced 2026-10-17 05:32:06 +02:00
add migrations and service
This commit is contained in:
+1
-7
@@ -18,15 +18,9 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@medusajs/medusa": "^1.10.1",
|
||||
"@medusajs/types": "^1.8.5",
|
||||
"@medusajs/utils": "^1.8.4",
|
||||
"body-parser": "^1.19.0",
|
||||
"cors": "^2.8.5",
|
||||
"cross-env": "^5.2.1",
|
||||
"express": "^4.17.2",
|
||||
"medusa-interfaces": "^1.3.7",
|
||||
"typeorm": "^0.3.16",
|
||||
"typescript": "^4.9.5"
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "cross-env NODE_ENV=production yarn run build",
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import cors from "cors"
|
||||
import configLoader from "@medusajs/medusa/dist/loaders/config"
|
||||
import { Router } from "express"
|
||||
import * as bodyParser from "body-parser"
|
||||
//import { User, UserService, Customer, CustomerService } from "@medusajs/medusa"
|
||||
import { authenticateCustomer } from "@medusajs/medusa"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
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 router = Router()
|
||||
|
||||
// REVIEWS - GET ALL REVIEWS FOR A PRODUCT
|
||||
//router.use("/store/products/:id/reviews", authenticateCustomer())
|
||||
router.use(authenticateCustomer())
|
||||
//router.get("/store/products/:id/reviews", cors(storeCorsOptions), authenticateCustomer(), async (req, res) => {
|
||||
router.get("/store/products/:id/reviews", cors(storeCorsOptions), async (req, res) => {
|
||||
// console.log('get reviews')
|
||||
// console.log(req.user)
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
productReviewService.getProductReviews(req.params.id).then((product_reviews) => {
|
||||
return res.json({product_reviews})
|
||||
})
|
||||
})
|
||||
|
||||
// REVIEWS - GET ALL REVIEWS FOR A CUSTOMER
|
||||
// router.use("/store/customers/:id/reviews", authenticate(), getCustomer)
|
||||
router.get("/store/customers/:id/reviews", async (req, res) => {
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
productReviewService.getCustomerProductReviews(req.params.id).then((product_reviews) => {
|
||||
return res.json({product_reviews})
|
||||
})
|
||||
})
|
||||
|
||||
// REVIEWS - ADD A NEW REVIEW FOR A PRODUCT
|
||||
//router.use("/store/products/:id/reviews", authenticate(), getCustomer, bodyParser.json())
|
||||
router.use("/store/products/:id/reviews", bodyParser.json())
|
||||
router.post("/store/products/:id/reviews", async (req, res) => {
|
||||
const schema = z.object({
|
||||
customer_id: z.string().min(1),
|
||||
display_name: z.string().min(1),
|
||||
content: z.string().min(1),
|
||||
rating: z.coerce.number().min(0).max(5),
|
||||
})
|
||||
/* @ts-ignore */
|
||||
const { success, error, data } = schema.safeParse(req.body)
|
||||
if (!success) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error)
|
||||
} else {
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
productReviewService.addProductReview(req.params.id, data.customer_id, data.display_name, data.content, data.rating)
|
||||
.then((product_review) => {
|
||||
return res.json({product_review})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// REVIEWS - GET A SINGLE REVIEW
|
||||
router.get("/store/reviews/:id", async (req, res) => {
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
productReviewService.getReview(req.params.id).then((product_review) => {
|
||||
return res.json({product_review})
|
||||
})
|
||||
})
|
||||
|
||||
// REVIEWS - UPDATE A REVIEW FOR A PRODUCT
|
||||
//router.use("/store/reviews/:id", authenticate(), getCustomer, bodyParser.json())
|
||||
router.use("/store/reviews/:id", bodyParser.json())
|
||||
router.post("/store/reviews/:id", async (req, res) => {
|
||||
const schema = z.object({
|
||||
customer_id: z.string().min(1),
|
||||
display_name: z.string().min(1),
|
||||
content: z.string().min(1),
|
||||
rating: z.coerce.number().min(0).max(5),
|
||||
})
|
||||
/* @ts-ignore */
|
||||
const { success, error, data } = schema.safeParse(req.body)
|
||||
if (!success) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error)
|
||||
} else {
|
||||
}
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
const productReview = await productReviewService.getProductReviews(req.params.id)
|
||||
if (productReview.customer_id !== req.body.userId) {
|
||||
return res.status(401).json({ message: "Unauthorized" })
|
||||
}
|
||||
productReviewService.updateProductReview(req.params.id, req.body.display_name, req.body.content, req.body.rating)
|
||||
.then((product_review) => {
|
||||
return res.json({product_review})
|
||||
})
|
||||
})
|
||||
|
||||
// REVIEWS - ADMIN GET ALL REVIEWS FOR A PRODUCT
|
||||
router.get("/admin/products/:id/reviews", async (req, res) => {
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
productReviewService.getProductReviews(req.params.id).then((product_reviews) => {
|
||||
return res.json({product_reviews})
|
||||
})
|
||||
})
|
||||
|
||||
// REVIEWS - ADMIN EDIT A REVIEW FOR A PRODUCT
|
||||
//router.use("/admin/reviews/:id", bodyParser.json(), authenticate(), getUser)
|
||||
router.use("/admin/reviews/:id", bodyParser.json())
|
||||
router.post("/admin/reviews/:id", async (req, res) => {
|
||||
const productReviewService = req.scope.resolve("productReviewService")
|
||||
productReviewService.editProductReview(req.params.id, req.body.display_name, req.body.content, req.body.rating, req.body.approved)
|
||||
.then((product_review) => {
|
||||
return res.json({product_review})
|
||||
})
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
// async function getCustomer(req, res, next) {
|
||||
// console.log('getCustomer')
|
||||
// let loggedInCustomer: Customer | null = null
|
||||
// if (req.customer && req.customer.customerId) {
|
||||
// console.log(req.customer.customerId)
|
||||
// const customerService = req.scope.resolve("customerService") as CustomerService
|
||||
// loggedInCustomer = await customerService.retrieve(req.customer.customerId)
|
||||
// }
|
||||
// req.scope.register({ loggedInCustomer: { resolve: () => loggedInCustomer }})
|
||||
// next()
|
||||
// }
|
||||
|
||||
// async function getUser(req, res, next) {
|
||||
// let loggedInUser: User | null = null
|
||||
// if (req.user && req.user.userId) {
|
||||
// const userService = req.scope.resolve("userService") as UserService
|
||||
// loggedInUser = await userService.retrieve(req.user.userId)
|
||||
// }
|
||||
// req.scope.register({ loggedInUser: { resolve: () => loggedInUser }})
|
||||
// next()
|
||||
// }
|
||||
@@ -0,0 +1,112 @@
|
||||
import { MigrationInterface, QueryRunner, TableForeignKey } from "typeorm"
|
||||
|
||||
export class Blog1684173263726 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE IF NOT EXISTS "blog_category" ("id" character varying NOT NULL,
|
||||
"handle" character varying,
|
||||
"title" character varying NOT NULL,
|
||||
"description" character varying,
|
||||
"keywords" varchar[],
|
||||
"metadata" jsonb)`
|
||||
)
|
||||
await queryRunner.createPrimaryKey("blog_category", ["id"])
|
||||
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE IF NOT EXISTS "blog_post" ("id" character varying NOT NULL,
|
||||
"handle" character varying,
|
||||
"title" character varying NOT NULL,
|
||||
"author" character varying,
|
||||
"published" boolean NOT NULL DEFAULT false,
|
||||
"content" character varying,
|
||||
"description" character varying,
|
||||
"keywords" varchar[],
|
||||
"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,
|
||||
"title" character varying NOT NULL)`
|
||||
)
|
||||
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_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: "collection",
|
||||
onDelete: "CASCADE",
|
||||
onUpdate: "CASCADE"
|
||||
}))
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.dropTable("blog_category", true)
|
||||
await queryRunner.dropTable("blog_post", true)
|
||||
await queryRunner.dropTable("blog_tag", true)
|
||||
await queryRunner.dropTable("blog_tags", true)
|
||||
await queryRunner.dropTable("blog_product_tags", true)
|
||||
await queryRunner.dropTable("blog_collection_tags", true)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,9 +27,9 @@ export class BlogPost extends BaseEntity {
|
||||
description: string | null
|
||||
|
||||
@Column({ type: "text", nullable: true, array: true })
|
||||
keywords: string | null
|
||||
keywords: string[] | null
|
||||
|
||||
@Column({ type: "varchar", nullable: false })
|
||||
@Column({ type: "varchar", nullable: true })
|
||||
category_id: string
|
||||
|
||||
@ManyToOne(() => BlogCategory)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import { BlogCategory } from "../models/blog-category"
|
||||
import { dataSource } from '@medusajs/medusa/dist/loaders/database'
|
||||
|
||||
export const BlogCategoryRepository = dataSource.getRepository(BlogCategory)
|
||||
@@ -0,0 +1,4 @@
|
||||
import { BlogPost } from "../models/blog-post"
|
||||
import { dataSource } from '@medusajs/medusa/dist/loaders/database'
|
||||
|
||||
export const BlogPostRepository = dataSource.getRepository(BlogPost)
|
||||
@@ -0,0 +1,4 @@
|
||||
import { BlogTag } from "../models/blog-tag"
|
||||
import { dataSource } from '@medusajs/medusa/dist/loaders/database'
|
||||
|
||||
export const BlogTagRepository = dataSource.getRepository(BlogTag)
|
||||
@@ -0,0 +1,177 @@
|
||||
import { TransactionBaseService } from '@medusajs/utils'
|
||||
import { BlogCategoryRepository } from '../repositories/blog-category'
|
||||
import { BlogPostRepository } from '../repositories/blog-post'
|
||||
import { BlogTagRepository } from '../repositories/blog-tag'
|
||||
|
||||
export default class BlogService extends TransactionBaseService {
|
||||
protected readonly blogCategoryRepository_: typeof BlogCategoryRepository
|
||||
protected readonly blogPostRepository_: typeof BlogPostRepository
|
||||
protected readonly blogTagRepository_: typeof BlogTagRepository
|
||||
|
||||
constructor({ blogCategoryRepository, blogPostRepository, blogTagRepository }) {
|
||||
super(arguments[0])
|
||||
this.blogCategoryRepository_ = blogCategoryRepository
|
||||
this.blogPostRepository_ = blogPostRepository
|
||||
this.blogTagRepository_ = blogTagRepository
|
||||
}
|
||||
|
||||
async getBlogCategories() {
|
||||
/* @ts-ignore */
|
||||
const blogCategoryRepository = this.activeManager_.withRepository(this.blogCategoryRepository_)
|
||||
return await blogCategoryRepository.find()
|
||||
}
|
||||
|
||||
async getBlogCategory(id) {
|
||||
/* @ts-ignore */
|
||||
const blogCategoryRepository = this.activeManager_.withRepository(this.blogCategoryRepository_)
|
||||
return await blogCategoryRepository.findOne({
|
||||
where: { id }
|
||||
})
|
||||
}
|
||||
|
||||
async addBlogCategory (category) {
|
||||
const { handle, title, description, keywords, metadata } = category
|
||||
if (!title) throw new Error("Adding a blog category requires a title")
|
||||
/* @ts-ignore */
|
||||
const blogCategoryRepository = this.activeManager_.withRepository(this.blogCategoryRepository_)
|
||||
const createdCategory = blogCategoryRepository.create({
|
||||
handle,
|
||||
title,
|
||||
description,
|
||||
keywords,
|
||||
metadata
|
||||
})
|
||||
const blogCategory = await blogCategoryRepository.save(createdCategory)
|
||||
return blogCategory
|
||||
}
|
||||
|
||||
async updateBlogCategory (id, category) {
|
||||
const { handle, title, description, keywords, metadata } = category
|
||||
if (!id || !title) throw new Error("Updating a blog category requires an id and a title")
|
||||
/* @ts-ignore */
|
||||
const blogCategoryRepository = this.activeManager_.withRepository(this.blogCategoryRepository_)
|
||||
const blogCategory = blogCategoryRepository.update(id, {
|
||||
handle,
|
||||
title,
|
||||
description,
|
||||
keywords,
|
||||
metadata
|
||||
})
|
||||
return blogCategory
|
||||
}
|
||||
|
||||
async deleteBlogCategory(id) {
|
||||
if (!id) throw new Error("Deleting a blog category requires an id")
|
||||
/* @ts-ignore */
|
||||
const blogCategoryRepository = this.activeManager_.withRepository(this.blogCategoryRepository_)
|
||||
return await blogCategoryRepository.delete(id)
|
||||
}
|
||||
|
||||
async getBlogPosts() {
|
||||
/* @ts-ignore */
|
||||
const blogPostRepository = this.activeManager_.withRepository(this.blogPostRepository_)
|
||||
return await blogPostRepository.find()
|
||||
}
|
||||
|
||||
async getBlogCategoryPosts(category_id) {
|
||||
/* @ts-ignore */
|
||||
const blogPostRepository = this.activeManager_.withRepository(this.blogPostRepository_)
|
||||
return await blogPostRepository.find({
|
||||
where: { category_id }
|
||||
})
|
||||
}
|
||||
|
||||
async getBlogPost(id) {
|
||||
/* @ts-ignore */
|
||||
const blogPostRepository = this.activeManager_.withRepository(this.blogPostRepository_)
|
||||
return await blogPostRepository.findOne({
|
||||
where: { id }
|
||||
})
|
||||
}
|
||||
|
||||
async addBlogPost(post) {
|
||||
const { handle, title, author, published, content, description, keywords, category_id, tags, products, collections, metadata } = post
|
||||
if (!title) throw new Error("Adding a blog post requires a title")
|
||||
/* @ts-ignore */
|
||||
const blogPostRepository = this.activeManager_.withRepository(this.blogPostRepository_)
|
||||
const createdPost = blogPostRepository.create({
|
||||
handle,
|
||||
title,
|
||||
author,
|
||||
published,
|
||||
content,
|
||||
description,
|
||||
keywords,
|
||||
category_id,
|
||||
tags,
|
||||
products,
|
||||
collections,
|
||||
metadata
|
||||
})
|
||||
const blogPost = await blogPostRepository.save(createdPost)
|
||||
return blogPost
|
||||
}
|
||||
|
||||
async updateBlogPost(id, post) {
|
||||
const { handle, title, author, published, content, description, keywords, category_id, tags, products, collections, metadata } = post
|
||||
if (!id || !title) throw new Error("Updating a blog post requires an id and a title")
|
||||
/* @ts-ignore */
|
||||
const blogPostRepository = this.activeManager_.withRepository(this.blogPostRepository_)
|
||||
const blogPost = blogPostRepository.update(id, {
|
||||
handle,
|
||||
title,
|
||||
author,
|
||||
published,
|
||||
content,
|
||||
description,
|
||||
keywords,
|
||||
category_id,
|
||||
tags,
|
||||
products,
|
||||
collections,
|
||||
metadata
|
||||
})
|
||||
return blogPost
|
||||
}
|
||||
|
||||
async deleteBlogPost(id) {
|
||||
if (!id) throw new Error("Deleting a blog post requires an id")
|
||||
/* @ts-ignore */
|
||||
const blogPostRepository = this.activeManager_.withRepository(this.blogPostRepository_)
|
||||
return await blogPostRepository.delete(id)
|
||||
}
|
||||
|
||||
async getBlogTags() {
|
||||
/* @ts-ignore */
|
||||
const blogTagRepository = this.activeManager_.withRepository(this.blogTagRepository_)
|
||||
return await blogTagRepository.find()
|
||||
}
|
||||
|
||||
async addBlogTag(title) {
|
||||
if (!title) throw new Error("Adding a blog tag requires a title")
|
||||
/* @ts-ignore */
|
||||
const blogTagRepository = this.activeManager_.withRepository(this.blogTagRepository_)
|
||||
const createdTag = blogTagRepository.create({
|
||||
title
|
||||
})
|
||||
const blogTag = await blogTagRepository.save(createdTag)
|
||||
return blogTag
|
||||
}
|
||||
|
||||
async updateBlogTag(id, title) {
|
||||
if (!id || !title) throw new Error("Updating a blog tag requires an id and a title")
|
||||
/* @ts-ignore */
|
||||
const blogTagRepository = this.activeManager_.withRepository(this.blogTagRepository_)
|
||||
const blogTag = blogTagRepository.update(id, {
|
||||
title
|
||||
})
|
||||
return blogTag
|
||||
}
|
||||
|
||||
async deleteBlogTag(id) {
|
||||
if (!id) throw new Error("Deleting a blog tag requires an id")
|
||||
/* @ts-ignore */
|
||||
const blogTagRepository = this.activeManager_.withRepository(this.blogTagRepository_)
|
||||
return await blogTagRepository.delete(id)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user