added apikey model
This commit is contained in:
parent
9ad277c784
commit
cf7b18e012
|
@ -5,6 +5,7 @@ import {
|
||||||
faPalette,
|
faPalette,
|
||||||
faBoxArchive,
|
faBoxArchive,
|
||||||
faKey,
|
faKey,
|
||||||
|
faLock,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
@ -20,7 +21,7 @@ import {
|
||||||
} from "@fortawesome/free-brands-svg-icons";
|
} from "@fortawesome/free-brands-svg-icons";
|
||||||
|
|
||||||
export default function SettingsSidebar({ className }: { className?: string }) {
|
export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
const LINKWARDEN_VERSION = "v2.2.1";
|
const LINKWARDEN_VERSION = "v2.3.0";
|
||||||
|
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
|
|
||||||
|
@ -96,6 +97,23 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
<Link href="/settings/api">
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
active === `/settings/api` ? "bg-sky-500" : "hover:bg-slate-500"
|
||||||
|
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faKey}
|
||||||
|
className="w-6 h-6 text-sky-500 dark:text-sky-500"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p className="text-black dark:text-white truncate w-full pr-7">
|
||||||
|
API Keys
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
<Link href="/settings/password">
|
<Link href="/settings/password">
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
|
@ -105,7 +123,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
|
||||||
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
} duration-100 py-2 px-2 hover:bg-opacity-20 bg-opacity-20 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faKey}
|
icon={faLock}
|
||||||
className="w-6 h-6 text-sky-500 dark:text-sky-500"
|
className="w-6 h-6 text-sky-500 dark:text-sky-500"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ export default function SettingsLayout({ children }: Props) {
|
||||||
<SettingsSidebar />
|
<SettingsSidebar />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full flex flex-col min-h-screen p-5 lg:ml-64">
|
<div className="w-full min-h-screen p-5 lg:ml-64">
|
||||||
<div className="flex gap-3">
|
<div className="gap-2 inline-flex mr-3">
|
||||||
<div
|
<div
|
||||||
onClick={toggleSidebar}
|
onClick={toggleSidebar}
|
||||||
className="inline-flex lg:hidden gap-1 items-center select-none cursor-pointer p-2 text-gray-500 dark:text-gray-300 rounded-md duration-100 hover:bg-slate-200 dark:hover:bg-neutral-700"
|
className="inline-flex lg:hidden gap-1 items-center select-none cursor-pointer p-2 text-gray-500 dark:text-gray-300 rounded-md duration-100 hover:bg-slate-200 dark:hover:bg-neutral-700"
|
||||||
|
@ -60,18 +60,12 @@ export default function SettingsLayout({ children }: Props) {
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="/dashboard"
|
href="/dashboard"
|
||||||
className="inline-flex gap-1 items-center select-none cursor-pointer p-2 text-gray-500 dark:text-gray-300 rounded-md duration-100 hover:bg-slate-200 dark:hover:bg-neutral-700"
|
className="inline-flex w-fit gap-1 items-center select-none cursor-pointer p-2 text-gray-500 dark:text-gray-300 rounded-md duration-100 hover:bg-slate-200 dark:hover:bg-neutral-700"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faChevronLeft} className="w-5 h-5" />
|
<FontAwesomeIcon icon={faChevronLeft} className="w-5 h-5" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<p className="capitalize text-3xl font-thin">
|
|
||||||
{router.asPath.split("/").pop()} Settings
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
|
|
||||||
{sidebar ? (
|
{sidebar ? (
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
"@types/dompurify": "^3.0.4",
|
"@types/dompurify": "^3.0.4",
|
||||||
"@types/jsdom": "^21.1.3",
|
"@types/jsdom": "^21.1.3",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
|
"daisyui": "^4.4.2",
|
||||||
"postcss": "^8.4.26",
|
"postcss": "^8.4.26",
|
||||||
"prisma": "^5.1.0",
|
"prisma": "^5.1.0",
|
||||||
"tailwindcss": "^3.3.3"
|
"tailwindcss": "^3.3.3"
|
||||||
|
|
|
@ -151,6 +151,10 @@ export default function Account() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
|
<p className="capitalize text-3xl font-thin inline">Account Settings</p>
|
||||||
|
|
||||||
|
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
||||||
|
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-10">
|
||||||
<div className="grid sm:grid-cols-2 gap-3 auto-rows-auto">
|
<div className="grid sm:grid-cols-2 gap-3 auto-rows-auto">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import Checkbox from "@/components/Checkbox";
|
||||||
|
import SubmitButton from "@/components/SubmitButton";
|
||||||
|
import SettingsLayout from "@/layouts/SettingsLayout";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import useAccountStore from "@/store/account";
|
||||||
|
import { toast } from "react-hot-toast";
|
||||||
|
import { AccountSettings } from "@/types/global";
|
||||||
|
import TextInput from "@/components/TextInput";
|
||||||
|
|
||||||
|
export default function Api() {
|
||||||
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
|
const { account, updateAccount } = useAccountStore();
|
||||||
|
const [user, setUser] = useState<AccountSettings>(account);
|
||||||
|
|
||||||
|
const [archiveAsScreenshot, setArchiveAsScreenshot] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
const [archiveAsPDF, setArchiveAsPDF] = useState<boolean>(false);
|
||||||
|
const [archiveAsWaybackMachine, setArchiveAsWaybackMachine] =
|
||||||
|
useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setUser({
|
||||||
|
...account,
|
||||||
|
archiveAsScreenshot,
|
||||||
|
archiveAsPDF,
|
||||||
|
archiveAsWaybackMachine,
|
||||||
|
});
|
||||||
|
}, [account, archiveAsScreenshot, archiveAsPDF, archiveAsWaybackMachine]);
|
||||||
|
|
||||||
|
function objectIsEmpty(obj: object) {
|
||||||
|
return Object.keys(obj).length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!objectIsEmpty(account)) {
|
||||||
|
setArchiveAsScreenshot(account.archiveAsScreenshot);
|
||||||
|
setArchiveAsPDF(account.archiveAsPDF);
|
||||||
|
setArchiveAsWaybackMachine(account.archiveAsWaybackMachine);
|
||||||
|
}
|
||||||
|
}, [account]);
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
// setSubmitLoader(true);
|
||||||
|
// const load = toast.loading("Applying...");
|
||||||
|
// const response = await updateAccount({
|
||||||
|
// ...user,
|
||||||
|
// });
|
||||||
|
// toast.dismiss(load);
|
||||||
|
// if (response.ok) {
|
||||||
|
// toast.success("Settings Applied!");
|
||||||
|
// } else toast.error(response.data as string);
|
||||||
|
// setSubmitLoader(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsLayout>
|
||||||
|
<p className="capitalize text-3xl font-thin inline">API Keys</p>
|
||||||
|
|
||||||
|
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<div className="badge bg-yellow-300 text-black">
|
||||||
|
Status: Under Development
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>This page will be for creating and managing your API keys.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For now, you can <i>temporarily</i> use your{" "}
|
||||||
|
<code className="text-xs whitespace-nowrap bg-gray-500/40 rounded-md px-2 py-1">
|
||||||
|
next-auth.session-token
|
||||||
|
</code>{" "}
|
||||||
|
in your browser cookies as the API key for your integrations.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</SettingsLayout>
|
||||||
|
);
|
||||||
|
}
|
|
@ -68,6 +68,10 @@ export default function Appearance() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
|
<p className="capitalize text-3xl font-thin inline">Appearance</p>
|
||||||
|
|
||||||
|
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
||||||
|
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-10">
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-3">Select Theme</p>
|
<p className="mb-3">Select Theme</p>
|
||||||
|
|
|
@ -57,6 +57,10 @@ export default function Archive() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
|
<p className="capitalize text-3xl font-thin inline">Archive Settings</p>
|
||||||
|
|
||||||
|
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
||||||
|
|
||||||
<p>Formats to Archive webpages:</p>
|
<p>Formats to Archive webpages:</p>
|
||||||
<div className="p-3">
|
<div className="p-3">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
|
|
@ -11,9 +11,13 @@ export default function Billing() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
|
<p className="capitalize text-3xl font-thin inline">Billing Settings</p>
|
||||||
|
|
||||||
|
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
||||||
|
|
||||||
<div className="w-full mx-auto flex flex-col gap-3 justify-between">
|
<div className="w-full mx-auto flex flex-col gap-3 justify-between">
|
||||||
<p className="text-md text-black dark:text-white">
|
<p className="text-md text-black dark:text-white">
|
||||||
To manage/cancel your subsciption, visit the{" "}
|
To manage/cancel your subscription, visit the{" "}
|
||||||
<a
|
<a
|
||||||
href={process.env.NEXT_PUBLIC_STRIPE_BILLING_PORTAL_URL}
|
href={process.env.NEXT_PUBLIC_STRIPE_BILLING_PORTAL_URL}
|
||||||
className="underline"
|
className="underline"
|
||||||
|
|
|
@ -45,6 +45,10 @@ export default function Password() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsLayout>
|
<SettingsLayout>
|
||||||
|
<p className="capitalize text-3xl font-thin inline">Change Password</p>
|
||||||
|
|
||||||
|
<hr className="my-3 border-1 border-sky-100 dark:border-neutral-700" />
|
||||||
|
|
||||||
<p className="mb-3">
|
<p className="mb-3">
|
||||||
To change your password, please fill out the following. Your password
|
To change your password, please fill out the following. Your password
|
||||||
should be at least 8 characters.
|
should be at least 8 characters.
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ApiKeys" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"userId" INTEGER NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"expires" TIMESTAMP(3) NOT NULL,
|
||||||
|
"lastUsedAt" TIMESTAMP(3),
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "ApiKeys_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ApiKeys_token_key" ON "ApiKeys"("token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ApiKeys_token_userId_key" ON "ApiKeys"("token", "userId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ApiKeys" ADD CONSTRAINT "ApiKeys_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the `ApiKeys` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "ApiKeys" DROP CONSTRAINT "ApiKeys_userId_fkey";
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "ApiKeys";
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ApiKey" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"userId" INTEGER NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"expires" TIMESTAMP(3) NOT NULL,
|
||||||
|
"lastUsedAt" TIMESTAMP(3),
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "ApiKey_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ApiKey_token_key" ON "ApiKey"("token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ApiKey_token_userId_key" ON "ApiKey"("token", "userId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -20,7 +20,6 @@ model Account {
|
||||||
scope String?
|
scope String?
|
||||||
id_token String?
|
id_token String?
|
||||||
session_state String?
|
session_state String?
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
@@unique([provider, providerAccountId])
|
@@unique([provider, providerAccountId])
|
||||||
|
@ -29,45 +28,34 @@ model Account {
|
||||||
model User {
|
model User {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String
|
name String
|
||||||
|
|
||||||
username String? @unique
|
username String? @unique
|
||||||
|
|
||||||
email String? @unique
|
email String? @unique
|
||||||
emailVerified DateTime?
|
emailVerified DateTime?
|
||||||
image String?
|
image String?
|
||||||
|
|
||||||
accounts Account[]
|
accounts Account[]
|
||||||
|
|
||||||
password String?
|
password String?
|
||||||
|
|
||||||
collections Collection[]
|
collections Collection[]
|
||||||
tags Tag[]
|
tags Tag[]
|
||||||
pinnedLinks Link[]
|
pinnedLinks Link[]
|
||||||
collectionsJoined UsersAndCollections[]
|
collectionsJoined UsersAndCollections[]
|
||||||
whitelistedUsers WhitelistedUser[]
|
whitelistedUsers WhitelistedUser[]
|
||||||
|
apiKeys ApiKey[]
|
||||||
subscriptions Subscription?
|
subscriptions Subscription?
|
||||||
|
|
||||||
archiveAsScreenshot Boolean @default(true)
|
archiveAsScreenshot Boolean @default(true)
|
||||||
archiveAsPDF Boolean @default(true)
|
archiveAsPDF Boolean @default(true)
|
||||||
archiveAsWaybackMachine Boolean @default(false)
|
archiveAsWaybackMachine Boolean @default(false)
|
||||||
|
|
||||||
isPrivate Boolean @default(false)
|
isPrivate Boolean @default(false)
|
||||||
|
|
||||||
displayLinkIcons Boolean @default(true)
|
displayLinkIcons Boolean @default(true)
|
||||||
blurredFavicons Boolean @default(true)
|
blurredFavicons Boolean @default(true)
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
}
|
}
|
||||||
|
|
||||||
model WhitelistedUser {
|
model WhitelistedUser {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
|
|
||||||
username String @default("")
|
username String @default("")
|
||||||
User User? @relation(fields: [userId], references: [id])
|
User User? @relation(fields: [userId], references: [id])
|
||||||
userId Int?
|
userId Int?
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
}
|
}
|
||||||
|
@ -76,7 +64,6 @@ model VerificationToken {
|
||||||
identifier String
|
identifier String
|
||||||
token String @unique
|
token String @unique
|
||||||
expires DateTime
|
expires DateTime
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
|
|
||||||
|
@ -89,13 +76,12 @@ model Collection {
|
||||||
description String @default("")
|
description String @default("")
|
||||||
color String @default("#0ea5e9")
|
color String @default("#0ea5e9")
|
||||||
isPublic Boolean @default(false)
|
isPublic Boolean @default(false)
|
||||||
|
owner User @relation(fields: [ownerId], references: [id])
|
||||||
owner User @relation(fields: [ownerId], references: [id])
|
ownerId Int
|
||||||
ownerId Int
|
members UsersAndCollections[]
|
||||||
members UsersAndCollections[]
|
links Link[]
|
||||||
links Link[]
|
createdAt DateTime @default(now())
|
||||||
createdAt DateTime @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
|
||||||
|
|
||||||
@@unique([name, ownerId])
|
@@unique([name, ownerId])
|
||||||
}
|
}
|
||||||
|
@ -103,16 +89,13 @@ model Collection {
|
||||||
model UsersAndCollections {
|
model UsersAndCollections {
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
userId Int
|
userId Int
|
||||||
|
|
||||||
collection Collection @relation(fields: [collectionId], references: [id])
|
collection Collection @relation(fields: [collectionId], references: [id])
|
||||||
collectionId Int
|
collectionId Int
|
||||||
|
|
||||||
canCreate Boolean
|
canCreate Boolean
|
||||||
canUpdate Boolean
|
canUpdate Boolean
|
||||||
canDelete Boolean
|
canDelete Boolean
|
||||||
|
createdAt DateTime @default(now())
|
||||||
createdAt DateTime @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
|
||||||
|
|
||||||
@@id([userId, collectionId])
|
@@id([userId, collectionId])
|
||||||
}
|
}
|
||||||
|
@ -122,32 +105,25 @@ model Link {
|
||||||
name String
|
name String
|
||||||
url String
|
url String
|
||||||
description String @default("")
|
description String @default("")
|
||||||
|
|
||||||
pinnedBy User[]
|
pinnedBy User[]
|
||||||
|
|
||||||
collection Collection @relation(fields: [collectionId], references: [id])
|
collection Collection @relation(fields: [collectionId], references: [id])
|
||||||
collectionId Int
|
collectionId Int
|
||||||
tags Tag[]
|
tags Tag[]
|
||||||
|
|
||||||
textContent String?
|
textContent String?
|
||||||
|
|
||||||
screenshotPath String?
|
screenshotPath String?
|
||||||
pdfPath String?
|
pdfPath String?
|
||||||
readabilityPath String?
|
readabilityPath String?
|
||||||
|
|
||||||
lastPreserved DateTime?
|
lastPreserved DateTime?
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
}
|
}
|
||||||
|
|
||||||
model Tag {
|
model Tag {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String
|
name String
|
||||||
links Link[]
|
links Link[]
|
||||||
owner User @relation(fields: [ownerId], references: [id])
|
owner User @relation(fields: [ownerId], references: [id])
|
||||||
ownerId Int
|
ownerId Int
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
|
|
||||||
|
@ -160,10 +136,22 @@ model Subscription {
|
||||||
stripeSubscriptionId String @unique
|
stripeSubscriptionId String @unique
|
||||||
currentPeriodStart DateTime
|
currentPeriodStart DateTime
|
||||||
currentPeriodEnd DateTime
|
currentPeriodEnd DateTime
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
userId Int @unique
|
userId Int @unique
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt @default(now())
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model ApiKey {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
name String
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
userId Int
|
||||||
|
token String @unique
|
||||||
|
expires DateTime
|
||||||
|
lastUsedAt DateTime?
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt @default(now())
|
||||||
|
|
||||||
|
@@unique([token, userId])
|
||||||
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ body {
|
||||||
/* Theme */
|
/* Theme */
|
||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply dark:bg-neutral-900 bg-white dark:text-white;
|
@apply dark:bg-neutral-900 bg-white text-black dark:text-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
darkMode: "class",
|
darkMode: "class",
|
||||||
|
// daisyui: {
|
||||||
|
// themes: ["light", "dark"],
|
||||||
|
// },
|
||||||
content: [
|
content: [
|
||||||
"./app/**/*.{js,ts,jsx,tsx}",
|
"./app/**/*.{js,ts,jsx,tsx}",
|
||||||
"./pages/**/*.{js,ts,jsx,tsx}",
|
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||||
|
@ -10,5 +13,5 @@ module.exports = {
|
||||||
// For the "layouts" directory
|
// For the "layouts" directory
|
||||||
"./layouts/**/*.{js,ts,jsx,tsx}",
|
"./layouts/**/*.{js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
plugins: [],
|
plugins: [require("daisyui")],
|
||||||
};
|
};
|
||||||
|
|
32
yarn.lock
32
yarn.lock
|
@ -2129,6 +2129,14 @@ crypto-js@^4.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
|
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
|
||||||
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
|
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
|
||||||
|
|
||||||
|
css-selector-tokenizer@^0.8:
|
||||||
|
version "0.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz#88267ef6238e64f2215ea2764b3e2cf498b845dd"
|
||||||
|
integrity sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==
|
||||||
|
dependencies:
|
||||||
|
cssesc "^3.0.0"
|
||||||
|
fastparse "^1.1.2"
|
||||||
|
|
||||||
cssesc@^3.0.0:
|
cssesc@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||||
|
@ -2151,6 +2159,11 @@ csstype@^3.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||||
|
|
||||||
|
culori@^3:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/culori/-/culori-3.2.0.tgz#df6561503f0cc20e8e1c029f086466666c0ac62f"
|
||||||
|
integrity sha512-HIEbTSP7vs1mPq/2P9In6QyFE0Tkpevh0k9a+FkjhD+cwsYm9WRSbn4uMdW9O0yXlNYC3ppxL3gWWPOcvEl57w==
|
||||||
|
|
||||||
cwise-compiler@^1.1.2:
|
cwise-compiler@^1.1.2:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5"
|
resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5"
|
||||||
|
@ -2158,6 +2171,16 @@ cwise-compiler@^1.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
uniq "^1.0.0"
|
uniq "^1.0.0"
|
||||||
|
|
||||||
|
daisyui@^4.4.2:
|
||||||
|
version "4.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/daisyui/-/daisyui-4.4.2.tgz#669ee310be42894abe36d493635000d010fa4023"
|
||||||
|
integrity sha512-Ecg5loskj9dkaAnTSK5Xn5jb24TqDlQIg/NJ025jCkw2S/zw12btjvLgY2Sv5Ws1DFVoVBRs3XYXyojZG7zVnw==
|
||||||
|
dependencies:
|
||||||
|
css-selector-tokenizer "^0.8"
|
||||||
|
culori "^3"
|
||||||
|
picocolors "^1"
|
||||||
|
postcss-js "^4"
|
||||||
|
|
||||||
damerau-levenshtein@^1.0.8:
|
damerau-levenshtein@^1.0.8:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
||||||
|
@ -2726,6 +2749,11 @@ fast-xml-parser@4.2.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
strnum "^1.0.5"
|
strnum "^1.0.5"
|
||||||
|
|
||||||
|
fastparse@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
|
||||||
|
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
|
||||||
|
|
||||||
fastq@^1.6.0:
|
fastq@^1.6.0:
|
||||||
version "1.15.0"
|
version "1.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
|
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
|
||||||
|
@ -4113,7 +4141,7 @@ performance-now@^2.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||||
integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
|
integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
|
||||||
|
|
||||||
picocolors@^1.0.0:
|
picocolors@^1, picocolors@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||||
|
@ -4159,7 +4187,7 @@ postcss-import@^15.1.0:
|
||||||
read-cache "^1.0.0"
|
read-cache "^1.0.0"
|
||||||
resolve "^1.1.7"
|
resolve "^1.1.7"
|
||||||
|
|
||||||
postcss-js@^4.0.1:
|
postcss-js@^4, postcss-js@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
|
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
|
||||||
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
|
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
|
||||||
|
|
Ŝarĝante…
Reference in New Issue