mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-29 03:53:14 +03:00
Adds login for stats
This commit is contained in:
parent
058d226be8
commit
cf9b85466e
@ -25,13 +25,24 @@ app waspAi {
|
||||
("@visx/scale", "3.2.0"),
|
||||
("@visx/responsive", "3.0.0"),
|
||||
("@visx/gradient", "3.0.0"),
|
||||
("@visx/axis", "3.2.0")
|
||||
("@visx/axis", "3.2.0"),
|
||||
],
|
||||
client: {
|
||||
rootComponent: import { RootComponent } from "@client/RootComponent.jsx",
|
||||
},
|
||||
db: {
|
||||
system: PostgreSQL
|
||||
},
|
||||
auth: {
|
||||
userEntity: User,
|
||||
externalAuthEntity: SocialLogin,
|
||||
methods: {
|
||||
google: {
|
||||
configFn: import { getGoogleAuthConfig } from "@server/auth.js",
|
||||
getUserFieldsFn: import { getUserFields } from "@server/auth.js",
|
||||
}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +58,13 @@ page ResultPage {
|
||||
|
||||
route StatsRoute { path: "/stats", to: StatsPage }
|
||||
page StatsPage {
|
||||
component: import { Stats } from "@client/pages/StatsPage.jsx"
|
||||
component: import { Stats } from "@client/pages/StatsPage.jsx",
|
||||
authRequired: true
|
||||
}
|
||||
|
||||
route LoginRoute { path: "/login", to: LoginPage }
|
||||
page LoginPage {
|
||||
component: import { LoginPage } from "@client/pages/LoginPage.jsx",
|
||||
}
|
||||
|
||||
action startGeneratingNewApp {
|
||||
@ -73,6 +90,23 @@ query getStats {
|
||||
]
|
||||
}
|
||||
|
||||
entity User {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
|
||||
email String @unique
|
||||
externalAuthAssociations SocialLogin[]
|
||||
psl=}
|
||||
|
||||
entity SocialLogin {=psl
|
||||
id String @id @default(uuid())
|
||||
|
||||
provider String
|
||||
providerId String
|
||||
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
psl=}
|
||||
|
||||
entity Project {=psl
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
|
19
wasp-ai/migrations/20230703150042_add_user/migration.sql
Normal file
19
wasp-ai/migrations/20230703150042_add_user/migration.sql
Normal file
@ -0,0 +1,19 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" SERIAL NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SocialLogin" (
|
||||
"id" TEXT NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"providerId" TEXT NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "SocialLogin_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SocialLogin" ADD CONSTRAINT "SocialLogin_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[email]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `email` to the `User` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "email" TEXT NOT NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
@ -28,7 +28,6 @@ function generateLast24HoursData(projects) {
|
||||
buckets[reverseBucketIndex].count++;
|
||||
}
|
||||
});
|
||||
console.log(buckets);
|
||||
return buckets;
|
||||
}
|
||||
|
||||
|
9
wasp-ai/src/client/pages/LoginPage.jsx
Normal file
9
wasp-ai/src/client/pages/LoginPage.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
import { LoginForm } from "@wasp/auth/forms/Login";
|
||||
|
||||
export function LoginPage() {
|
||||
return (
|
||||
<div className="big-box">
|
||||
<LoginForm />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -8,6 +8,7 @@ import { StatusPill } from "../components/StatusPill";
|
||||
import { BarChart } from "../components/BarChart";
|
||||
import ParentSize from "@visx/responsive/lib/components/ParentSize";
|
||||
import { poolOfExampleIdeas } from "../examples";
|
||||
import logout from "@wasp/auth/logout";
|
||||
|
||||
export function Stats() {
|
||||
const [filterOutExampleApps, setFilterOutExampleApps] = useState(true);
|
||||
@ -64,13 +65,24 @@ export function Stats() {
|
||||
|
||||
return (
|
||||
<div className="big-box">
|
||||
<h1 className="text-3xl font-semibold text-slate-800 mb-4">Stats</h1>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h1 className="text-3xl font-semibold text-slate-800">Stats</h1>
|
||||
<div>
|
||||
<button className="button sm" onClick={logout}>Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading && <p>Loading...</p>}
|
||||
|
||||
{error && <p>Error: {error.message}</p>}
|
||||
|
||||
{stats && (
|
||||
{stats && filteredStats.length === 0 && (
|
||||
<p className="text-sm text-slate-500">
|
||||
No projects created yet.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{stats && filteredStats.length > 0 && (
|
||||
<>
|
||||
<p className="text-sm text-slate-500 mb-2">
|
||||
Number of projects created in the last 24 hours:{" "}
|
||||
|
15
wasp-ai/src/server/auth.ts
Normal file
15
wasp-ai/src/server/auth.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { GetUserFieldsFn } from "@wasp/types";
|
||||
|
||||
export const getUserFields: GetUserFieldsFn = async (_context, args) => {
|
||||
return {
|
||||
email: args.profile.emails[0].value,
|
||||
};
|
||||
};
|
||||
|
||||
export const getGoogleAuthConfig = () => {
|
||||
return {
|
||||
clientID: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
scope: ["profile", "email"],
|
||||
};
|
||||
};
|
@ -198,6 +198,11 @@ export const getAppGenerationResult = (async (args, context) => {
|
||||
}>;
|
||||
|
||||
export const getStats = (async (args, context) => {
|
||||
const emailsWhitelist = process.env.ADMIN_EMAILS_WHITELIST?.split(",") || [];
|
||||
if (!context.user || !emailsWhitelist.includes(context.user.email)) {
|
||||
throw new HttpError(401, "Only admins can access stats.");
|
||||
}
|
||||
|
||||
const { Project } = context.entities;
|
||||
const projects = await Project.findMany({
|
||||
orderBy: {
|
||||
|
Loading…
Reference in New Issue
Block a user