i2u7sdyUTwdNB2zaZ(qGp4Us(SLZ=*g_Yn~4yZ)z$gW
z1XJf=WLV0U-((isSoiW&%8TE{jFAQ+($M|4Rm$>KDV~FIzM2aa1#F=6Li3z_-2m^?;*N;{
zsk=N&$bCQiiODpJueDg&s^G2fb0wrcn6<*;e&+|@VhSW6v_b3^3y3@K-}8a9*($Gs
zj&c%UtszXENr=olh>s?d-fdT3+hFVWRYznoD&h6N5KgeltFBlkjPiTD0Fde(k2ARvqjE3Iv`>^*DFJr12HLAskj3N
dm<)R~mTCuLr|Zu^(+uE}y0VtiR|T_x{{<$+w}=1$
diff --git a/src/app/api/posts/route.ts b/src/app/api/posts/route.ts
index 87aa72af..7d4259b3 100644
--- a/src/app/api/posts/route.ts
+++ b/src/app/api/posts/route.ts
@@ -4,12 +4,16 @@ import { z } from 'zod'
export async function GET(req: Request) {
const url = new URL(req.url)
-
const session = await getAuthSession()
+ // 获取请求的 Referer 头部
+ const referer = req.headers.get('Referer');
+ const isMyFeedRequest = referer && new URL(referer).pathname === '/myfeed';
+ // console.log("isMyFeedRequest",isMyFeedRequest);
+
let followedCommunitiesIds: string[] = []
- if (session) {
+ if (session && isMyFeedRequest) {
const followedCommunities = await db.subscription.findMany({
where: {
userId: session.user.id,
@@ -43,7 +47,7 @@ export async function GET(req: Request) {
name: subredditName,
},
}
- } else if (session) {
+ } else if (session && isMyFeedRequest) {
whereClause = {
subreddit: {
id: {
diff --git a/src/app/api/subreddit/post/vote/route.ts b/src/app/api/subreddit/post/vote/route.ts
index 40efac15..4a74d7f0 100644
--- a/src/app/api/subreddit/post/vote/route.ts
+++ b/src/app/api/subreddit/post/vote/route.ts
@@ -5,7 +5,7 @@ import { PostVoteValidator } from '@/lib/validators/vote'
import { CachedPost } from '@/types/redis'
import { z } from 'zod'
-const CACHE_AFTER_UPVOTES = 1
+const CACHE_AFTER_UPVOTES = 0
export async function PATCH(req: Request) {
try {
@@ -61,16 +61,16 @@ export async function PATCH(req: Request) {
}, 0)
if (votesAmt >= CACHE_AFTER_UPVOTES) {
- const cachePayload: CachedPost = {
- authorUsername: post.author.username ?? '',
+ const cachePayload = {
+ authorUsername: post.author.name ?? '',
content: JSON.stringify(post.content),
id: post.id,
title: post.title,
- currentVote: null,
- createdAt: post.createdAt,
+ currentVote: "null",
+ createdAt: post.createdAt.toISOString(),
}
- await redis.hset(`post:${postId}`, cachePayload) // Store the post data as a hash
+ await redis.hSet(`post:${postId}`, cachePayload) // Store the post data as a hash
}
return new Response('OK')
@@ -97,16 +97,16 @@ export async function PATCH(req: Request) {
}, 0)
if (votesAmt >= CACHE_AFTER_UPVOTES) {
- const cachePayload: CachedPost = {
- authorUsername: post.author.username ?? '',
+ const cachePayload = {
+ authorUsername: post.author.name ?? '',
content: JSON.stringify(post.content),
id: post.id,
title: post.title,
- currentVote: voteType,
- createdAt: post.createdAt,
+ currentVote: voteType ? voteType : 'null',
+ createdAt: post.createdAt.toISOString(),
}
- await redis.hset(`post:${postId}`, cachePayload) // Store the post data as a hash
+ await redis.hSet(`post:${postId}`, cachePayload) // Store the post data as a hash
}
return new Response('OK')
@@ -129,16 +129,16 @@ export async function PATCH(req: Request) {
}, 0)
if (votesAmt >= CACHE_AFTER_UPVOTES) {
- const cachePayload: CachedPost = {
- authorUsername: post.author.username ?? '',
+ const cachePayload = {
+ authorUsername: post.author.name ?? '',
content: JSON.stringify(post.content),
id: post.id,
title: post.title,
- currentVote: voteType,
- createdAt: post.createdAt,
+ currentVote: voteType ? voteType : 'null',
+ createdAt: post.createdAt.toISOString(),
}
- await redis.hset(`post:${postId}`, cachePayload) // Store the post data as a hash
+ await redis.hSet(`post:${postId}`, cachePayload) // Store the post data as a hash
}
return new Response('OK')
diff --git a/src/app/api/upload/backroute b/src/app/api/upload/backroute
new file mode 100644
index 00000000..91b032dd
--- /dev/null
+++ b/src/app/api/upload/backroute
@@ -0,0 +1,61 @@
+import { getAuthSession } from '@/lib/auth'
+import { writeFile } from "fs/promises";
+import { NextResponse } from "next/server";
+import { v4 as uuidv4 } from 'uuid'; // 引入uuid
+import { existsSync, mkdirSync } from 'fs';
+
+export async function POST(request: Request) {
+
+ const session = await getAuthSession()
+ if (!session?.user) {
+ return new Response('Unauthorized', { status: 401 })
+ }
+
+ const formData = await request.formData();
+ // 获取上传文件
+ const file = formData.get("file") as File;
+ // 定义文件保存的目录和访问路径
+ const currentYear = new Date().getFullYear();
+ const uploadDir = `./public/uploads/${currentYear}/`;
+ const accessPath = `/uploads/${currentYear}/`;
+
+ if (!file) {
+ return new NextResponse(JSON.stringify({ error: 'No file uploaded' }), {
+ status: 400,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+
+ // 检查文件大小
+ const maxFileSize = 4 * 1024 * 1024; // 4MB
+ if (file.size > maxFileSize) {
+ return new NextResponse(JSON.stringify({ error: 'File is too large' }), {
+ status: 400,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+
+ // // 使用uuid生成唯一文件名
+ // const fileExtension = file.name.split('.').pop(); // 获取文件扩展名
+ // const fileName = uuidv4() + '.' + fileExtension; // 生成唯一文件名
+ // // 将文件保存到服务器的文件系统中
+ // const fileBuffer = await file.arrayBuffer();
+ // // 生成文件保存路径
+ // const filePath = uploadDir + fileName;
+ // // 生成访问URL
+ // const fileUrl = request.headers.get("origin") + accessPath + fileName;
+
+ // // 检查上传目录是否存在,如果不存在则创建
+ // if (!existsSync(uploadDir)) {
+ // mkdirSync(uploadDir, { recursive: true }); // 使用 recursive 选项创建嵌套目录
+ // }
+ // await writeFile(filePath, Buffer.from(fileBuffer));
+
+ // return new NextResponse(JSON.stringify({ url: fileUrl }), {
+ // status: 200,
+ // headers: {
+ // "Content-Type": "application/json"
+ // }
+ // });
+}
+
diff --git a/src/app/api/upload/route.ts b/src/app/api/upload/route.ts
new file mode 100644
index 00000000..e75ea441
--- /dev/null
+++ b/src/app/api/upload/route.ts
@@ -0,0 +1,71 @@
+import { getAuthSession } from '@/lib/auth'
+// import { writeFile } from "fs/promises";
+import { NextResponse } from "next/server";
+// import { v4 as uuidv4 } from 'uuid'; // 引入uuid
+// import { existsSync, mkdirSync } from 'fs';
+import axios from 'axios'
+
+export async function POST(request: Request) {
+
+ const session = await getAuthSession()
+ if (!session?.user) {
+ return new Response('Unauthorized', { status: 401 })
+ }
+
+ const formData = await request.formData();
+ // 获取上传文件
+ const file = formData.get("file") as File;
+
+ if (!file) {
+ return new NextResponse(JSON.stringify({ error: 'No file uploaded' }), {
+ status: 400,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+
+ console.log("文件大小:",file.size / 1024 / 1024)
+ // 检查文件大小
+ const maxFileSize = 4 * 1024 * 1024; // 4MB
+ if (file.size > maxFileSize) {
+ return new NextResponse(JSON.stringify({ error: 'File is too large' }), {
+ status: 400,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+
+ //上传到图片服务器 .env中配置http://localhost:8080/upload
+ const uploadFormData = new FormData();
+ uploadFormData.append('file', file);
+
+ try {
+ // 替换这里的URL为你的图片服务器上传接口地址
+ if (!process.env.UPLOAD_SERVER) {
+ throw new Error('UPLOAD_SERVER environment variable is not defined.');
+ }
+ const response = await axios.post(process.env.UPLOAD_SERVER, uploadFormData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ 'X-API-KEY': process.env.UPLOAD_SECRET, // 如果你的图片服务器需要API密钥
+ },
+ });
+
+ // 处理响应
+ const { data } = response;
+ if (data && data.url) {
+ // 如果图片服务器返回的有图片的URL
+ return new Response(JSON.stringify({ url: data.url }), {
+ status: 200,
+ headers: { "Content-Type": "application/json" },
+ });
+ } else {
+ throw new Error('Failed to upload image.');
+ }
+ } catch (error) {
+ // console.error(error);
+ return new Response(JSON.stringify({ error: 'Failed to upload image' }), {
+ status: 500,
+ headers: { "Content-Type": "application/json" },
+ });
+ }
+}
+
diff --git a/src/app/api/uploadvideo/route.ts b/src/app/api/uploadvideo/route.ts
new file mode 100644
index 00000000..8801d679
--- /dev/null
+++ b/src/app/api/uploadvideo/route.ts
@@ -0,0 +1,56 @@
+import { getAuthSession } from '@/lib/auth';
+import { writeFile } from 'fs/promises';
+import { NextResponse } from 'next/server';
+import { v4 as uuidv4 } from 'uuid';
+import { existsSync, mkdirSync } from 'fs';
+
+export async function POST(request: Request) {
+ const session = await getAuthSession();
+ if (!session?.user) {
+ return new Response('Unauthorized', { status: 401 });
+ }
+
+ const formData = await request.formData();
+ // 获取上传的文件
+ const file = formData.get('file') as File;
+ // 定义文件保存的目录和访问路径
+ const currentYear = new Date().getFullYear();
+ const uploadDir = `./public/uploadvideos/${currentYear}/videos/`;
+ const accessPath = `/uploadvideos/${currentYear}/videos/`;
+
+ if (!file) {
+ return new NextResponse(JSON.stringify({ error: 'No file uploaded' }), {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' },
+ });
+ }
+
+ // 检查文件大小(例如,设置为 100MB)
+ const maxFileSize = 100 * 1024 * 1024; // 100MB
+ if (file.size > maxFileSize) {
+ return new NextResponse(JSON.stringify({ error: 'File is too large' }), {
+ status: 400,
+ headers: { 'Content-Type': 'application/json' },
+ });
+ }
+
+ // 使用 uuid 生成唯一文件名
+ const fileExtension = file.name.split('.').pop(); // 获取文件扩展名
+ const fileName = uuidv4() + '.' + fileExtension; // 生成唯一文件名
+ const fileBuffer = await file.arrayBuffer();
+ const filePath = uploadDir + fileName;
+ const fileUrl = request.headers.get('origin') + accessPath + fileName;
+
+ // 检查上传目录是否存在,如果不存在则创建
+ if (!existsSync(uploadDir)) {
+ mkdirSync(uploadDir, { recursive: true });
+ }
+ await writeFile(filePath, Buffer.from(fileBuffer));
+
+ return new NextResponse(JSON.stringify({ url: fileUrl }), {
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
diff --git a/src/app/api/username/route.ts b/src/app/api/username/route.ts
index 701d7cdc..c75ef11a 100644
--- a/src/app/api/username/route.ts
+++ b/src/app/api/username/route.ts
@@ -17,12 +17,12 @@ export async function PATCH(req: Request) {
// check if username is taken
const username = await db.user.findFirst({
where: {
- username: name,
+ name: name,
},
})
if (username) {
- return new Response('Username is taken', { status: 409 })
+ return new Response('用户名已被占用', { status: 409 })
}
// update username
@@ -31,7 +31,7 @@ export async function PATCH(req: Request) {
id: session.user.id,
},
data: {
- username: name,
+ name: name,
},
})
diff --git a/src/app/api/weixinauth/route.ts b/src/app/api/weixinauth/route.ts
new file mode 100644
index 00000000..b3a9a9f7
--- /dev/null
+++ b/src/app/api/weixinauth/route.ts
@@ -0,0 +1,60 @@
+// src/app/weixinauth/route.ts
+
+import { signIn } from "next-auth/react";
+
+export async function GET(req: Request) {
+ const url = new URL(req.url);
+ const code = url.searchParams.get('code');
+ const state = url.searchParams.get('state');
+
+ if (!code) return new Response('Code is required', { status: 400 });
+
+ let APP_ID,APP_SECRET;
+ if(state === "open"){
+ APP_ID = process.env.NEXT_PUBLIC_WX_OPEN_APP_ID; // 从环境变量中获取
+ APP_SECRET = process.env.WX_OPEN_APP_SECRET; // 从环境变量中获取
+ }else{
+ APP_ID = process.env.NEXT_PUBLIC_WEIXIN_APP_ID; // 从环境变量中获取
+ APP_SECRET = process.env.WEIXIN_APP_SECRET; // 从环境变量中获取
+ }
+ console.log("code =",code);
+ console.log(APP_ID);
+ console.log(APP_SECRET);
+ if (!APP_ID || !APP_SECRET) {
+ return new Response('Missing WEIXIN_APP_ID or WEIXIN_APP_SECRET in environment variables', { status: 500 });
+ }
+
+ const accessTokenUrl = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APP_ID}&secret=${APP_SECRET}&code=${code}&grant_type=authorization_code`;
+ console.log(accessTokenUrl);
+ try {
+ const accessTokenResponse = await fetch(accessTokenUrl);
+ const accessTokenData = await accessTokenResponse.json();
+ console.log("accessTokenData");
+ console.log(accessTokenData);
+ if (accessTokenData.errcode) {
+ return new Response(JSON.stringify(accessTokenData), { status: 500 });
+ }
+
+ // 获取用户信息
+ const userInfoUrl = `https://api.weixin.qq.com/sns/userinfo?access_token=${accessTokenData.access_token}&openid=${accessTokenData.openid}&lang=zh_CN`;
+
+ const userInfoResponse = await fetch(userInfoUrl);
+ const userInfo = await userInfoResponse.json();
+
+ if (userInfo.errcode) {
+ return new Response(JSON.stringify(userInfo), { status: 500 });
+ }
+
+ // 在userInfo对象中添加access_token和refresh_token
+ userInfo.access_token = accessTokenData.access_token;
+ userInfo.refresh_token = accessTokenData.refresh_token;
+
+ console.log("获得微信用户信息和令牌");
+ console.log(userInfo);
+ return new Response(JSON.stringify(userInfo));
+
+ } catch (error) {
+ console.error('Weixin Authentication Error:', error);
+ return new Response('Internal Server Error', { status: 500 });
+ }
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index e876175e..44ea10ca 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,16 +1,16 @@
import Navbar from '@/components/Navbar'
import { cn } from '@/lib/utils'
-import { Inter } from 'next/font/google'
+// import { Inter } from 'next/font/google'
import Providers from '@/components/Providers'
import { Toaster } from '@/components/ui/Toaster'
import '@/styles/globals.css'
-const inter = Inter({ subsets: ['latin'] })
+// const inter = Inter({ subsets: ['latin'] })
export const metadata = {
- title: 'Breadit',
- description: 'A Reddit clone built with Next.js and TypeScript.',
+ title: '绘画爱好者社区',
+ description: '绘园|绘画爱好者社区|分享你的绘画.',
}
export default function RootLayout({
@@ -25,7 +25,7 @@ export default function RootLayout({
lang='en'
className={cn(
'bg-white text-slate-900 antialiased light',
- inter.className
+ // inter.className
)}>
@@ -33,7 +33,7 @@ export default function RootLayout({
{authModal}
-
+
{children}
diff --git a/src/app/myfeed/page.tsx b/src/app/myfeed/page.tsx
new file mode 100644
index 00000000..49f4dc84
--- /dev/null
+++ b/src/app/myfeed/page.tsx
@@ -0,0 +1,50 @@
+import { redirect } from 'next/navigation'
+import CustomFeed from '@/components/homepage/CustomFeed'
+import { buttonVariants } from '@/components/ui/Button'
+import { Home as HomeIcon } from 'lucide-react'
+import Link from 'next/link'
+import { authOptions, getAuthSession } from '@/lib/auth'
+
+export default async function MyFeed() {
+ const session = await getAuthSession()
+ if (!session?.user) {
+ redirect(authOptions?.pages?.signIn || '/login')
+ }
+ const PostCustomFeed = await CustomFeed();
+ return (
+ <>
+
我的关注
+
+ {/* @ ts-expect-error server component */}
+ {/* {session ?
:
} */}
+ {PostCustomFeed}
+
+
+ {/* subreddit info */}
+
+
+ >
+ )
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 1f388356..37ba5dd6 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,4 +1,4 @@
-import CustomFeed from '@/components/homepage/CustomFeed'
+// import CustomFeed from '@/components/homepage/CustomFeed'
import GeneralFeed from '@/components/homepage/GeneralFeed'
import { buttonVariants } from '@/components/ui/Button'
import { getAuthSession } from '@/lib/auth'
@@ -10,27 +10,31 @@ export const fetchCache = 'force-no-store'
export default async function Home() {
const session = await getAuthSession()
-
+ const PostFeed = await GeneralFeed();
return (
<>
-
Your feed
+
+ 开始分享你的绘画
+
+ {/*
分享你的绘画
*/}
- {/* @ts-expect-error server component */}
- {session ?
:
}
+ {/* @ ts-expect-error server component */}
+ {/* {session ?
:
} */}
+ {PostFeed}
+
{/* subreddit info */}
-
+ { session &&
- Your personal Breadit frontpage. Come here to check in with your
- favorite communities.
+ 创建属于你的版块
@@ -39,10 +43,10 @@ export default async function Home() {
className: 'w-full mt-4 mb-6',
})}
href={`/r/create`}>
- Create Community
+ 创建版块
-
+
}
>
)
diff --git a/src/app/r/[slug]/layout.tsx b/src/app/r/[slug]/layout.tsx
index 824b5faf..b122cee2 100644
--- a/src/app/r/[slug]/layout.tsx
+++ b/src/app/r/[slug]/layout.tsx
@@ -10,7 +10,7 @@ import { notFound } from 'next/navigation'
import { ReactNode } from 'react'
export const metadata: Metadata = {
- title: 'Breadit',
+ title: '绘园',
description: 'A Reddit clone built with Next.js and TypeScript.',
}
@@ -22,9 +22,10 @@ const Layout = async ({
params: { slug: string }
}) => {
const session = await getAuthSession()
+ const decodedSlug = decodeURIComponent(slug);
const subreddit = await db.subreddit.findFirst({
- where: { name: slug },
+ where: { name: decodedSlug },
include: {
posts: {
include: {
@@ -40,7 +41,7 @@ const Layout = async ({
: await db.subscription.findFirst({
where: {
subreddit: {
- name: slug,
+ name: decodedSlug,
},
user: {
id: session.user.id,
@@ -55,13 +56,13 @@ const Layout = async ({
const memberCount = await db.subscription.count({
where: {
subreddit: {
- name: slug,
+ name: decodedSlug,
},
},
})
return (
-
+
@@ -71,26 +72,26 @@ const Layout = async ({
{/* info sidebar */}
-
About r/{subreddit.name}
+
版块/{subreddit.name}
-
- Created
+ - 创建于
-
-
- Members
+
- 已关注
-
-
{memberCount}
+ {memberCount}人
{subreddit.creatorId === session?.user?.id ? (
-
- You created this community
+ - 你创造了这个版块
) : null}
@@ -106,8 +107,8 @@ const Layout = async ({
variant: 'outline',
className: 'w-full mb-6',
})}
- href={`r/${slug}/submit`}>
- Create Post
+ href={`r/${decodedSlug}/submit`}>
+ 发布帖子
diff --git a/src/app/r/[slug]/page.tsx b/src/app/r/[slug]/page.tsx
index f823b64f..f82c07ac 100644
--- a/src/app/r/[slug]/page.tsx
+++ b/src/app/r/[slug]/page.tsx
@@ -13,11 +13,11 @@ interface PageProps {
const page = async ({ params }: PageProps) => {
const { slug } = params
-
+ const decodedSlug = decodeURIComponent(slug);
const session = await getAuthSession()
const subreddit = await db.subreddit.findFirst({
- where: { name: slug },
+ where: { name: decodedSlug },
include: {
posts: {
include: {
@@ -38,8 +38,9 @@ const page = async ({ params }: PageProps) => {
return (
<>
+ {/*
版块/ */}
- r/{subreddit.name}
+ {subreddit.name}
diff --git a/src/app/r/[slug]/post/[postId]/page.tsx b/src/app/r/[slug]/post/[postId]/page.tsx
index 484fab15..8de5f5bb 100644
--- a/src/app/r/[slug]/post/[postId]/page.tsx
+++ b/src/app/r/[slug]/post/[postId]/page.tsx
@@ -1,31 +1,47 @@
-import CommentsSection from '@/components/CommentsSection'
-import EditorOutput from '@/components/EditorOutput'
-import PostVoteServer from '@/components/post-vote/PostVoteServer'
-import { buttonVariants } from '@/components/ui/Button'
-import { db } from '@/lib/db'
-import { redis } from '@/lib/redis'
-import { formatTimeToNow } from '@/lib/utils'
-import { CachedPost } from '@/types/redis'
-import { Post, User, Vote } from '@prisma/client'
-import { ArrowBigDown, ArrowBigUp, Loader2 } from 'lucide-react'
-import { notFound } from 'next/navigation'
-import { Suspense } from 'react'
+import CommentsSection from "@/components/CommentsSection";
+import EditorOutput from "@/components/EditorOutput";
+import PostVoteServer from "@/components/post-vote/PostVoteServer";
+import { buttonVariants } from "@/components/ui/Button";
+import { db } from "@/lib/db";
+import { redis } from "@/lib/redis";
+import { formatTimeToNow } from "@/lib/utils";
+import { CachedPost } from "@/types/redis";
+import { Post, User, Vote } from "@prisma/client";
+import { ArrowBigDown, ArrowBigUp, Loader2 } from "lucide-react";
+import { notFound } from "next/navigation";
+import { Suspense } from "react";
interface SubRedditPostPageProps {
params: {
- postId: string
- }
+ postId: string;
+ };
}
-export const dynamic = 'force-dynamic'
-export const fetchCache = 'force-no-store'
+export const dynamic = "force-dynamic";
+export const fetchCache = "force-no-store";
const SubRedditPostPage = async ({ params }: SubRedditPostPageProps) => {
- const cachedPost = (await redis.hgetall(
- `post:${params.postId}`
- )) as CachedPost
-
- let post: (Post & { votes: Vote[]; author: User }) | null = null
+ let cachedPost: CachedPost | null = null;
+ console.log("params", params)
+ try {
+ const result = await redis.hGetAll(`post:${params.postId}`);
+ console.log("result")
+ console.log(result)
+ if (Object.keys(result).length) {
+ // Ensure the result is of the expected type, or convert it as necessary
+ cachedPost = result as unknown as CachedPost;
+ console.log("cachedPost");
+ console.log(cachedPost);
+ } else {
+ // Handle the case where the hash does not exist or is empty
+ console.log(`Post with ID ${params.postId} not found in cache.`);
+ }
+ } catch (error) {
+ console.error(`Error fetching post from Redis: ${error}`);
+ }
+ let post: (Post & { votes: Vote[]; author: User }) | null = null;
+ console.log(post);
+ console.log(!cachedPost);
if (!cachedPost) {
post = await db.post.findFirst({
@@ -36,18 +52,42 @@ const SubRedditPostPage = async ({ params }: SubRedditPostPageProps) => {
votes: true,
author: true,
},
- })
+ });
}
+ console.log("2");
- if (!post && !cachedPost) return notFound()
+ const postId = post?.id ?? cachedPost?.id;
+ console.log(postId);
+ if (!postId) return notFound();
return (
-
+
+
+
+
+
+ 发表于
+ {(post?.createdAt ?? cachedPost?.createdAt) &&
+ formatTimeToNow(
+ new Date((post?.createdAt ?? cachedPost?.createdAt)!)
+ )}{" "}
+ /{" "}{post?.author.name ?? cachedPost?.authorUsername}
+
+
+ {post?.title ?? cachedPost?.title}
+
+
+
+ {/*
comment here
*/}
+
+
+
+
}>
{/* @ts-expect-error server component */}
{
return await db.post.findUnique({
where: {
@@ -56,53 +96,43 @@ const SubRedditPostPage = async ({ params }: SubRedditPostPageProps) => {
include: {
votes: true,
},
- })
+ });
}}
/>
-
-
-
- Posted by u/{post?.author.username ?? cachedPost.authorUsername}{' '}
- {formatTimeToNow(new Date(post?.createdAt ?? cachedPost.createdAt))}
-
-
- {post?.title ?? cachedPost.title}
-
-
-
-
- }>
- {/* @ts-expect-error Server Component */}
-
-
-
+
+
+ }
+ >
+ {/* @ts-expect-error Server Component */}
+
+
- )
-}
+ );
+};
function PostVoteShell() {
return (
-
+
{/* upvote */}
-
-
+
{/* score */}
-
-
+
+
{/* downvote */}
-
- )
+ );
}
-export default SubRedditPostPage
+export default SubRedditPostPage;
\ No newline at end of file
diff --git a/src/app/r/[slug]/submit/page.tsx b/src/app/r/[slug]/submit/page.tsx
index 9acde787..783a3314 100644
--- a/src/app/r/[slug]/submit/page.tsx
+++ b/src/app/r/[slug]/submit/page.tsx
@@ -10,9 +10,10 @@ interface pageProps {
}
const page = async ({ params }: pageProps) => {
+ const decodedSlug = decodeURIComponent(params.slug);
const subreddit = await db.subreddit.findFirst({
where: {
- name: params.slug,
+ name: decodedSlug,
},
})
@@ -24,10 +25,10 @@ const page = async ({ params }: pageProps) => {
- Create Post
+ 创建帖子
- in r/{params.slug}
+ 版块/{decodedSlug}
@@ -37,7 +38,7 @@ const page = async ({ params }: pageProps) => {
diff --git a/src/app/r/create/page.tsx b/src/app/r/create/page.tsx
index 1b6c42aa..5a5c3f71 100644
--- a/src/app/r/create/page.tsx
+++ b/src/app/r/create/page.tsx
@@ -28,16 +28,16 @@ const Page = () => {
if (err instanceof AxiosError) {
if (err.response?.status === 409) {
return toast({
- title: 'Subreddit already exists.',
- description: 'Please choose a different name.',
+ title: '版块名已存在.',
+ description: '请重新输入一个版块名称.',
variant: 'destructive',
})
}
if (err.response?.status === 422) {
return toast({
- title: 'Invalid subreddit name.',
- description: 'Please choose a name between 3 and 21 letters.',
+ title: '版块名错误.',
+ description: '版块名长度需要在1到21个字符之间.',
variant: 'destructive',
})
}
@@ -48,8 +48,8 @@ const Page = () => {
}
toast({
- title: 'There was an error.',
- description: 'Could not create subreddit.',
+ title: '出错了.',
+ description: '不能创版块.',
variant: 'destructive',
})
},
@@ -62,24 +62,24 @@ const Page = () => {
-
Create a Community
+ 创建新版块
-
Name
+
请填写版块名称
- Community names including capitalization cannot be changed.
+ 名称不能为空
-
- r/
+
+ 版块/
setInput(e.target.value)}
- className='pl-6'
+ className='pl-10'
/>
@@ -89,13 +89,13 @@ const Page = () => {
disabled={isLoading}
variant='subtle'
onClick={() => router.back()}>
- Cancel
+ 取消
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx
index f9f3160d..57be2423 100644
--- a/src/app/settings/page.tsx
+++ b/src/app/settings/page.tsx
@@ -16,15 +16,15 @@ export default async function SettingsPage() {
}
return (
-
+
-
Settings
+
设置
diff --git a/src/app/weixin-callback/page.tsx b/src/app/weixin-callback/page.tsx
new file mode 100644
index 00000000..17733c5c
--- /dev/null
+++ b/src/app/weixin-callback/page.tsx
@@ -0,0 +1,64 @@
+'use client'
+
+import { signIn } from 'next-auth/react';
+import { FC,useEffect } from 'react'
+
+const page : FC = () => {
+
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useEffect(() => {
+ // 在这里处理微信回调的逻辑
+ // 解析查询参数,执行身份验证等
+ const queryParams = new URLSearchParams(window.location.search);
+ const code = queryParams.get('code');
+ const state = queryParams.get('state');
+
+ // 示例:输出获取到的 code 和 state 参数
+ console.log('code:', code);
+ console.log('state:', state);
+
+
+ if (!code) {
+ console.error('code is missing in environment variables.');
+ return;
+ }
+
+ // 调用你的自定义 API
+ fetch(`/api/weixinauth?code=${code}&state=${state}`)
+ .then(response => response.json())
+ .then(data => {
+ // 假设返回的数据中包含了必要的用户信息
+ console.log(JSON.stringify(data));
+
+ // 检查 data 是否包含必要字段
+ if (data && data.openid && data.nickname) {
+ // 使用 signIn 完成登录
+ signIn('weixin', {
+ redirect: true,
+ ...data
+ });
+ } else {
+ console.error('Required data is missing');
+ }
+
+ })
+ .catch(error => {
+ console.error('Error while signing in:', error);
+ });
+
+
+
+
+ }, []);
+
+
+ return (
+
+
绘画是心灵的事务,不是手的事务
+
+
登录中,请稍后...
+
+ );
+};
+
+export default page;
\ No newline at end of file
diff --git a/src/components/CommentsSection.tsx b/src/components/CommentsSection.tsx
index 557f5670..a8c41345 100644
--- a/src/components/CommentsSection.tsx
+++ b/src/components/CommentsSection.tsx
@@ -42,8 +42,8 @@ const CommentsSection = async ({ postId }: CommentsSectionProps) => {
})
return (
-
-
+
+
diff --git a/src/components/CreateComment.tsx b/src/components/CreateComment.tsx
index f8c94cde..ab763da1 100644
--- a/src/components/CreateComment.tsx
+++ b/src/components/CreateComment.tsx
@@ -54,14 +54,14 @@ const CreateComment: FC
= ({ postId, replyToId }) => {
return (
-
+
diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx
index 5f8eaad2..abe82f22 100644
--- a/src/components/Editor.tsx
+++ b/src/components/Editor.tsx
@@ -7,13 +7,11 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import { useForm } from 'react-hook-form'
import TextareaAutosize from 'react-textarea-autosize'
import { z } from 'zod'
-
import { toast } from '@/hooks/use-toast'
-import { uploadFiles } from '@/lib/uploadthing'
+// import { uploadFiles } from '@/lib/uploadthing'
import { PostCreationRequest, PostValidator } from '@/lib/validators/post'
import { useMutation } from '@tanstack/react-query'
import axios from 'axios'
-
import '@/styles/editor.css'
type FormData = z.infer
@@ -53,8 +51,8 @@ export const Editor: React.FC = ({ subredditId }) => {
},
onError: () => {
return toast({
- title: 'Something went wrong.',
- description: 'Your post was not published. Please try again.',
+ title: '出了点问题.',
+ description: '你的帖子发布失败,请重试.',
variant: 'destructive',
})
},
@@ -66,7 +64,7 @@ export const Editor: React.FC = ({ subredditId }) => {
router.refresh()
return toast({
- description: 'Your post has been published.',
+ description: '你的帖子已经发表了.',
})
},
})
@@ -75,7 +73,7 @@ export const Editor: React.FC = ({ subredditId }) => {
const EditorJS = (await import('@editorjs/editorjs')).default
const Header = (await import('@editorjs/header')).default
const Embed = (await import('@editorjs/embed')).default
- const Table = (await import('@editorjs/table')).default
+ // const Table = (await import('@editorjs/table')).default
const List = (await import('@editorjs/list')).default
const Code = (await import('@editorjs/code')).default
const LinkTool = (await import('@editorjs/link')).default
@@ -88,7 +86,7 @@ export const Editor: React.FC = ({ subredditId }) => {
onReady() {
ref.current = editor
},
- placeholder: 'Type here to write your post...',
+ placeholder: '输入图文内容...',
inlineToolbar: true,
data: { blocks: [] },
tools: {
@@ -104,24 +102,62 @@ export const Editor: React.FC = ({ subredditId }) => {
config: {
uploader: {
async uploadByFile(file: File) {
- // upload to uploadthing
- const [res] = await uploadFiles([file], 'imageUploader')
-
- return {
- success: 1,
- file: {
- url: res.fileUrl,
- },
+ // // upload to uploadthing
+ // const [res] = await uploadFiles([file], 'imageUploader')
+
+ // return {
+ // success: 1,
+ // file: {
+ // url: res.fileUrl,
+ // },
+ // }
+
+ //upload to localhost
+ const formData = new FormData();
+ formData.append('file', file);
+ console.log("file",file);
+ try{
+ // 发送POST请求到你的文件上传API
+ const response = await axios.post('/api/upload', formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ },
+ });
+
+ // 假设你的API返回文件在服务器上的访问URL
+ const fileUrl = response.data.url;
+
+ return {
+ success: 1,
+ file: {
+ url: fileUrl,
+ },
+ }
+ }catch(error){
+ console.log('Upload failed', error);
+ return {
+ success: 0,
+ };
}
+
+
},
},
+ types: 'image/*,.HEIC,.heic', // 添加对 HEIC 文件的支持
},
},
list: List,
code: Code,
inlineCode: InlineCode,
- table: Table,
+ // table: Table,
embed: Embed,
+ // video: {
+ // class: VideoTool,
+ // config: {
+ // // 视频工具的配置选项
+
+ // }
+ // }
},
})
}
@@ -132,7 +168,7 @@ export const Editor: React.FC = ({ subredditId }) => {
for (const [_key, value] of Object.entries(errors)) {
value
toast({
- title: 'Something went wrong.',
+ title: '出了点问题.',
description: (value as { message: string }).message,
variant: 'destructive',
})
@@ -197,16 +233,16 @@ export const Editor: React.FC = ({ subredditId }) => {
_titleRef.current = e
}}
{...rest}
- placeholder='Title'
+ placeholder='标题'
className='w-full resize-none appearance-none overflow-hidden bg-transparent text-5xl font-bold focus:outline-none'
/>
- Use{' '}
+ 按{' '}
Tab
{' '}
- to open the command menu.
+ 键打开功能菜单.
diff --git a/src/components/MiniCreatePost.tsx b/src/components/MiniCreatePost.tsx
index f8662d76..b24e1f08 100644
--- a/src/components/MiniCreatePost.tsx
+++ b/src/components/MiniCreatePost.tsx
@@ -32,7 +32,7 @@ const MiniCreatePost: FC = ({ session }) => {
router.push(pathname + '/submit')}
readOnly
- placeholder='Create post'
+ placeholder='发布帖子'
/>