auth mw stuff

This commit is contained in:
Nathan Rashleigh committed 2025-05-01 21:25:06 +10:00
1 parent d868baade5
commit a79c11496b
8 files changed
+166 -31

No files matched your search

+4 -10
View File
@@ -3,11 +3,9 @@ import { getCookies, setCookie } from "$std/http/cookie.ts"
import { createPg } from "api/pg.ts" import { createPg } from "api/pg.ts"
// Define public paths that don't require authentication // Define public paths that don't require authentication
const PUBLIC_PATHS = [ const PROTECTED = [
"/", "/home",
"/api/auth/login", "/api/auth",
"/api/auth/register",
"/api/auth/logout",
] ]
// Sessions storage shared between routes // Sessions storage shared between routes
@@ -18,11 +16,8 @@ export async function authMiddleware(req: Request, ctx: FreshContext): Promise<R
const url = new URL(req.url) const url = new URL(req.url)
const path = url.pathname const path = url.pathname
console.log("authing...")
// Allow public paths without authentication // Allow public paths without authentication
if (PUBLIC_PATHS.includes(path)) { if (!PROTECTED.includes(path)) {
console.log("noauth")
return await ctx.next() return await ctx.next()
} }
@@ -66,7 +61,6 @@ export async function authMiddleware(req: Request, ctx: FreshContext): Promise<R
ctx.state.user = user ctx.state.user = user
ctx.state.pg = pg ctx.state.pg = pg
console.log("woas")
return await ctx.next() return await ctx.next()
} }
+153
View File
@@ -0,0 +1,153 @@
import type Log from 'bunyan';
import type { PrismaClient, Want, User, Listing, Offer, } from '@prisma/client';
import assert from 'assert/strict';
import groupBy from 'lodash/groupBy';
import sortBy from 'lodash/sortBy';
import flatMap from 'lodash/flatMap';
import { Context } from 'koa';
import { logAxiosError, wantDetails } from './utils';
import { Pg } from './pg';
export enum Status {
Complete = 'Complete',
Confirmed = 'Confirmed',
Accepted = 'Accepted',
Pending = 'Pending',
Declined = 'Declined',
}
function sortOffers(o) {
return Object.values(Status).indexOf(o.status);
}
export default function createOffers(log: Log, pg: Pg) {
async function generate() {
const listings = flatMap(await pg.interestingListings());
log.debug('generateOffers', { listings: listings.length });
const shipping = 7.5; // yolt
const offers = listings.map(l => ({
userId: l.want.user.id,
listingId: l.id,
wantId: l.want.id,
status: Status.Pending,
condition: l.data.condition,
item: l.data.price.value,
shipping,
total: l.data.price.value + shipping,
}))
// we must sort the offers by price,
// sometimes a seller has multiples of a want
// to deal with this we just ignore duplicates on insert
// and ensure the cheapest one goes in first
const sorted = sortBy(offers, ['item']);
// TODO probably need to take one of each condition of record from a store
// eg. they have a VG+ and a M we should make offers for each
log.trace('generated offers', sorted);
const inserts = await pg.offersUpdate(sorted);
return inserts;
}
async function accept(ctx: Context) {
const { id } = ctx.request.body;
ctx.assert(id, 401, 'no id supplied');
// check the user actually has this offer
const offer = await pg.userOfferFind(ctx.state.user, id);
return pg.offerStatusSet([offer.id], Status.Accepted);
}
async function statusSet(user: User, ids: UUID[], status: Status) {
log.info({ status, ids }, 'setting offer status');
// const offer = await pg.offerFindId(ids);
const update = await pg.offerStatusSet(ids, status);
// forget about this for now
// if (status === Status.Complete) {
// log.info({ id, status }, 'completed offer, removing want...');
// await pg.wantRm(offer.wantId);
// }
return update;
}
// converts offers into groups based on seller
// includes some bits of info about shipping etc
async function acpOffers() {
const offers = await pg.offersAdmin();
const grouped = groupBy(offers, o => o.listing.data.seller.id);
const sellerOffers = sortBy(Object.values(grouped).map(offers => {
const shipping = offers[0]?.listing.data.seller.shipping;
const bundle = {
username: offers[0]?.listing.data.seller.username,
seller: offers[0]?.listing.data.seller.id,
shipsFrom: offers[0]?.listing.data.ships_from,
shipping,
offers: sortBy(offers, sortOffers),
mentionsAustralia: shipping.toLowerCase().includes('australia'),
mentionsWorldwide: shipping.toLowerCase().includes('world'),
}
return bundle;
}), bundle => -bundle.offers.length);
return sellerOffers;
}
// also groups offers by seller for users
// but mostly just munges the structure so the details
// are easily available
async function userOffers(user: User) {
const offers = await pg.userOffers(user);
const groups = Object.values(groupBy(offers, (o) => o.wantId))
.map(g => {
// the offer status is just the most advanced status
// based on sort
const offers = sortBy(g, sortOffers);
const status = offers[0].status;
// now actually sort them by price
offers.sort((a, b) => a.total - b.total);
const details = offers[0].want.data;
return {
details,
offers,
status,
};
});
return groups;
}
async function samples() {
const user = await pg.userFindEmail('ntr@mnml.gg');
const offerGroups = await userOffers(user);
const i = Math.floor(Math.random() * offerGroups.length / 2);
return offerGroups[i];
}
return {
generate,
accept,
statusSet,
acpOffers,
userOffers,
samples,
};
}
export type Offers = ReturnType<typeof createOffers>;
+2
View File
@@ -32,6 +32,8 @@ function Main({ wants, offers }) {
); );
} }
console.log(offers)
return ( return (
<main> <main>
<nav> <nav>
-6
View File
@@ -1,8 +1,6 @@
import { defineConfig } from "$fresh/server.ts"; import { defineConfig } from "$fresh/server.ts";
// import twind from "$fresh/plugins/twindv1.ts"; // import twind from "$fresh/plugins/twindv1.ts";
// import twindConfig from "./twind.config.ts"; // import twindConfig from "./twind.config.ts";
import { authMiddleware } from "api/auth.middleware.ts";
import { errorMiddleware } from "api/error.middleware.ts";
import lessPlugin from "./less.plugin.ts"; import lessPlugin from "./less.plugin.ts";
export default defineConfig({ export default defineConfig({
@@ -10,8 +8,4 @@ export default defineConfig({
// twind(twindConfig), // twind(twindConfig),
lessPlugin() lessPlugin()
], ],
middleware: {
auth: authMiddleware,
error: errorMiddleware,
}
}); });
+2 -2
View File
@@ -4,6 +4,7 @@
import * as $_404 from './routes/_404.tsx' import * as $_404 from './routes/_404.tsx'
import * as $_app from './routes/_app.tsx' import * as $_app from './routes/_app.tsx'
import * as $_middleware from './routes/_middleware.ts'
import * as $api_auth_login from './routes/api/auth/login.ts' import * as $api_auth_login from './routes/api/auth/login.ts'
import * as $api_auth_logout from './routes/api/auth/logout.ts' import * as $api_auth_logout from './routes/api/auth/logout.ts'
import * as $api_auth_register from './routes/api/auth/register.ts' import * as $api_auth_register from './routes/api/auth/register.ts'
@@ -11,7 +12,6 @@ import * as $api_auth_status from './routes/api/auth/status.ts'
import * as $api_offers from './routes/api/offers.ts' import * as $api_offers from './routes/api/offers.ts'
import * as $api_wants from './routes/api/wants.ts' import * as $api_wants from './routes/api/wants.ts'
import * as $home from './routes/home.tsx' import * as $home from './routes/home.tsx'
import * as $index from './routes/index.tsx'
import * as $login from './routes/login.tsx' import * as $login from './routes/login.tsx'
import * as $register from './routes/register.tsx' import * as $register from './routes/register.tsx'
@@ -21,6 +21,7 @@ const manifest = {
routes: { routes: {
'./routes/_404.tsx': $_404, './routes/_404.tsx': $_404,
'./routes/_app.tsx': $_app, './routes/_app.tsx': $_app,
'./routes/_middleware.ts': $_middleware,
'./routes/api/auth/login.ts': $api_auth_login, './routes/api/auth/login.ts': $api_auth_login,
'./routes/api/auth/logout.ts': $api_auth_logout, './routes/api/auth/logout.ts': $api_auth_logout,
'./routes/api/auth/register.ts': $api_auth_register, './routes/api/auth/register.ts': $api_auth_register,
@@ -28,7 +29,6 @@ const manifest = {
'./routes/api/offers.ts': $api_offers, './routes/api/offers.ts': $api_offers,
'./routes/api/wants.ts': $api_wants, './routes/api/wants.ts': $api_wants,
'./routes/home.tsx': $home, './routes/home.tsx': $home,
'./routes/index.tsx': $index,
'./routes/login.tsx': $login, './routes/login.tsx': $login,
'./routes/register.tsx': $register, './routes/register.tsx': $register,
}, },
+4 -10
View File
@@ -1,18 +1,12 @@
import { FreshContext } from "$fresh/server.ts"; import { FreshContext } from "$fresh/server.ts";
import { Pg } from 'api/pg.ts' import { Pg } from 'api/pg.ts'
import { User } from 'prisma/generated/index.d.ts' import { User } from 'prisma/generated/index.ts'
import { authMiddleware } from 'api/auth.middleware.ts'
import { errorMiddleware } from 'api/error.middleware.ts'
interface State { interface State {
pg: Pg; pg: Pg;
user: User user: User
} }
export async function handler( export const handler = [errorMiddleware, authMiddleware]
req: Request,
ctx: FreshContext<State>,
) {
ctx.state.data = "myData";
const resp = await ctx.next();
resp.headers.set("server", "fresh server");
return resp;
}
-2
View File
@@ -1,10 +1,8 @@
import { Handlers } from "$fresh/server.ts" import { Handlers } from "$fresh/server.ts"
import { createPg } from "../../api/pg.ts"
export const handler: Handlers = { export const handler: Handlers = {
async GET(_req, ctx) { async GET(_req, ctx) {
const user = ctx.state.user const user = ctx.state.user
const pg = createPg(console)
const offers = await pg.userOffers(user) const offers = await pg.userOffers(user)
return new Response(JSON.stringify(offers), { return new Response(JSON.stringify(offers), {
+1 -1
View File
@@ -1,7 +1,7 @@
import { Handlers, PageProps } from "$fresh/server.ts"; import { Handlers, PageProps } from "$fresh/server.ts";
import { createPg, Pg } from "../api/pg.ts"; import { createPg, Pg } from "../api/pg.ts";
import Main from "../components/main.tsx"; import Main from "../components/main.tsx";
import { User } from 'prisma/generated/index.d.ts' import { User } from 'prisma/generated/index.ts'
export const handler: Handlers = { export const handler: Handlers = {
async GET(req, ctx) { async GET(req, ctx) {