commit working state

This commit is contained in:
2024-04-15 11:38:40 +02:00
parent 89f3f86c54
commit 508258bf0f
33 changed files with 1130 additions and 221 deletions

View File

@@ -1,8 +1,9 @@
import { MUser } from "@/model/sequelize/User";
import { MAuth } from "@/model/sequelize/Auth";
// import { MUser } from "@/model/sequelize/User";
// import { MAuth } from "@/model/sequelize/Auth";
import { validatePassword } from "@/util/Auth";
import { APIError } from "@/api/error";
import { User, Auth } from "@/model/sequelize/NewModels";
export function parseBasicAuth(authb64:string):UserAuth
{
@@ -22,7 +23,7 @@ export type UserAuth = {
export async function getAssociatedUser(auth:UserAuth)
{
const username = auth.username;
let foundUser = await MUser.findOne({ where: {username: auth.username} });
let foundUser = await User.findOne({ attributes: {include: ['password']}, where: {username: auth.username} });
if (!foundUser)
throw new APIError({status: 401, responseText:"Unauthorized: Invalid Username"});

View File

@@ -0,0 +1,40 @@
'use client'
import { authenticate } from '@/app/lib/actions'
import { useFormState, useFormStatus } from "react-dom";
import { cookies } from 'next/headers';
export default function Page(state:any) {
const [loginResult, dispatch] = useFormState(authenticate, undefined)
console.log(dispatch);
console.log(state);
// if(loginResult?.cookie && loginResult.cookie){
// cookies().set('auth',loginResult.cookie['auth'])
// }
return (
<main className="h-screen w-screen flex flex-col p-10 bg-background-500 box-border m-0">
<form action={dispatch}>
<input type="text" name="username" placeholder="Username" required />
<input type="password" name="password" placeholder="Password" required />
<div>{loginResult?.errorMessage && <p>{loginResult?.errorMessage}</p>}</div>
<LoginButton />
</form>
<div>
<p>{""+loginResult?.cookie}</p>
</div>
</main>
)
}
function LoginButton() {
const { pending } = useFormStatus()
return (
<button aria-disabled={pending} className="mr-auto bg-secondary-200 outline outline-2 border-5 p-3 mt-3 rounded-lg outline-secondary-500 shadow-primary" type="submit">
Login
</button>
)
}

View File

@@ -1,58 +1,13 @@
'use client'
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import AdminPanel from "@/components/admin/adminPanel";
import AuthHandler from "@/components/admin/authHandler";
import { cookies } from "next/headers";
export default function Page(){
return <div>
<Navbar bg="light" expand="lg">
<Container>
<Navbar.Brand href="#home">React-Bootstrap</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#link">Link</Nav.Link>
<NavDropdown title="Dropdown" id="basic-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">
Another action
</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action/3.4">
Separated link
</NavDropdown.Item>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<Container style={{width:"800px"}}>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Container>
</div>
export default async function Page(){
return (
<main className="h-screen w-screen flex flex-col p-10 bg-background-500 box-border m-0">
<AuthHandler params={null}><AdminPanel><p>this is only shown on the admin panel</p></AdminPanel></AuthHandler>
<section>{JSON.stringify(cookies().getAll())}</section>
</main>
);
}

View File

@@ -14,7 +14,7 @@ export async function GET(request:Request, { params }: {params:{slug: string}}){
// @ts-ignore
cookies().set('name', 'lee');
return Response.json({
"a": "kanker",
"a": "lorem",
"b": params
});
}

View File

@@ -41,7 +41,7 @@ async function tryAuth(request:Request){
return new Response("error",{status:500});
const kanker = await authentication.getUser();
const authUser = await authentication.getUser();
// @ts-ignore
cookies().set('auth', JSON.stringify(authentication));
@@ -51,7 +51,7 @@ async function tryAuth(request:Request){
{
credentials: userAuth,
auth: authentication,
kanker: kanker,
user: authUser,
foundAuth: foundAuth
}),
{

View File

@@ -0,0 +1,64 @@
'use server'
import { Model } from "sequelize";
import { cookies } from "next/headers";
import { Auth, Post, User } from "@/model/sequelize/NewModels";
import { APIError} from "@/api/error"
import { UserAuth, parseBasicAuth, getAssociatedUser } from "@/api/user"
async function tryAuth(request:Request){
// await User.sync();
await Auth.sync();
const koek = cookies().get('auth');
if(!koek){
return new Response("unauthorized",{status:403});
}
console.log(koek);
const auth = JSON.parse(koek.value);
const authentication = await Auth.findOne( { include: 'user', where: {token:auth.token} })
if(!authentication)
return new Response("unauthorized: invalid token",{status:403});
const authUser = await authentication.getUser();
// @ts-ignore
cookies().set('auth', JSON.stringify(authentication));
return new Response(
JSON.stringify(
{
auth: authentication,
}),
{
status: 200,
headers:{
"Content-Type": "text/JSON"
}
}
);
}
export async function POST(request:Request){
try{
return await tryAuth(request);
}
catch(e){
if (e instanceof APIError){
return new Response(e.info.responseText,{status:e.info.status});
}
else{
throw e;
}
}
}

View File

@@ -1,6 +1,6 @@
'use server'
import { User, Auth, Post } from "@/model/sequelize/NewModels"
import { User, Auth, Post, UserPerms } from "@/model/sequelize/NewModels"
import { APIError } from "@/api/error";
import { UserAuth } from "@/api/user";
import { hashPassword } from "@/util/Auth";
@@ -24,7 +24,16 @@ async function tryRegister(request:Request){
const hash = await hashPassword(requestBody.password);
const user = await User.create({
username: requestBody.username,
password: hash
password: hash,
perms:{
isAdmin: false
}
},
{
include: [{
association: 'perms'
}]
})
return new Response(
@@ -58,7 +67,19 @@ export async function POST(request:Request){
async function tryGetUsers(request:Request){
const users = await User.findAll({include: "authtokens"});
const defaultScope:any = User.scope('defaultScope');
const mergedInclude = defaultScope.include ? [defaultScope.include] : [];
mergedInclude.push({ association: 'authtokens' });
// const mergedInclude = [...defaultScope.include, { association: 'authtokens' }];
const users = await User.findAll(
{
attributes: defaultScope.attributes,
include: mergedInclude,
}
);
return new Response(

View File

@@ -5,7 +5,7 @@ import Sidebar from "@/components/sidebar";
import Article from "@/components/news/article";
import ArticlePreview from "@/components/news/article-preview"
import ReactDOM from "react";
import "public/global.css"
import "/public/global.css"
import "@/app/index.css"
import { Post, User } from "@/model/sequelize/NewModels";
import { Attributes } from "sequelize";
@@ -17,7 +17,7 @@ type DeepPartial<T> = T extends object ? {
async function getData(slug:string):Promise<DeepPartial<Post>> {
// Get all posts from the API
const res = await fetch(`http://localhost:3000/api2/post/${slug}`);
const res = await fetch(`http://localhost:3000/api/post/${slug}`);
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
// Recommendation: handle errors
@@ -39,12 +39,12 @@ export default async function Page({ params }: {params: {slug:string}}) {
<Header />
<Navbar />
<PageContainer>
<Sidebar>
{/* <Sidebar>
<h1>
Filters
</h1>
<ul><li>filter 1</li><li>filter 2</li><li>filter 3</li></ul>
</Sidebar>
</Sidebar> */}
<main>
<Article id={post?.id?.toString()} title={post?.title?.toString()} content={post?.content?.toString()}/>
</main>

View File

@@ -25,3 +25,130 @@ body {
)
rgb(var(--background-start-rgb));
}
@layer base {
:root {
--text-50: #f3eff5;
--text-100: #e7dfec;
--text-200: #cfbfd9;
--text-300: #b89fc6;
--text-400: #a080b3;
--text-500: #88609f;
--text-600: #6d4d80;
--text-700: #523960;
--text-800: #362640;
--text-900: #1b1320;
--text-950: #0e0a10;
--background-50: #f4eef6;
--background-100: #e8ddee;
--background-200: #d2bbdd;
--background-300: #bb99cc;
--background-400: #a477bb;
--background-500: #8e55aa;
--background-600: #714488;
--background-700: #553366;
--background-800: #392244;
--background-900: #1c1122;
--background-950: #0e0911;
--primary-50: #f3edf8;
--primary-100: #e6daf1;
--primary-200: #ceb5e3;
--primary-300: #b590d5;
--primary-400: #9c6bc7;
--primary-500: #8346b9;
--primary-600: #693894;
--primary-700: #4f2a6f;
--primary-800: #351c4a;
--primary-900: #1a0e25;
--primary-950: #0d0712;
--secondary-50: #f3ebf9;
--secondary-100: #e7d7f4;
--secondary-200: #cfb0e8;
--secondary-300: #b788dd;
--secondary-400: #9f61d1;
--secondary-500: #8739c6;
--secondary-600: #6c2e9e;
--secondary-700: #512277;
--secondary-800: #36174f;
--secondary-900: #1b0b28;
--secondary-950: #0d0614;
--accent-50: #f3eafb;
--accent-100: #e7d5f6;
--accent-200: #cfaaee;
--accent-300: #b880e5;
--accent-400: #a056dc;
--accent-500: #882bd4;
--accent-600: #6d23a9;
--accent-700: #521a7f;
--accent-800: #361155;
--accent-900: #1b092a;
--accent-950: #0e0415;
}
.dark {
--text-50: #0e0910;
--text-100: #1b1320;
--text-200: #362541;
--text-300: #513861;
--text-400: #6c4a82;
--text-500: #885da2;
--text-600: #9f7db5;
--text-700: #b79ec7;
--text-800: #cfbeda;
--text-900: #e7dfec;
--text-950: #f3eff6;
--background-50: #0d0911;
--background-100: #1b1122;
--background-200: #352244;
--background-300: #503366;
--background-400: #6a4488;
--background-500: #8555aa;
--background-600: #9d77bb;
--background-700: #b699cc;
--background-800: #cebbdd;
--background-900: #e7ddee;
--background-950: #f3eef6;
--primary-50: #0d0712;
--primary-100: #1a0e25;
--primary-200: #351c4a;
--primary-300: #4f2a6f;
--primary-400: #693894;
--primary-500: #8346b9;
--primary-600: #9c6bc7;
--primary-700: #b590d5;
--primary-800: #ceb5e3;
--primary-900: #e6daf1;
--primary-950: #f3edf8;
--secondary-50: #0d0614;
--secondary-100: #1b0b28;
--secondary-200: #36174f;
--secondary-300: #512277;
--secondary-400: #6c2e9e;
--secondary-500: #8739c6;
--secondary-600: #9f61d1;
--secondary-700: #b788dd;
--secondary-800: #cfb0e8;
--secondary-900: #e7d7f4;
--secondary-950: #f3ebf9;
--accent-50: #0e0415;
--accent-100: #1b092a;
--accent-200: #361155;
--accent-300: #521a7f;
--accent-400: #6d23a9;
--accent-500: #882bd4;
--accent-600: #a056dc;
--accent-700: #b880e5;
--accent-800: #cfaaee;
--accent-900: #e7d5f6;
--accent-950: #f3eafb;
}
}

View File

@@ -1,6 +1,7 @@
import './globals.css'
import { Inter } from 'next/font/google'
import StyledJsxRegistry from './registry';
import Providers from '@/providers/providers';
const inter = Inter({ subsets: ['latin'], fallback: ['system-ui', 'arial'] })
@@ -16,7 +17,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className={inter.className}><StyledJsxRegistry>{children}</StyledJsxRegistry></body>
<body className={inter.className}><StyledJsxRegistry><Providers>{children}</Providers></StyledJsxRegistry></body>
</html>
)
}

79
src/app/lib/actions.ts Normal file
View File

@@ -0,0 +1,79 @@
'use server'
import { constructAPIUrl } from "@/util/Utils"
// import { signIn } from '@/auth'
import { cookies } from "next/headers"
import { parseSetCookie } from "@/util/parseSetCookie";
import makeFetchCookie from 'fetch-cookie';
type LoginReturn = {
cookie?:unknown,
errorMessage?:string;
}
async function signIn(method:string,b:FormData):Promise<LoginReturn|null>
{
console.log("form data:");
console.log(b);
if(!b || !b.get('input_username') || !b.get('input_password')) return null;
let headers:Headers = new Headers();
const fetchCookie = makeFetchCookie(fetch)
headers.set('Authorization', 'Basic ' + Buffer.from(b.get('input_username') + ":" + b.get('input_password')).toString('base64'));
let res = await fetchCookie(constructAPIUrl("auth"), {
method:'POST',
credentials: 'include',
headers:headers,
});
// if(res.headers.get('set-coo')) console.log(res.headers['set-cookie'])
let koek = res.headers.getSetCookie();
// console.log("api koek:" + koek.map((k)=>decodeURIComponent(k)));
let cookieDict = parseSetCookie(koek);
console.log("testing cookiedict")
console.log(cookieDict);
await cookies().set('auth', cookieDict.auth);
return {
cookie:cookieDict.auth,
errorMessage:""
};
// console.log(koek);
}
export async function authenticate(_currentState: unknown, formData: FormData):Promise<LoginReturn|null>
{
console.log("action triggered")
try {
const signInStatus = await signIn('credentials', formData)
return signInStatus;
} catch (error:any) {
if (error) {
switch (error.type) {
case 'CredentialsSignin':
return {
errorMessage: 'invalidCredentials'
}
default:
return {
errorMessage: 'Something went wrong.'
}
}
}
throw error
}
}
export async function koekValid(koek:string):Promise<boolean>
{
const validateSession = await fetch(constructAPIUrl("auth/validate"),{
method:"POST",
headers:{
Cookie: `auth=${koek};`
}
});
if(validateSession.status == 200)
return true
else
return false
}

View File

@@ -4,10 +4,11 @@ import Navbar from "@/components/navbar";
import Sidebar from "@/components/sidebar";
import ArticlePreview from "@/components/news/article-preview"
import ReactDOM from "react";
import "public/global.css"
import "/public/global.css"
import "./index.css"
import { Post, PostAttributes } from "@/model/sequelize/NewModels";
import { constructAPIUrl } from "@/util/Utils";
import Link from "next/link";
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
@@ -23,12 +24,12 @@ export default async function Test() {
<Header/>
<Navbar/>
<PageContainer>
<Sidebar>
{/* <Sidebar>
<h1>
Filters
</h1>
<ul><li>filter 1</li><li>filter 2</li><li>filter 3</li></ul>
</Sidebar>
</Sidebar> */}
<main>
{articles.map((article, i) => {
console.log("Entered");

View File

@@ -0,0 +1,32 @@
'use client'
import { ReactNode, useContext } from "react";
import { AuthContext, AuthProps } from "@/providers/providers";
import SomeServerSubComponent from "./serverContextUserTest";
interface Props {
children?: ReactNode;
auth?: AuthProps;
}
export default function AdminPanel(props:Props){
return (
<div className="AdminPanelWrapper">
<h1>Super Secret Admin Panel!</h1>
<h2>this is where we use the context test:<SomeSubComponent></SomeSubComponent></h2>
<SomeServerSubComponent></SomeServerSubComponent>
<section>
{props.children}
</section>
</div>
)
}
function SomeSubComponent(props:Props){
let { test, auth } = useContext(AuthContext);
return (
<span>{test}{JSON.stringify(auth)}</span>
);
}

View File

@@ -0,0 +1,47 @@
'use server'
import { cookies } from "next/headers";
// import { useState } from "react";
import LoginForm from "./loginForm";
import { koekValid } from "@/app/lib/actions";
import { constructAPIUrl } from "@/util/Utils";
import AdminPanel from "./adminPanel";
import { ReactNode } from "react";
import { AuthContext, AuthProps } from "@/providers/providers";
import ClientAuthHandler from "./clientAuthHandler";
interface Props {
children?: ReactNode;
params?: any;
requiredRole?: number;
} // We interfacing lads
export default async function AuthHandler(props: Props) {
const protoKoek = await cookies().get('auth')?.value;
const koek = decodeURIComponent(protoKoek?protoKoek:"");
console.log("koekje:" + koek)
let p:AuthProps = {
test:"not pog"
};
if(koek){
const kd = JSON.parse(koek);
if(kd.id && kd.token && kd.user_id){
p = {
test:"success!",
auth: {
id:kd.id,
token:kd.token,
user_id:kd.user_id
}
}
}
}
return (
<div className="flex flex-row">
{!(koek && await koekValid(koek)) ? <LoginForm>{ }</LoginForm> : <ClientAuthHandler authProps={p}><section>{props.children}<div>signed in! :D</div></section></ClientAuthHandler>}
</div>
);
}

View File

@@ -0,0 +1,16 @@
'use client'
import { AuthContext, AuthProps } from "@/providers/providers";
import { ReactNode, createContext } from "react"
type Props = {
children?:ReactNode;
authProps:AuthProps
}
export default function ClientAuthHandler(props:Props){
return (
<AuthContext.Provider value={props.authProps}>{props.children}</AuthContext.Provider>
)
}

View File

@@ -0,0 +1,46 @@
'use client'
import { authenticate } from "@/app/lib/actions";
import { AuthContext } from "@/providers/providers";
import { constructAPIUrl } from "@/util/Utils";
import { cookies } from "next/headers";
import { createContext, useState } from "react";
import { useFormState, useFormStatus } from "react-dom";
// async function authenticate(){
// const url = await constructAPIUrl("auth");
// const auth = await fetch(url);
// }
export default function LoginForm(){
const [loginResult, dispatch] = useFormState(authenticate, undefined);
// if(loginResult?.cookie && loginResult.cookie && loginResult.cookie['auth']){
// cookies().set('auth', loginResult.cookie['auth'])
// }
return (
<form className="bg-background-400 border-4 border-primary-500 drop-shadow-md w-fit p-3 rounded-lg flex flex-col gap-1" action={dispatch}>
<label htmlFor="input_username">Username</label>
<input type="text" name="input_username" id="input_username" className="bg-secondary border-2 border-primary rounded-lg drop-shadow-md" />
<label htmlFor="input_password">Password</label>
<input type="password" name="input_password" id="input_password" className="bg-secondary outline-primary border-2 border-primary rounded-lg drop-shadow-md shadow-inner shadow-primary" />
<LoginButton></LoginButton>
<div>{loginResult?.errorMessage && <p>{loginResult?.errorMessage}</p>}</div>
<div className="flex flex-col w-[400px] break-words ">
<p>{""+loginResult?.cookie}</p>
</div>
</form>);
}
function LoginButton() {
const { pending } = useFormStatus()
return (
<button aria-disabled={pending} className="mr-auto bg-secondary-200 outline outline-2 border-5 p-3 mt-3 rounded-lg outline-secondary-500 shadow-primary" type="submit">
{!pending ? 'Sign In' : 'Pending Sign In...'}
</button>
)
}

View File

@@ -0,0 +1,14 @@
import { AuthContext, AuthProps } from "@/providers/providers";
import { ReactNode, useContext } from "react";
interface Props {
children?: ReactNode;
auth?: AuthProps;
}
export default function SomeServerSubComponent(props:Props){
let { test, auth } = useContext(AuthContext);
return (
<span>{test}{JSON.stringify(auth)}</span>
);
}

View File

@@ -0,0 +1,16 @@
import { AuthContext } from "@/providers/providers";
import { ReactNode, useContext } from "react"
type Props = {
children:ReactNode;
}
export default function AdminOnlyComponent(p:Props){
const context = useContext(AuthContext)
return
(<div>
</div>);
}

View File

@@ -3,6 +3,8 @@
flex-direction: row;
box-sizing: content-box;
min-height:128px;
padding-top: 0;
background-color: #1a4457;
/* background-color: aqua; */
/* max-width:25vw; */
/* outline: auto; */
@@ -20,4 +22,5 @@
.summary{
/* flex-shrink: 1; */
padding:8px;
padding-top:0px;
}

View File

@@ -4,16 +4,35 @@ import styles from "./article-preview.module.css"
import bg from "public/placeholder-square.png"
import { ReactNode } from "react"
import { Style } from "util";
import Link from "next/link";
import { redirect } from 'next/navigation';
import { Router } from "next/router";
import { useRouter } from 'next/navigation'
import { truncateString } from "@/util/Utils";
export default function ArticlePreview(params: { id: string|undefined, title: string|undefined, content: string|undefined, date?:string|undefined } ){
return <div className={styles.previewbox}>
<div className={styles.imagecontainer}>
type Props = {
id?:string
title?:string
content?:string
date?:string
}
export default function ArticlePreview(props:Props){
// if (!props.content)
return (
<section className={styles.previewbox}>
<div className={styles.imagecontainer}></div>
</div>
<div className={styles.summary}>
<h2>{params.title}</h2><Tagbar/>
<p>{params.content}</p>
</div>
</div>;
<div className={`${styles.summary} flex flex-col justify-between p-0`}>
<section className="w-[100%]">
<span className="inline-block"><h2><Link href={`/article/${props.id}`}>{props.title}</Link></h2></span>
<p>{truncateString(props.content,255)}</p>
</section>
<Tagbar/>
</div>
</section>
);
}

View File

@@ -9,7 +9,7 @@
}
.imagecontainer{
min-width:100%;
min-width:fit-content;
min-height:256px;
/* flex-grow: 10; */
background-image: url(/placeholder-square.png);

View File

@@ -1,5 +1,5 @@
import Tagbar from "@/components/news/tagbar";
import "public/global.css"
import "/public/global.css"
import "@/app/index.css"
import styles from "./article.module.css"
@@ -7,13 +7,11 @@ import styles from "./article.module.css"
export default function Article(params: { id: string|undefined, title: string|undefined, content: string|undefined, date?:string|undefined } ) {
return (
<article id={`post-${params.id}`}>
<h1 className=".article-title">{params.title}</h1>
<Tagbar/>
<div className={styles.imagecontainer}/>
<p className=".article-content">{params.content}</p>
<section className=".article-date">{params.date}</section>
<br/>
<h1 className=".article-title pl-5 pr-5">{params.title}</h1>
<div className={`${styles.imagecontainer} m-5`}/>
<div className="pl-5 pr-5"><Tagbar/></div>
<p className=".article-content p-5">{params.content}</p>
<section className=".article-date">{params.date}</section> <br/>
</article>
);
}

View File

@@ -10,5 +10,5 @@
*display: inline;
}
.tagbar{
margin: 0px 0px 4px 0px;
margin: 0px 0px 0px 0px;
}

View File

@@ -1,7 +1,7 @@
import styles from "./tagbar.module.css"
const tagItems = ["tag1", "tag2", "tag3"];
const tagList = tagItems.map(value => <li key={value} className={styles.navItem}><a>{value}</a></li>);
const tagList = tagItems.map(value => <li key={value} className={styles.navItem}><a href={`/tagged/${value}`}>{value}</a></li>);
export default function Tagbar() {

View File

@@ -1,34 +0,0 @@
import { Connection, RowDataPacket, OkPacket, QueryError } from "mysql2";
import { getConnection } from "@/db";
export interface IPost extends RowDataPacket {
id: number;
post: string;
}
export async function getPost(id:Number): Promise<IPost[]> {
// let [rows]:Array<IPost> = await conn.execute("SELECT * FROM `post`", []);
return new Promise((resolve, reject) => {
let res = getConnection().then((conn)=>{conn.query<IPost[]>(`SELECT * FROM post WHERE id = ${id}`, (err:QueryError, res) => {
if (err) reject(err)
else resolve(res)
});
});
return res;
});
}
export async function getPosts(): Promise<IPost[]> {
// let [rows]:Array<IPost> = await conn.execute("SELECT * FROM `post`", []);
return new Promise((resolve, reject) => {
let res = getConnection().then((conn)=>{conn.query<IPost[]>("SELECT * FROM post", (err:QueryError, res) => {
if (err) reject(err)
else resolve(res)
});
});
return res;
});
}
// export default { getPost, getPosts }

View File

@@ -4,7 +4,9 @@ import {
HasManySetAssociationsMixin, HasManyAddAssociationsMixin, HasManyHasAssociationsMixin,
HasManyRemoveAssociationMixin, HasManyRemoveAssociationsMixin, Model, ModelDefined, Optional,
Sequelize, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ForeignKey, BelongsTo, BelongsToGetAssociationMixin, UUIDV4, UUID,
VirtualDataType
VirtualDataType,
HasOneGetAssociationMixin,
HasOneCreateAssociationMixin
} from 'sequelize';
@@ -13,11 +15,35 @@ const sequelize = new Sequelize({
storage: 'db.sqlite'
});
export class UserPerms extends Model<InferAttributes<UserPerms>, InferCreationAttributes<UserPerms>> {
declare id: CreationOptional<number>;
declare user:NonAttribute<User>;
declare user_id:ForeignKey<User['id']>;
declare isAdmin:CreationOptional<boolean>;
}
UserPerms.init({
id: {
allowNull: false,
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true,
unique: true,
},
isAdmin: {
allowNull: false,
defaultValue: false,
type: DataTypes.BOOLEAN
}
},
{
tableName: 'Perms',
sequelize // passing the `sequelize` instance is required
});
export class Auth extends Model<InferAttributes<Auth>, InferCreationAttributes<Auth>> {
declare id: CreationOptional<number>;
declare token: CreationOptional<string>;
declare user:NonAttribute<User>;
declare user_id:ForeignKey<User['id']>;
declare getUser: BelongsToGetAssociationMixin<User>;
declare static associations: {
@@ -96,6 +122,13 @@ export class User extends Model<InferAttributes<User>, InferCreationAttributes<U
declare password: string;
declare getAuthTokens:HasManyGetAssociationsMixin<Auth>;
declare getPosts:HasManyGetAssociationsMixin<Post>;
declare getPerms:HasOneGetAssociationMixin<UserPerms>;
declare createPerms:HasOneCreateAssociationMixin<UserPerms>;
declare perms?:NonAttribute<UserPerms>
declare static associations: {
perms: Association<UserPerms,User>;
};
}
User.init(
@@ -114,20 +147,19 @@ User.init(
password: {
allowNull: false,
type: DataTypes.STRING,
}
},
},
{
defaultScope: {
attributes:{
exclude:['password']
}
attributes: {
exclude: ['password'],
},
include: [{ association: 'perms' }],
},
tableName: 'Users',
sequelize // passing the `sequelize` instance is required
}
);
User.scope
Auth.belongsTo(User, {
foreignKey:'user_id',
@@ -149,7 +181,19 @@ User.hasMany(Post, {
foreignKey: 'user_id',
as: 'posts' // this determines the name in `associations`!
});
UserPerms.belongsTo(User, {
foreignKey:'user_id',
targetKey:'id',
as: 'user'
})
User.hasOne(UserPerms, {
sourceKey: 'id',
foreignKey: 'user_id',
as: 'perms'
})
User.sync();
Auth.sync();
Post.sync();
Post.sync();
UserPerms.sync();

View File

@@ -0,0 +1,28 @@
'use client'
import { Auth, User } from "@/model/sequelize/NewModels";
import { ReactNode, createContext } from "react";
import { InferAttributes } from "sequelize/types/model";
export type AuthProps = {
test: string;
auth?: InferAttributes<Auth>
user?: InferAttributes<User>
}
let p: AuthProps = {
test: "lorem",
}
export const AuthContext = createContext(p);
interface Props {
children?: ReactNode;
params?: any;
}
export default function Providers(props:Props){
return (
<AuthContext.Provider value={{test:"freek"}}>{props.children}</AuthContext.Provider>
)
}

View File

@@ -14,6 +14,17 @@ function constructAPIUrl(endpoint:string){
const { schema, host, port, basepath } = getAPIEnv();
return `${schema}://${host}:${port}/${basepath}/${endpoint}`
}
function constructUrl(endpoint:string){
const { schema, host, port, basepath } = getAPIEnv();
return `${schema}://${host}:${port}/${endpoint}`
}
function truncateString(str:string = '', num:number = 255) {
if (str.length > num) {
return str.slice(0, num) + "...";
} else {
return str;
}
}
export { Gens, Auth, constructAPIUrl }
export { Gens, Auth, constructAPIUrl, constructUrl, truncateString }

View File

@@ -0,0 +1,9 @@
export function parseSetCookie(h: string[]) {
let aaa = h.map(
s => [...s.matchAll(/(.*?)=(.*?)($|;|,(?! ))/gm)]
);
const dict = Object.assign({}, ...aaa[0].map((e) => {
return { [e[1]]: decodeURIComponent(e[2]) };
}));
return dict;
}