From 6dc657a136a00b4f6441a5b4506b7e5712c79ebd Mon Sep 17 00:00:00 2001 From: Gerome Grignon Date: Fri, 25 Oct 2024 11:57:38 +0200 Subject: [PATCH] update --- .github/CODEOWNERS | 2 +- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 2 - .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml | 2 - .github/PULL_REQUEST_TEMPLATE.md | 9 -- README.md | 5 +- api/openapi.yml | 2 +- apps/api/package.json | 2 +- apps/api/prisma/dev.db | Bin 0 -> 94208 bytes .../20240816162230_init/migration.sql | 121 ------------------ .../20241009081140_init/migration.sql | 95 ++++++++++++++ .../api/prisma/migrations/migration_lock.toml | 2 +- apps/api/prisma/schema.prisma | 4 +- apps/documentation/src/assets/swagger.json | 2 +- .../implementation-creation/introduction.md | 1 - apps/documentation/src/content/docs/index.mdx | 4 - .../src/content/docs/introduction.mdx | 4 +- 16 files changed, 105 insertions(+), 152 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 apps/api/prisma/dev.db delete mode 100644 apps/api/prisma/migrations/20240816162230_init/migration.sql create mode 100644 apps/api/prisma/migrations/20241009081140_init/migration.sql diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e02dc9424..8b1378917 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -@geromegrignon + diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index fa3bd26d0..1e5e294e5 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -3,8 +3,6 @@ description: Report a bug in the RealWorld project title: '[Bug]: ' labels: - bug -assignees: - - geromegrignon body: - type: dropdown attributes: diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml index 507d0564d..a93efe494 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml @@ -1,8 +1,6 @@ name: 🚀 Feature request description: Suggest a feature for RealWorld project title: '[Feature Request]:' -assignees: - - geromegrignon body: - type: markdown attributes: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 69899ece8..000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ - - -## Summary - -copilot:summary - -## Details - -copilot:walkthrough diff --git a/README.md b/README.md index 2458eb5c4..a4df03972 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,10 @@

