diff --git a/README-zh.md b/README-zh.md index 9dfe684..998c3c1 100644 --- a/README-zh.md +++ b/README-zh.md @@ -56,11 +56,22 @@ pnpm install pnpm dev ``` +#### 初始化数据库 + +```bash +pnpm postinstall +pnpm db:push +``` + +#### 激活管理员面板 + +Follow https://localhost:3000/setup + ## 社区群组 -- Discord: https://discord.gg/AHPQYuZu3m -- 微信群: - +- Discord: https://discord.gg/AHPQYuZu3m +- 微信群: + ![](https://wr.do/s/group) ## 许可证 diff --git a/README.md b/README.md index a6e195c..8dc93d1 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,17 @@ pnpm install pnpm dev ``` +#### Init database + +```bash +pnpm postinstall +pnpm db:push +``` + +#### Setup Admin Panel + +Follow https://localhost:3000/setup + ## Legitimacy review - To avoid abuse, applications without website content will be rejected @@ -68,9 +79,9 @@ pnpm dev ## Community Group -- Discord: https://discord.gg/AHPQYuZu3m -- 微信群: - +- Discord: https://discord.gg/AHPQYuZu3m +- 微信群: + ![](https://wr.do/s/group) ## License diff --git a/app/(protected)/admin/domains/domain-list.tsx b/app/(protected)/admin/domains/domain-list.tsx index d913e8b..300381c 100644 --- a/app/(protected)/admin/domains/domain-list.tsx +++ b/app/(protected)/admin/domains/domain-list.tsx @@ -2,20 +2,13 @@ import { useState } from "react"; import Link from "next/link"; -import { Domain, User } from "@prisma/client"; +import { User } from "@prisma/client"; import { PenLine, RefreshCwIcon } from "lucide-react"; import { toast } from "sonner"; import useSWR, { useSWRConfig } from "swr"; import { DomainFormData } from "@/lib/dto/domains"; -import { ShortUrlFormData } from "@/lib/dto/short-urls"; -import { - cn, - expirationTime, - fetcher, - removeUrlSuffix, - timeAgo, -} from "@/lib/utils"; +import { fetcher, timeAgo } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Card, @@ -23,7 +16,6 @@ import { CardDescription, CardHeader, } from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; import { Modal } from "@/components/ui/modal"; import { Skeleton } from "@/components/ui/skeleton"; import { Switch } from "@/components/ui/switch"; @@ -81,10 +73,10 @@ export default function DomainList({ user, action }: DomainListProps) { useState(null); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); - const [isShowDomainInfo, setShowDomainInfo] = useState(false); - const [selectedDomain, setSelectedDomain] = useState( - null, - ); + // const [isShowDomainInfo, setShowDomainInfo] = useState(false); + // const [selectedDomain, setSelectedDomain] = useState( + // null, + // ); const [searchParams, setSearchParams] = useState({ slug: "", target: "", @@ -169,7 +161,7 @@ export default function DomainList({ user, action }: DomainListProps) { -
+ {/*
)}
-
+
*/} @@ -274,6 +266,7 @@ export default function DomainList({ user, action }: DomainListProps) { handleChangeStatus(value, "active", domain) diff --git a/app/(protected)/dashboard/scrape/page.tsx b/app/(protected)/dashboard/scrape/page.tsx index 4c9d8fc..5904135 100644 --- a/app/(protected)/dashboard/scrape/page.tsx +++ b/app/(protected)/dashboard/scrape/page.tsx @@ -2,7 +2,7 @@ import { redirect } from "next/navigation"; import { getCurrentUser } from "@/lib/session"; import { constructMetadata } from "@/lib/utils"; -import { ScrapeInfoCard } from "@/components/dashboard/dashboard-info-card"; +import { StaticInfoCard } from "@/components/dashboard/dashboard-info-card"; import { DashboardHeader } from "@/components/dashboard/header"; import DashboardScrapeCharts from "./charts"; @@ -26,22 +26,19 @@ export default async function DashboardPage() { linkText="Open API." />
- - -
- - ([]); + const [isMobile, setIsMobile] = useState(false); + + const steps = [ + { + id: 1, + title: "Set up an administrator", + description: + "Begin by entering your website URL or selecting an example site to reimagine your website with modern themes.", + component: () => , + }, + { + id: 2, + title: "Add the first domain", + description: + "Check out your reimagined site and click to Migrate & Download.", + component: () => , + }, + { + id: 3, + title: "Congrats on completing setup 🎉", + description: + "Navigate to your GitHub dashboard where you'll manage your repository and project files.", + component: () => , + }, + ]; + + useEffect(() => { + const checkMobile = () => { + setIsMobile(window.innerWidth < 768); + }; + + checkMobile(); + window.addEventListener("resize", checkMobile); + + return () => { + window.removeEventListener("resize", checkMobile); + }; + }, []); + + const goToNextStep = () => { + if (currentStep < steps.length) { + setDirection(1); + setCurrentStep(currentStep + 1); + if (!completedSteps.includes(currentStep)) { + setCompletedSteps([...completedSteps, currentStep]); + } + } else if (currentStep === steps.length) { + router.push("/admin"); + } + }; + + const goToPreviousStep = () => { + if (currentStep > 1) { + setDirection(-1); + setCurrentStep(currentStep - 1); + } + }; + + const currentStepData = + steps.find((step) => step.id === currentStep) || steps[0]; + + const variants = { + enter: (direction: number) => ({ + x: direction > 0 ? 100 : -100, + opacity: 0, + }), + center: { + x: 0, + opacity: 1, + }, + exit: (direction: number) => ({ + x: direction < 0 ? 100 : -100, + opacity: 0, + }), + }; + + return ( + +
+
+

Admin Setup Guide

+
+ + {currentStep} + + of + {steps.length} +
+
+ + {/* Content area */} +
+ + +
+
+ + {currentStep} + + + {currentStepData.title} + +
+ + + {currentStepData.component()} + +
+
+
+
+
+ + + + + + +
+ ); +} + +function SetAdminRole({ id, email }: { id: string; email: string }) { + const [isPending, startTransition] = useTransition(); + const [isAdmin, setIsAdmin] = useState(false); + const handleSetAdmin = async () => { + startTransition(async () => { + const res = await fetch("/api/setup"); + if (res.ok) { + setIsAdmin(true); + } + }); + }; + + const ReadyBadge = ( + + + Ready + + ); + + return ( +
+
+ + Allow Sign Up: + + {siteConfig.openSignup ? ReadyBadge : } +
+ +
+ + Set {email} as ADMIN: + + {isAdmin ? ( + ReadyBadge + ) : ( + + )} +
+ +
+

+ 📢 Only by becoming an administrator can one access the admin panel + and add domain names. +

+

+ 📢 Administrators can set all user permissions, allocate quotas, view + and edit all resources (short links, subdomains, email), etc. +

+

+ 📢 Via{" "} + + quick start + {" "} + docs to get more information. +

+
+
+ ); +} + +function AddDomain({ onNextStep }: { onNextStep: () => void }) { + const [isPending, startTransition] = useTransition(); + const [domain, setDomain] = useState(""); + const handleCreateDomain = async () => { + if (!domain) { + toast.warning("Domain name cannot be empty"); + return; + } + startTransition(async () => { + const res = await fetch("/api/admin/domain", { + method: "POST", + body: JSON.stringify({ + data: { + domain_name: removeUrlSuffix(domain), + enable_short_link: true, + enable_email: true, + enable_dns: true, + cf_zone_id: "", + cf_api_key: "", + cf_email: "", + cf_api_key_encrypted: false, + max_short_links: 0, + max_email_forwards: 0, + max_dns_records: 0, + active: true, + }, + }), + }); + if (res.ok) { + onNextStep(); + } else { + toast.error("Created Failed!", { + description: await res.text(), + }); + } + }); + }; + return ( +
+ +
+ +
+ setDomain(e.target.value)} + /> +
+

+ Please enter a valid domain name (must be hosted on Cloudflare). +

+
+ +
+ + +
+
+
+ ); +} + +function Congrats() { + return <>; +} diff --git a/app/(protected)/setup/loading.tsx b/app/(protected)/setup/loading.tsx new file mode 100644 index 0000000..2c0fcc0 --- /dev/null +++ b/app/(protected)/setup/loading.tsx @@ -0,0 +1,15 @@ +import { Skeleton } from "@/components/ui/skeleton"; +import { DashboardHeader } from "@/components/dashboard/header"; + +export default function DashboardLoading() { + return ( + <> + + + + + ); +} diff --git a/app/(protected)/setup/page.tsx b/app/(protected)/setup/page.tsx new file mode 100644 index 0000000..087a833 --- /dev/null +++ b/app/(protected)/setup/page.tsx @@ -0,0 +1,28 @@ +import { redirect } from "next/navigation"; + +import { getAllUsersCount } from "@/lib/dto/user"; +import { getCurrentUser } from "@/lib/session"; +import { constructMetadata } from "@/lib/utils"; + +import SetupGuide from "./guide"; + +export const metadata = constructMetadata({ + title: "Setup Guide", + description: "Setup Guide", +}); + +export default async function SetupPage() { + const user = await getCurrentUser(); + + if (!user?.id) redirect("/login"); + + if (user.role === "ADMIN") redirect("/admin"); + + const count = await getAllUsersCount(); + + if (count === 1 && user.role === "USER") { + return ; + } + + return redirect("/admin"); +} diff --git a/app/api/domain/route.ts b/app/api/domain/route.ts index 137ba1b..34b65c7 100644 --- a/app/api/domain/route.ts +++ b/app/api/domain/route.ts @@ -1,6 +1,6 @@ import { NextRequest } from "next/server"; -import { FeatureMap, getDomainsByFeature } from "@/lib/dto/domains"; +import { FeatureMap, getDomainsByFeatureClient } from "@/lib/dto/domains"; import { checkUserStatus } from "@/lib/dto/user"; import { getCurrentUser } from "@/lib/session"; @@ -22,7 +22,8 @@ export async function GET(req: NextRequest) { ); } - const domainList = await getDomainsByFeature(FeatureMap[feature]); + const domainList = await getDomainsByFeatureClient(FeatureMap[feature]); + return Response.json(domainList, { status: 200 }); } catch (error) { console.error("[Error]", error); diff --git a/app/api/setup/route.ts b/app/api/setup/route.ts new file mode 100644 index 0000000..0183d68 --- /dev/null +++ b/app/api/setup/route.ts @@ -0,0 +1,31 @@ +import { redirect } from "next/navigation"; + +import { + checkUserStatus, + getAllUsersCount, + setFirstUserAsAdmin, +} from "@/lib/dto/user"; +import { getCurrentUser } from "@/lib/session"; + +export async function GET(req: Request) { + try { + const user = checkUserStatus(await getCurrentUser()); + if (user instanceof Response) return user; + + const count = await getAllUsersCount(); + + if (count === 1 && user.role === "USER") { + const res = await setFirstUserAsAdmin(user.id); + if (res) { + return Response.json({ admin: res.role === "ADMIN" }, { status: 201 }); + } + return Response.json({ admin: false }, { status: 400 }); + } + + return redirect("/admin"); + } catch (error) { + return Response.json(error?.statusText || error, { + status: error.status || 500, + }); + } +} diff --git a/app/manifest.json b/app/manifest.json index 66a72fc..ad20795 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -3,7 +3,7 @@ "short_name": "WR.DO", "description": "Shorten links with analytics, manage emails and control subdomains—all on one platform.", "appid": "com.wr.do", - "versionName": "0.6.0", + "versionName": "0.6.1", "versionCode": "1", "start_url": "/", "orientation": "portrait", diff --git a/components/dashboard/dashboard-info-card.tsx b/components/dashboard/dashboard-info-card.tsx index 174b067..4f48634 100644 --- a/components/dashboard/dashboard-info-card.tsx +++ b/components/dashboard/dashboard-info-card.tsx @@ -145,14 +145,12 @@ export function HeroCard({ ); } -export async function ScrapeInfoCard({ - userId, +export async function StaticInfoCard({ title, desc, link, icon = "users", }: { - userId: string; title: string; desc?: string; link: string; diff --git a/components/email/EmailSidebar.tsx b/components/email/EmailSidebar.tsx index b9f0478..851c9c2 100644 --- a/components/email/EmailSidebar.tsx +++ b/components/email/EmailSidebar.tsx @@ -603,32 +603,34 @@ export default function EmailSidebar({ {isLoadingDomains ? ( ) : ( - emailDomains && ( - { + setDomainSuffix(value); + }} + name="suffix" + defaultValue={domainSuffix || "wr.do"} + disabled={isEdit} + > + + + + + {emailDomains && emailDomains.length > 0 ? ( + emailDomains.map((v) => ( @{v.domain_name} - ))} - - - ) + )) + ) : ( + + )} + + )}
diff --git a/components/forms/record-form.tsx b/components/forms/record-form.tsx index 9d590f8..9265df2 100644 --- a/components/forms/record-form.tsx +++ b/components/forms/record-form.tsx @@ -212,28 +212,32 @@ export function RecordForm({ {isLoading ? ( ) : ( - recordDomains && ( - { + setValue("zone_name", value); + setCurrentZoneName(value); + }} + name="zone_name" + defaultValue={String(initData?.zone_name || "wr.do")} + disabled={type === "edit"} + > + + + + + {recordDomains && recordDomains.length > 0 ? ( + recordDomains.map((v) => ( {v.domain_name} - ))} - - - ) + )) + ) : ( + + )} + + )}

Required. Select a domain. diff --git a/components/forms/url-form.tsx b/components/forms/url-form.tsx index 3899dfe..c15f0b7 100644 --- a/components/forms/url-form.tsx +++ b/components/forms/url-form.tsx @@ -204,29 +204,31 @@ export function UrlForm({ {isLoading ? ( ) : ( - shortDomains && ( - { + setValue("prefix", value); + }} + name="prefix" + defaultValue={initData?.prefix || "wr.do"} + disabled={type === "edit"} + > + + + + + {shortDomains && shortDomains.length > 0 ? ( + shortDomains.map((v) => ( {v.domain_name} - ))} - - - ) + )) + ) : ( + + )} + + )} - After change change the account's role to ADMIN, and then you can refresh the website and access http://localhost:3000/admin. +![](/_static/docs/setup-1.png) - You must add at least one domain to start using short links, email or subdomain management functions. +![](/_static/docs/setup-2.png) + + + After change the account's role to ADMIN, then you can refresh the website and access http://localhost:3000/admin. + + You must add at least one domain to start using short links, email or subdomain management features. ## Q & A @@ -215,17 +217,6 @@ https://dash.cloudflare.com/[account_id]/[zone_name]/ssl-tls/configuration Change the `SSL/TLS Encryption` Mode to `Full` in the Cloudflare dashboard. -### How can I access the admin panel after first deployment? - -You need to first register an account and log in, -and modify the `role` field of this account to `ADMIN` in the `users` table of the database. -Then, refresh the website and access http://localhost:3000/admin. - - -Although it may not be convenient to do so, this is currently the fastest way to become an administrator. -In future versions, we will implement the function of automatically setting up administrators as soon as possible. - - ### How can I change the team plan quota? Via team.ts: diff --git a/lib/dto/domains.ts b/lib/dto/domains.ts index 183b51b..41dff10 100644 --- a/lib/dto/domains.ts +++ b/lib/dto/domains.ts @@ -81,6 +81,20 @@ export async function getDomainsByFeature( } } +export async function getDomainsByFeatureClient(feature: string) { + try { + const domains = await prisma.domain.findMany({ + where: { [feature]: true }, + select: { + domain_name: true, + }, + }); + return domains; + } catch (error) { + throw new Error(`Failed to fetch domain config: ${error.message}`); + } +} + export async function createDomain(data: DomainConfig) { try { const createdDomain = await prisma.domain.create({ data }); diff --git a/lib/dto/user.ts b/lib/dto/user.ts index 8004a1f..9d91f71 100644 --- a/lib/dto/user.ts +++ b/lib/dto/user.ts @@ -85,6 +85,17 @@ export async function getAllUsersCount() { } } +export async function setFirstUserAsAdmin(userId: string) { + try { + return await prisma.user.update({ + where: { id: userId }, + data: { role: UserRole.ADMIN }, + }); + } catch (error) { + return null; + } +} + export async function getAllUsersActiveApiKeyCount() { try { return await prisma.user.count({ where: { apiKey: { not: null } } }); diff --git a/package.json b/package.json index 698f52c..17d9a3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wr.do", - "version": "0.6.0", + "version": "0.6.1", "author": { "name": "oiov", "url": "https://github.com/oiov" diff --git a/prisma/migrations/20240705091917_init/migration.sql b/prisma/migrations/20240705091917_init/migration.sql index 9cb9c4b..4096392 100644 --- a/prisma/migrations/20240705091917_init/migration.sql +++ b/prisma/migrations/20240705091917_init/migration.sql @@ -274,7 +274,7 @@ CREATE TABLE "user_send_emails" "html" TEXT DEFAULT '', "replyTo" TEXT DEFAULT '', "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX "user_send_emails_userId_idx" ON "user_send_emails" ("userId"); diff --git a/public/_static/docs/setup-1.png b/public/_static/docs/setup-1.png new file mode 100644 index 0000000..b266c68 Binary files /dev/null and b/public/_static/docs/setup-1.png differ diff --git a/public/_static/docs/setup-2.png b/public/_static/docs/setup-2.png new file mode 100644 index 0000000..4d61f0a Binary files /dev/null and b/public/_static/docs/setup-2.png differ diff --git a/public/manifest.json b/public/manifest.json index 66a72fc..ad20795 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -3,7 +3,7 @@ "short_name": "WR.DO", "description": "Shorten links with analytics, manage emails and control subdomains—all on one platform.", "appid": "com.wr.do", - "versionName": "0.6.0", + "versionName": "0.6.1", "versionCode": "1", "start_url": "/", "orientation": "portrait", diff --git a/public/site.webmanifest b/public/site.webmanifest index 66a72fc..ad20795 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -3,7 +3,7 @@ "short_name": "WR.DO", "description": "Shorten links with analytics, manage emails and control subdomains—all on one platform.", "appid": "com.wr.do", - "versionName": "0.6.0", + "versionName": "0.6.1", "versionCode": "1", "start_url": "/", "orientation": "portrait", diff --git a/public/sw.js.map b/public/sw.js.map index 95b5bf0..0691226 100644 --- a/public/sw.js.map +++ b/public/sw.js.map @@ -1 +1 @@ -{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/04443f5fc75df19ba6a55a8a764fbf11/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/9b/3qmyp8zd2xvdspdrp149fyg00000gn/T/6217469e87d14bd5106dd3d5117a6cdd/sw.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-routing@6.6.0/node_modules/workbox-routing/registerRoute.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {NetworkOnly as workbox_strategies_NetworkOnly} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-strategies@6.6.0/node_modules/workbox-strategies/NetworkOnly.mjs';\nimport {clientsClaim as workbox_core_clientsClaim} from '/Users/songjunxi/Desktop/repos/wrdo-app/wr.do/node_modules/.pnpm/workbox-core@6.6.0/node_modules/workbox-core/clientsClaim.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\nimportScripts(\n \n);\n\n\n\n\n\n\n\nself.skipWaiting();\n\nworkbox_core_clientsClaim();\n\n\n\nworkbox_routing_registerRoute(\"/\", new workbox_strategies_NetworkFirst({ \"cacheName\":\"start-url\", plugins: [{ cacheWillUpdate: async ({ request, response, event, state }) => { if (response && response.type === 'opaqueredirect') { return new Response(response.body, { status: 200, statusText: 'OK', headers: response.headers }) } return response } }] }), 'GET');\nworkbox_routing_registerRoute(/.*/i, new workbox_strategies_NetworkOnly({ \"cacheName\":\"dev\", plugins: [] }), 'GET');\n\n\n\n\n"],"names":["importScripts","self","skipWaiting","workbox_core_clientsClaim","workbox_routing_registerRoute","workbox_strategies_NetworkFirst","plugins","cacheWillUpdate","request","response","event","state","type","Response","body","status","statusText","headers","workbox_strategies_NetworkOnly"],"mappings":"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"} \ No newline at end of file