mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-11-24 03:35:17 +03:00
Made more progress.
This commit is contained in:
parent
85d8f5066c
commit
08238e69b2
@ -12,8 +12,8 @@ Todo:
|
||||
- [x] Profile page that shows basic user info.
|
||||
- [x] Home page with navbar.
|
||||
- [x] CRUD Articles (created from Markdown).
|
||||
- [ ] On /article page, show author username and date of creation (of article).
|
||||
- [ ] Render article content as markdown.
|
||||
- [x] On /article page, show author username and date of creation (of article).
|
||||
- [x] Render article content as markdown.
|
||||
- [ ] For Article, use special id which contains title in the name, and display it in url?
|
||||
- [ ] CR*D Comments on articles.
|
||||
- [ ] Paginated list of articles.
|
||||
|
@ -102,8 +102,7 @@ const ArticleEditor = (props) => {
|
||||
/>
|
||||
|
||||
<h2>Markdown content</h2>
|
||||
<input
|
||||
type='text'
|
||||
<textarea
|
||||
value={markdownContent}
|
||||
onChange={e => setMarkdownContent(e.target.value)}
|
||||
/>
|
||||
|
@ -1,10 +1,13 @@
|
||||
import React from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import moment from 'moment'
|
||||
|
||||
import useAuth from '@wasp/auth/useAuth.js'
|
||||
import { useQuery } from '@wasp/queries'
|
||||
|
||||
import getArticle from '@wasp/queries/getArticle'
|
||||
import getUser from '@wasp/queries/getUser'
|
||||
import deleteArticle from '@wasp/actions/deleteArticle'
|
||||
|
||||
import Navbar from './Navbar'
|
||||
@ -46,10 +49,17 @@ const ArticleViewPage = (props) => {
|
||||
<div>
|
||||
<Navbar />
|
||||
|
||||
<div>
|
||||
<div> Author: { article.user.username } </div>
|
||||
<div> Created at: { moment(article.createdAt).format('MMMM DD, YYYY') } </div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p> { article.title } </p>
|
||||
<p> { article.description } </p>
|
||||
<p> { article.markdownContent } </p>
|
||||
<p>
|
||||
<ReactMarkdown children={article.markdownContent} />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{ isMyArticle && (
|
||||
|
@ -86,8 +86,7 @@ const UserSettings = (props) => {
|
||||
/>
|
||||
|
||||
<h2>Short bio</h2>
|
||||
<input
|
||||
type='text'
|
||||
<textarea
|
||||
value={bio}
|
||||
onChange={e => setBio(e.target.value)}
|
||||
/>
|
||||
|
@ -1,8 +1,22 @@
|
||||
import HttpError from '@wasp/core/HttpError.js'
|
||||
|
||||
const userPublicSelection = {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
bio: true,
|
||||
profilePictureUrl: true
|
||||
}
|
||||
|
||||
export const getUser = async ({ username }, context) => {
|
||||
// TODO: Do some error handling?
|
||||
const user = await context.entities.User.findOne({ where: { username } })
|
||||
const user = await context.entities.User.findOne({
|
||||
where: { username },
|
||||
// TODO: Tricky, if you forget this you could return unwanted fields
|
||||
// like hashed password!
|
||||
// It would be cool if we had some protection against making this mistake easily.
|
||||
select: userPublicSelection
|
||||
})
|
||||
if (!user) throw new HttpError(404, 'No user with username ' + username)
|
||||
return user
|
||||
}
|
||||
@ -10,17 +24,24 @@ export const getUser = async ({ username }, context) => {
|
||||
export const getArticlesByUser = async ({ username }, context) => {
|
||||
// TODO: Do some error handling?
|
||||
const articles = await context.entities.Article.findMany({
|
||||
where: {
|
||||
user: { username }
|
||||
}
|
||||
where: { user: { username } }
|
||||
})
|
||||
return articles
|
||||
}
|
||||
|
||||
export const getArticle = async ({ id }, context) => {
|
||||
// TODO: Do some error handling?
|
||||
const article = await context.entities.Article.findOne({
|
||||
where: { id }
|
||||
})
|
||||
const article = await context.entities.Article
|
||||
.findOne({
|
||||
where: { id },
|
||||
include: {
|
||||
user: {
|
||||
// TODO: Tricky, if you forget this you could return unwanted fields
|
||||
// like hashed password!
|
||||
// It would be cool if we had some protection against making this mistake easily.
|
||||
select: userPublicSelection
|
||||
}
|
||||
}
|
||||
})
|
||||
return article
|
||||
}
|
||||
|
@ -53,12 +53,13 @@ psl=}
|
||||
// TODO: Add tags.
|
||||
// TODO: Add creation and update times.
|
||||
entity Article {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
description String
|
||||
markdownContent String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
id Int @id @default(autoincrement())
|
||||
createdAt DateTime @default(now())
|
||||
title String
|
||||
description String
|
||||
markdownContent String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
psl=}
|
||||
|
||||
auth {
|
||||
@ -104,4 +105,9 @@ action updateArticle {
|
||||
action deleteArticle {
|
||||
fn: import { deleteArticle } from "@ext/actions.js",
|
||||
entities: [Article]
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {=json
|
||||
"react-markdown": "5.0.3",
|
||||
"moment": "2.29.1"
|
||||
json=}
|
@ -0,0 +1,62 @@
|
||||
# Migration `20201124192901-added-created-at-to-article`
|
||||
|
||||
This migration has been generated by Martin Sosic at 11/24/2020, 8:29:01 PM.
|
||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
||||
|
||||
## Database Steps
|
||||
|
||||
```sql
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Article" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"markdownContent" TEXT NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Article" ("id", "title", "description", "markdownContent", "userId") SELECT "id", "title", "description", "markdownContent", "userId" FROM "Article";
|
||||
DROP TABLE "Article";
|
||||
ALTER TABLE "new_Article" RENAME TO "Article";
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON
|
||||
```
|
||||
|
||||
## Changes
|
||||
|
||||
```diff
|
||||
diff --git schema.prisma schema.prisma
|
||||
migration 20201119144622-added-article-entity..20201124192901-added-created-at-to-article
|
||||
--- datamodel.dml
|
||||
+++ datamodel.dml
|
||||
@@ -1,8 +1,8 @@
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
- url = "***"
|
||||
+ url = "***"
|
||||
}
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
@@ -19,12 +19,13 @@
|
||||
articles Article[]
|
||||
}
|
||||
model Article {
|
||||
- id Int @id @default(autoincrement())
|
||||
- title String
|
||||
- description String
|
||||
- markdownContent String
|
||||
- user User @relation(fields: [userId], references: [id])
|
||||
- userId Int
|
||||
+ id Int @id @default(autoincrement())
|
||||
+ createdAt DateTime @default(now())
|
||||
+ title String
|
||||
+ description String
|
||||
+ markdownContent String
|
||||
+ user User @relation(fields: [userId], references: [id])
|
||||
+ userId Int
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = "***"
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
output = "../server/node_modules/.prisma/client"
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
email String @unique
|
||||
password String
|
||||
bio String?
|
||||
profilePictureUrl String?
|
||||
articles Article[]
|
||||
}
|
||||
|
||||
model Article {
|
||||
id Int @id @default(autoincrement())
|
||||
createdAt DateTime @default(now())
|
||||
title String
|
||||
description String
|
||||
markdownContent String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": "0.3.14-fixed",
|
||||
"steps": [
|
||||
{
|
||||
"tag": "CreateField",
|
||||
"model": "Article",
|
||||
"field": "createdAt",
|
||||
"type": "DateTime",
|
||||
"arity": "Required"
|
||||
},
|
||||
{
|
||||
"tag": "CreateDirective",
|
||||
"location": {
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Article",
|
||||
"field": "createdAt"
|
||||
},
|
||||
"directive": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "CreateArgument",
|
||||
"location": {
|
||||
"tag": "Directive",
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Article",
|
||||
"field": "createdAt"
|
||||
},
|
||||
"directive": "default"
|
||||
},
|
||||
"argument": "",
|
||||
"value": "now()"
|
||||
}
|
||||
]
|
||||
}
|
@ -3,4 +3,5 @@
|
||||
20201030161549-user
|
||||
20201030185724-fixed-user
|
||||
20201117145436-added-bio-and-picture-to-user
|
||||
20201119144622-added-article-entity
|
||||
20201119144622-added-article-entity
|
||||
20201124192901-added-created-at-to-article
|
Loading…
Reference in New Issue
Block a user