- - -### See how _the exact same_ Medium.com clone (called [Conduit](https://demo.realworld.how)) is built using different [frontends](https://codebase.show/projects/realworld?category=frontend) and [backends](https://codebase.show/projects/realworld?category=backend). Yes, you can mix and match them, because **they all adhere to the same [API spec](https://realworld-docs.netlify.app/specifications/backend/introduction/)** 😮😎 While most "todo" demos provide an excellent cursory glance at a framework's capabilities, they typically don't convey the knowledge & perspective required to actually build _real_ applications with it. -**RealWorld** solves this by allowing you to choose any frontend (React, Angular, & more) and any backend (Node, Django, & more) and see how they power a real-world, beautifully designed full-stack app called [**Conduit**](https://conduit.realworld.how). +**RealWorld** solves this by allowing you to choose any frontend (React, Angular, & more) and any backend (Node, Django, & more). _Read the [full blog post announcing RealWorld on Medium.](https://medium.com/@ericsimons/introducing-realworld-6016654d36b5)_ diff --git a/api/openapi.yml b/api/openapi.yml index 2a82aa437..f140de933 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -4,7 +4,7 @@ info: description: Conduit API documentation contact: name: RealWorld - url: https://www.realworld.how + url: https://realworld-docs.netlify.app/ license: name: MIT License url: https://opensource.org/licenses/MIT diff --git a/apps/api/package.json b/apps/api/package.json index e5c57a0e0..6d6fb0c6f 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -5,7 +5,7 @@ "dev": "nitro dev", "prepare": "nitro prepare", "preview": "node .output/server/index.mjs", - "start": "node .output/server/index.mjs", + "start": "node .output/server/index.mjs", "db:seed": "npx prisma db seed" }, "prisma": { diff --git a/apps/api/prisma/dev.db b/apps/api/prisma/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..49a87df2b78c1bf5ea4953129f3842c620b7721d GIT binary patch literal 94208 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 CTgXNL literal 0 HcmV?d00001 diff --git a/apps/api/prisma/migrations/20240816162230_init/migration.sql b/apps/api/prisma/migrations/20240816162230_init/migration.sql deleted file mode 100644 index f6a1066ab..000000000 --- a/apps/api/prisma/migrations/20240816162230_init/migration.sql +++ /dev/null @@ -1,121 +0,0 @@ --- CreateTable -CREATE TABLE "Article" ( - "id" SERIAL NOT NULL, - "slug" TEXT NOT NULL, - "title" TEXT NOT NULL, - "description" TEXT NOT NULL, - "body" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "authorId" INTEGER NOT NULL, - - CONSTRAINT "Article_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Comment" ( - "id" SERIAL NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "body" TEXT NOT NULL, - "articleId" INTEGER NOT NULL, - "authorId" INTEGER NOT NULL, - - CONSTRAINT "Comment_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Tag" ( - "id" SERIAL NOT NULL, - "name" TEXT NOT NULL, - - CONSTRAINT "Tag_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "User" ( - "id" SERIAL NOT NULL, - "email" TEXT NOT NULL, - "username" TEXT NOT NULL, - "password" TEXT NOT NULL, - "image" TEXT DEFAULT 'https://api.realworld.io/images/smiley-cyrus.jpeg', - "bio" TEXT, - "demo" BOOLEAN NOT NULL DEFAULT false, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "_ArticleToTag" ( - "A" INTEGER NOT NULL, - "B" INTEGER NOT NULL -); - --- CreateTable -CREATE TABLE "_UserFavorites" ( - "A" INTEGER NOT NULL, - "B" INTEGER NOT NULL -); - --- CreateTable -CREATE TABLE "_UserFollows" ( - "A" INTEGER NOT NULL, - "B" INTEGER NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "Article_slug_key" ON "Article"("slug"); - --- CreateIndex -CREATE UNIQUE INDEX "Tag_name_key" ON "Tag"("name"); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); - --- CreateIndex -CREATE UNIQUE INDEX "_ArticleToTag_AB_unique" ON "_ArticleToTag"("A", "B"); - --- CreateIndex -CREATE INDEX "_ArticleToTag_B_index" ON "_ArticleToTag"("B"); - --- CreateIndex -CREATE UNIQUE INDEX "_UserFavorites_AB_unique" ON "_UserFavorites"("A", "B"); - --- CreateIndex -CREATE INDEX "_UserFavorites_B_index" ON "_UserFavorites"("B"); - --- CreateIndex -CREATE UNIQUE INDEX "_UserFollows_AB_unique" ON "_UserFollows"("A", "B"); - --- CreateIndex -CREATE INDEX "_UserFollows_B_index" ON "_UserFollows"("B"); - --- AddForeignKey -ALTER TABLE "Article" ADD CONSTRAINT "Article_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Comment" ADD CONSTRAINT "Comment_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Comment" ADD CONSTRAINT "Comment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "_ArticleToTag" ADD CONSTRAINT "_ArticleToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "_ArticleToTag" ADD CONSTRAINT "_ArticleToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "_UserFavorites" ADD CONSTRAINT "_UserFavorites_A_fkey" FOREIGN KEY ("A") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "_UserFavorites" ADD CONSTRAINT "_UserFavorites_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "_UserFollows" ADD CONSTRAINT "_UserFollows_A_fkey" FOREIGN KEY ("A") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "_UserFollows" ADD CONSTRAINT "_UserFollows_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/api/prisma/migrations/20241009081140_init/migration.sql b/apps/api/prisma/migrations/20241009081140_init/migration.sql new file mode 100644 index 000000000..8e2199027 --- /dev/null +++ b/apps/api/prisma/migrations/20241009081140_init/migration.sql @@ -0,0 +1,95 @@ +-- CreateTable +CREATE TABLE "Article" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "slug" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT NOT NULL, + "body" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "authorId" INTEGER NOT NULL, + CONSTRAINT "Article_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "Comment" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "body" TEXT NOT NULL, + "articleId" INTEGER NOT NULL, + "authorId" INTEGER NOT NULL, + CONSTRAINT "Comment_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "Comment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "Tag" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "User" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "email" TEXT NOT NULL, + "username" TEXT NOT NULL, + "password" TEXT NOT NULL, + "image" TEXT DEFAULT 'https://api.realworld.io/images/smiley-cyrus.jpeg', + "bio" TEXT, + "demo" BOOLEAN NOT NULL DEFAULT false +); + +-- CreateTable +CREATE TABLE "_ArticleToTag" ( + "A" INTEGER NOT NULL, + "B" INTEGER NOT NULL, + CONSTRAINT "_ArticleToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Article" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "_ArticleToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "_UserFavorites" ( + "A" INTEGER NOT NULL, + "B" INTEGER NOT NULL, + CONSTRAINT "_UserFavorites_A_fkey" FOREIGN KEY ("A") REFERENCES "Article" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "_UserFavorites_B_fkey" FOREIGN KEY ("B") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "_UserFollows" ( + "A" INTEGER NOT NULL, + "B" INTEGER NOT NULL, + CONSTRAINT "_UserFollows_A_fkey" FOREIGN KEY ("A") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "_UserFollows_B_fkey" FOREIGN KEY ("B") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateIndex +CREATE UNIQUE INDEX "Article_slug_key" ON "Article"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "Tag_name_key" ON "Tag"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "_ArticleToTag_AB_unique" ON "_ArticleToTag"("A", "B"); + +-- CreateIndex +CREATE INDEX "_ArticleToTag_B_index" ON "_ArticleToTag"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_UserFavorites_AB_unique" ON "_UserFavorites"("A", "B"); + +-- CreateIndex +CREATE INDEX "_UserFavorites_B_index" ON "_UserFavorites"("B"); + +-- CreateIndex +CREATE UNIQUE INDEX "_UserFollows_AB_unique" ON "_UserFollows"("A", "B"); + +-- CreateIndex +CREATE INDEX "_UserFollows_B_index" ON "_UserFollows"("B"); diff --git a/apps/api/prisma/migrations/migration_lock.toml b/apps/api/prisma/migrations/migration_lock.toml index fbffa92c2..e5e5c4705 100644 --- a/apps/api/prisma/migrations/migration_lock.toml +++ b/apps/api/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually # It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file +provider = "sqlite" \ No newline at end of file diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 9f88c48a4..40ebb3d13 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -1,6 +1,6 @@ datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "sqlite" + url = "file:./dev.db" } generator client { diff --git a/apps/documentation/src/assets/swagger.json b/apps/documentation/src/assets/swagger.json index 0a256fd31..66334827f 100644 --- a/apps/documentation/src/assets/swagger.json +++ b/apps/documentation/src/assets/swagger.json @@ -5,7 +5,7 @@ "description": "Conduit API documentation", "contact": { "name": "RealWorld", - "url": "https://realworld.how" + "url": "https://realworld-docs.netlify.app/" }, "license": { "name": "MIT License", diff --git a/apps/documentation/src/content/docs/implementation-creation/introduction.md b/apps/documentation/src/content/docs/implementation-creation/introduction.md index 2433afade..1684fe635 100644 --- a/apps/documentation/src/content/docs/implementation-creation/introduction.md +++ b/apps/documentation/src/content/docs/implementation-creation/introduction.md @@ -3,7 +3,6 @@ title: Introduction --- **Conduit** is a social blogging site (i.e. a Medium.com clone). It uses a custom API for all requests, including authentication. -Discover our [live demo](https://demo.realworld.how). :::tip Check for [Discussions](https://github.com/gothinkster/realworld/discussions/categories/wip-implementations) about works in progress as we don't list duplicate projects. diff --git a/apps/documentation/src/content/docs/index.mdx b/apps/documentation/src/content/docs/index.mdx index 66d95870a..1d7580096 100644 --- a/apps/documentation/src/content/docs/index.mdx +++ b/apps/documentation/src/content/docs/index.mdx @@ -11,8 +11,4 @@ hero: - text: Documentation link: /introduction icon: right-arrow - - text: Test the demo - link: https://demo.realworld.how - icon: external - variant: minimal --- diff --git a/apps/documentation/src/content/docs/introduction.mdx b/apps/documentation/src/content/docs/introduction.mdx index 5d64d61ea..0f6c29b63 100644 --- a/apps/documentation/src/content/docs/introduction.mdx +++ b/apps/documentation/src/content/docs/introduction.mdx @@ -8,11 +8,11 @@ title: Introduction -> See how _the exact same_ Medium.com clone (called [Conduit](https://demo.realworld.how)) is built using different [frontends](https://codebase.show/projects/realworld?category=frontend) and [backends](https://codebase.show/projects/realworld?category=backend). Yes, you can mix and match them, because **they all adhere to the same [API spec](specs/backend-specs/introduction)** 😮😎 +> See how _the exact same_ Medium.com clone is built using different [frontends](https://codebase.show/projects/realworld?category=frontend) and [backends](https://codebase.show/projects/realworld?category=backend). Yes, you can mix and match them, because **they all adhere to the same [API spec](specs/backend-specs/introduction)** 😮😎 While most "todo" demos provide an excellent cursory glance at a framework's capabilities, they typically don't convey the knowledge & perspective required to actually build _real_ applications with it. -**RealWorld** solves this by allowing you to choose any frontend (React, Angular, & more) and any backend (Node, Django, & more) and see how they power a real world, beautifully designed fullstack app called [**Conduit**](https://demo.realworld.how). +**RealWorld** solves this by allowing you to choose any frontend (React, Angular, & more) and any backend (Node, Django, & more). _Read the [full blog post announcing RealWorld on Medium.](https://medium.com/@ericsimons/introducing-realworld-6016654d36b5)_