Many Changes

This commit is contained in:
2024-05-14 12:49:50 +02:00
parent a01b6bdbc2
commit f6eef1ded3
53 changed files with 636 additions and 579 deletions

View File

@@ -3,14 +3,14 @@
import { validatePassword } from "@/util/Auth";
import { APIError } from "@/api/error";
import { User, Auth } from "@/model/sequelize/NewModels";
import { User } from "@/model/User";
export function parseBasicAuth(authb64:string):UserAuth
{
const authString:string = Buffer.from(authb64.split(" ")[1], "base64").toString("utf8");
const authString:string = Buffer.from(authb64.split(" ")[1] as any, "base64").toString("utf8");
var userAuth:UserAuth = {
username:authString.split(":")[0],
password:authString.split(":")[1]
username:authString.split(":")[0] as any,
password:authString.split(":")[1] as any
};
return userAuth
}
@@ -22,7 +22,6 @@ export type UserAuth = {
export async function getAssociatedUser(auth:UserAuth)
{
const username = auth.username;
let foundUser = await User.findOne({ attributes: {include: ['password']}, where: {username: auth.username} });
if (!foundUser)

View File

@@ -1,12 +1,12 @@
'use client'
import { authenticate } from '@/app/lib/actions'
import { serverAttemptAuthenticateUser } 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)
const [loginResult, dispatch] = useFormState(serverAttemptAuthenticateUser, undefined)
console.log(dispatch);
console.log(state);

View File

@@ -1,5 +1,5 @@
import AdminPanel from "@/components/admin/adminPanel";
import AuthHandler from "@/components/admin/authHandler";
import AdminPanel from "@/components/client/admin/adminPanel";
import AuthHandler from "@/components/server/admin/authHandler";
import { cookies } from "next/headers";

View File

@@ -14,17 +14,10 @@ export async function GET(request:Request, { params }: {params:{slug: string}}){
// @ts-ignore
cookies().set('name', 'lee');
return Response.json({
"a": "lorem",
"b": params
"params": params
});
}
// export default async function handler(req:NextApiRequest, res:NextApiResponse) {
// await MPost.sync();
// switch (req.method) {

View File

@@ -1,13 +1,10 @@
'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"
import { Auth, User } from "@/model/Models";
async function tryAuth(request:Request){
@@ -31,15 +28,24 @@ async function tryAuth(request:Request){
user_id: user.id,
})
console.log('ok');
const foundAuth = await Auth.findOne({
include: 'user',
include: {
model: User,
as: 'user'
},
where: {
user_id: user.id
}
})
console.log('ok2');
if(!foundAuth)
return new Response("error",{status:500});
const usr = foundAuth.user;
const authUser = await authentication.getUser();

View File

@@ -1,9 +1,10 @@
'use server'
import { Model } from "sequelize";
import { Model } from "@sequelize/core";
import { cookies } from "next/headers";
import { Auth, Post, User } from "@/model/sequelize/NewModels";
import { Auth } from "@/model/Models";
import { APIError} from "@/api/error"
@@ -23,9 +24,13 @@ async function tryAuth(request:Request){
console.log(koek);
const auth = JSON.parse(koek.value);
const authentication = await Auth.findOne( { include: 'user', where: {token:auth.token} })
const authentication = await Auth.findOne( { include: {
association: Auth.associations.user
}, where: { token:auth.token } })
if(!authentication)
return new Response("unauthorized: invalid token",{status:403});

View File

@@ -1,7 +1,7 @@
'use server'
import { APIError } from "@/api/error";
import { Post } from "@/model/sequelize/NewModels";
import { Post } from "@/model/Models";
export async function tryFetchPost(request:Request, { params }: {params:{slug: string}}){

View File

@@ -1,15 +1,16 @@
'use server'
import { APIError } from "@/api/error";
import { Auth, Post, User } from "@/model/Models";
import { Auth, Post, PostTag, Tag, User } from "@/model/Models";
import { cookies } from "next/headers";
import { where } from "sequelize";
async function tryCreatePost(request: Request) {
// Make sure the DB is ready
await PostTag.sync();
await Tag.sync();
await Post.sync();
// Prepare data
@@ -24,7 +25,7 @@ async function tryCreatePost(request: Request) {
const authObject = JSON.parse(cookieJSON);
// Fetch User Auth from the database
const auth = await Auth.findOne({ include: 'user', where: { token: authObject.token } });
const auth:any = await Auth.findOne({ include: 'user', where: { token: authObject.token } });
// Sanity check the auth and associated user
if (!auth || !auth.user) throw new APIError({ status: 401, responseText: "Authentication Error" });
@@ -35,6 +36,7 @@ async function tryCreatePost(request: Request) {
if (!requestBody.title) throw new APIError({ status: 500, responseText: "Missing post title" });
if (!requestBody.content) throw new APIError({ status: 500, responseText: "Missing post content" });
if (!user.id) throw new APIError({ status: 500, responseText: "Missing user id" });
if (!user.perms || !user.perms.isAdmin) throw new APIError({ status: 401, responseText: "Unauthorized" });
// Create a new Post in the database
const post = await Post.create(
@@ -42,8 +44,11 @@ async function tryCreatePost(request: Request) {
content: requestBody.content,
user_id: user.id,
title: requestBody.title,
date: Date.now()
},{include: "user"})
},{
include: {
association: Post.associations.user
}
}).then(post=>post.reload())
// // Find the post (Unneeded but nice to check)
// const foundPost = await Post.findOne({
// include: "user",
@@ -52,7 +57,7 @@ async function tryCreatePost(request: Request) {
// }
// })
return new Response(JSON.stringify(Post), { status: 200 });
return new Response(JSON.stringify(post), { status: 200 });
}
@@ -76,9 +81,12 @@ async function tryFetchPosts(request: Request) {
await Post.sync();
const foundPosts = await Post.findAll({
include: [{
association: 'user',
include: [
{
association: Post.associations.user,
attributes: { exclude: ['password', 'createdAt', 'updatedAt'] }
},{
association: Post.associations.postTags
}]
});

View File

@@ -1,41 +1,48 @@
'use server'
import { User, Auth, Post, UserPerms } from "@/model/sequelize/NewModels"
/* =================================================================================================
*
* Copyright 2024 Andreas Schaafsma
* Purpose: Handle API requests that fetch or permute User data
*
* ================================================================================================= */
import { APIError } from "@/api/error";
import { UserAuth } from "@/api/user";
import { UserPerms, User, Auth } from "@/model/Models"; // Do not alter "unused" imports, they are required to perform the nescessairy includes on the User model
import { hashPassword } from "@/util/Auth";
async function tryRegister(request:Request){
// Attempt to register a new User
async function attemptRegister(request:Request){
// Sync User model
User.sync();
// Get request body
const requestBody:Partial<UserAuth> = await request.json();
// Handle edgecases
if(!requestBody) throw new APIError({status:500,responseText: "Request Body is Empty"})
if(!requestBody.username) throw new APIError({status:500,responseText: "No username specified"})
if(!requestBody.password) throw new APIError({status:500,responseText: "No password specified"})
// Try to get user from database
const dbUser = await User.findOne({where:{username:requestBody.username}});
// If it exists we throw an error
if(dbUser) throw new APIError({status:500,responseText: "Username unavailable, try another"});
const hash = await hashPassword(requestBody.password);
// Hash the password and create a new user in the database
const user = await User.create({
username: requestBody.username,
password: hash,
password: await hashPassword(requestBody.password),
perms:{
isAdmin: false
}
},
{
include: [{
association: 'perms'
association: User.associations.perms
}]
})
}).then(user=>user.reload());
// Return the HTTP response
return new Response(
JSON.stringify(
{
@@ -52,7 +59,7 @@ async function tryRegister(request:Request){
export async function POST(request:Request){
try{
return await tryRegister(request);
return await attemptRegister(request);
}
catch(e){
if (e instanceof APIError){
@@ -65,23 +72,9 @@ export async function POST(request:Request){
}
}
async function tryGetUsers(request:Request){
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,
}
);
async function attemptGetUsers(request:Request){
// Get users with scopes applied
const users = await User.withScope(['defaultScope','withPerms','withAuthtokens']).findAll();
return new Response(
JSON.stringify(
{
@@ -98,7 +91,7 @@ async function tryGetUsers(request:Request){
export async function GET(request:Request){
try{
return await tryGetUsers(request);
return await attemptGetUsers(request);
}
catch(e){
if (e instanceof APIError){

View File

@@ -1,21 +1,21 @@
import Header from "@/components/header";
import PageContainer from "@/components/page-container";
import Navbar from "@/components/navbar";
import Sidebar from "@/components/sidebar";
import Article from "@/components/news/article";
import ArticlePreview from "@/components/news/article-preview"
import Header from "@/components/shared/header";
import PageContainer from "@/components/shared/page-container";
import Navbar from "@/components/shared/navbar";
import Sidebar from "@/components/shared/sidebar";
import Article from "@/components/shared/news/article";
import ArticlePreview from "@/components/shared/news/article-preview"
import ReactDOM from "react";
import "/public/global.css"
import "@/app/index.css"
import { Post, User } from "@/model/sequelize/NewModels";
import { Attributes } from "sequelize";
import { Post } from "@/model/Post";
import { Attributes } from "@sequelize/core";
import { DeepPartial } from "@/util/DeepPartial";
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
async function getData(slug:string):Promise<DeepPartial<Post>> {
async function getData(slug:string):Promise<Attributes<Post>> {
// Get all posts from the API
const res = await fetch(`http://localhost:3000/api/post/${slug}`);
// The return value is *not* serialized
@@ -31,7 +31,7 @@ async function getData(slug:string):Promise<DeepPartial<Post>> {
export default async function Page({ params }: {params: {slug:string}}) {
const { slug } = params;
const post:DeepPartial<Attributes<Post>> = await getData(slug);
const post:Attributes<Post> = await getData(slug);
console.log(post);

View File

@@ -5,27 +5,30 @@ import { constructAPIUrl } from "@/util/Utils"
import { cookies } from "next/headers"
import { parseSetCookie } from "@/util/parseSetCookie";
import makeFetchCookie from 'fetch-cookie';
import fetchCookie from "fetch-cookie";
type LoginReturn = {
cookie?:unknown,
errorMessage?:string;
}
async function signIn(method:string,b:FormData):Promise<LoginReturn|null>
async function attemptAPILogin(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"), {
const { CookieJar, Cookie } = fetchCookie.toughCookie;
const cj = new CookieJar()
const fetchKoek = makeFetchCookie(fetch, cj);
// Set Basic Auth
headers.set('Authorization', `Basic ${Buffer.from(`${b.get('input_username')}:${b.get('input_password')}`).toString('base64')}`);
let res = await fetchKoek(constructAPIUrl("auth"), {
method:'POST',
credentials: 'include',
headers:headers,
});
console.log(cj.store.idx['localhost']['/']);
// 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)));
@@ -40,11 +43,11 @@ async function signIn(method:string,b:FormData):Promise<LoginReturn|null>
// console.log(koek);
}
export async function authenticate(_currentState: unknown, formData: FormData):Promise<LoginReturn|null>
export async function serverAttemptAuthenticateUser(_currentState: unknown, formData: FormData):Promise<LoginReturn|null>
{
console.log("action triggered")
try {
const signInStatus = await signIn('credentials', formData)
const signInStatus = await attemptAPILogin('credentials', formData)
return signInStatus;
} catch (error:any) {
if (error) {
@@ -62,10 +65,9 @@ export async function authenticate(_currentState: unknown, formData: FormData):P
throw error
}
}
export async function koekValid(koek:string):Promise<boolean>
{
export async function serverValidateSessionCookie(koek:string):Promise<boolean>
{
const validateSession = await fetch(constructAPIUrl("auth/validate"),{
method:"POST",
headers:{

View File

@@ -1,14 +1,15 @@
import Header from "@/components/header";
import PageContainer from "@/components/page-container";
import Navbar from "@/components/navbar";
import Sidebar from "@/components/sidebar";
import ArticlePreview from "@/components/news/article-preview"
import Header from "@/components/shared/header";
import PageContainer from "@/components/shared/page-container";
import Navbar from "@/components/shared/navbar";
import Sidebar from "@/components/shared/sidebar";
import ArticlePreview from "@/components/shared/news/article-preview"
import ReactDOM from "react";
import "/public/global.css"
import "./index.css"
import { Post, PostAttributes } from "@/model/sequelize/NewModels";
import { Post } from "@/model/Post";
import { constructAPIUrl } from "@/util/Utils";
import Link from "next/link";
import { Attributes } from "@sequelize/core";
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
@@ -18,7 +19,7 @@ export default async function Test() {
const response = await fetch(constructAPIUrl('post'));
const articles:Array<DeepPartial<PostAttributes>> = await response.json();
const articles:Array<Attributes<Post>> = await response.json();
return <div className={`root`}>
<Header/>
@@ -32,9 +33,8 @@ export default async function Test() {
</Sidebar> */}
<main>
{articles.map((article, i) => {
console.log("Entered");
// Return the element. Also pass key
return (<ArticlePreview id={article?.id?.toString()} content={article?.content} title={article?.title}></ArticlePreview>)
return (<ArticlePreview key={article?.id} id={article?.id?.toString()} content={article?.content} title={article?.title}></ArticlePreview>)
})}
</main>
</PageContainer>

View File

@@ -1,17 +1,30 @@
import Header from "@/components/header";
import PageContainer from "@/components/page-container";
import Navbar from "@/components/navbar";
import Sidebar from "@/components/sidebar";
import ArticlePreview from "@/components/news/article-preview"
import ReactDOM from "react";
// import components
import Header from "@/components/shared/header";
import PageContainer from "@/components/shared/page-container";
import Navbar from "@/components/shared/navbar";
import Sidebar from "@/components/shared/sidebar";
import ArticlePreview from "@/components/shared/news/article-preview"
// import styles
import "public/global.css"
import "@/app/index.css"
// import other shit
import ReactDOM, { ReactNode } from "react";
type Props = {
children?: ReactNode
}
export default function Page() {
return <div className={`root`}>
<Header/>
<Navbar/>
export default function Page(props: Props) {
return (
<div className={`root`}>
<Header />
<Navbar />
<PageContainer>
<Sidebar>
<h1>
@@ -20,10 +33,10 @@ export default function Page() {
<ul><li>filter 1</li><li>filter 2</li><li>filter 3</li></ul>
</Sidebar>
<main>
<ArticlePreview/>
<ArticlePreview/>
<ArticlePreview/>
<ArticlePreview />
<ArticlePreview />
<ArticlePreview />
</main>
</PageContainer>
</div>;
</div>);
}

View File

@@ -1,7 +1,7 @@
import Header from "@/components/header";
import PageContainer from "@/components/page-container";
import PageContainer from "@/components/shared/page-container";
import Navbar from "@/components/navbar";
import Sidebar from "@/components/sidebar";
import Sidebar from "@/components/shared/sidebar";
import ArticlePreview from "@/components/news/article-preview"
import ReactDOM from "react";
import "public/global.css"

View File

@@ -1,7 +1,7 @@
'use client'
import { ReactNode, useContext } from "react";
import { AuthContext, AuthProps } from "@/providers/providers";
import SomeServerSubComponent from "./serverContextUserTest";
import SomeServerSubComponent from "@/components/server/admin/serverContextUserTest";
interface Props {
children?: ReactNode;

View File

@@ -1,9 +1,8 @@
'use client'
import { authenticate } from "@/app/lib/actions";
import { serverAttemptAuthenticateUser } 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";
@@ -15,11 +14,7 @@ import { useFormState, useFormStatus } from "react-dom";
export default function LoginForm(){
const [loginResult, dispatch] = useFormState(authenticate, undefined);
// if(loginResult?.cookie && loginResult.cookie && loginResult.cookie['auth']){
// cookies().set('auth', loginResult.cookie['auth'])
// }
const [loginResult, dispatch] = useFormState(serverAttemptAuthenticateUser, undefined);
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}>

View File

@@ -1,13 +1,14 @@
'use server'
import { cookies } from "next/headers";
// import { useState } from "react";
import LoginForm from "./loginForm";
import { koekValid } from "@/app/lib/actions";
import LoginForm from "@/components/client/admin/loginForm";
import AdminPanel from "@/components/client/admin/adminPanel";
import ClientAuthHandler from "@/components/client/admin/clientAuthHandler";
import { serverValidateSessionCookie } 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 {
@@ -17,10 +18,9 @@ interface Props {
} // We interfacing lads
export default async function AuthHandler(props: Props) {
const protoKoek = await cookies().get('auth')?.value;
const koek = decodeURIComponent(protoKoek?protoKoek:"");
const koek = decodeURIComponent(protoKoek ? protoKoek: "");
console.log("koekje:" + koek)
let p:AuthProps = {
test:"not pog"
@@ -41,7 +41,7 @@ export default async function AuthHandler(props: Props) {
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>}
{!(koek && await serverValidateSessionCookie(koek)) ? <LoginForm>{ }</LoginForm> : <ClientAuthHandler authProps={p}><section>{props.children}<div>signed in! :D</div></section></ClientAuthHandler>}
</div>
);
}

View File

@@ -8,6 +8,8 @@ interface Props {
export default function SomeServerSubComponent(props:Props){
let { test, auth } = useContext(AuthContext);
return (
<span>{test}{JSON.stringify(auth)}</span>
);

View File

@@ -1,5 +1,5 @@
import Tagbar from "@/components/news/tagbar";
import styles from "./article-preview.module.css"
import Tagbar from "@/components/shared/news/tagbar";
import styles from "@/components/shared/news/article-preview.module.css"
import bg from "public/placeholder-square.png"
import { ReactNode } from "react"

View File

@@ -1,4 +1,4 @@
import Tagbar from "@/components/news/tagbar";
import Tagbar from "@/components/shared/news/tagbar";
import "/public/global.css"
import "@/app/index.css"
import styles from "./article.module.css"

42
src/model/APIKey.ts Normal file
View File

@@ -0,0 +1,42 @@
import { Association, CreationOptional, DataTypes, HasManyGetAssociationsMixin, HasOneCreateAssociationMixin, HasOneGetAssociationMixin, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "@sequelize/core";
import {
PrimaryKey,
Attribute,
AutoIncrement,
NotNull,
BelongsTo,
Unique,
HasMany,
HasOne,
UpdatedAt,
CreatedAt,
} from '@sequelize/core/decorators-legacy';
import { SqliteDialect } from '@sequelize/sqlite3';
export class APIKey extends Model<InferAttributes<APIKey>, InferCreationAttributes<APIKey>>{
// Attributes
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
@Unique
declare id: number;
@Attribute(DataTypes.UUID)
declare key: string;
@Attribute(DataTypes.BOOLEAN)
declare isAdminKey: boolean
// Date thingies
@CreatedAt
declare createdAt: CreationOptional<Date>;
@UpdatedAt
declare updatedAt: CreationOptional<Date>;
}
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [APIKey]
});

View File

@@ -1,37 +1,54 @@
import { Association, BelongsToGetAssociationMixin, CreationOptional, DataTypes, ForeignKey, InferAttributes, InferCreationAttributes, Model, Sequelize, UUIDV4 } from "sequelize";
import {
Sequelize,
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
sql,
BelongsToGetAssociationMixin,
Association,
NonAttribute,
} from '@sequelize/core';
import { User } from "./User";
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'db.sqlite'
});
import { SqliteDialect } from '@sequelize/sqlite3';
import { Attribute, AutoIncrement, BelongsTo, Default, NotNull, PrimaryKey, Table, Unique } from "@sequelize/core/decorators-legacy";
@Table({
tableName: 'Auths'
})
export class Auth extends Model<InferAttributes<Auth>, InferCreationAttributes<Auth>> {
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
@Unique
declare id: CreationOptional<number>;
@Attribute(DataTypes.UUIDV4)
@Default(sql.uuidV4)
declare token: CreationOptional<string>;
declare user_id:ForeignKey<User['id']>;
@Attribute(DataTypes.INTEGER)
@NotNull
declare user_id:number;
@BelongsTo( ()=>User, { foreignKey: 'user_id', inverse: { type: 'hasMany', as: 'authtokens' } } )
declare user?: NonAttribute<User>
declare getUser: BelongsToGetAssociationMixin<User>;
declare static associations: {
user: Association<User, Auth>;
};
}
Auth.init({
id: {
allowNull: false,
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true,
unique: true,
},
token: {
type: DataTypes.UUID,
defaultValue: UUIDV4
}
},
{
tableName: 'Auths',
sequelize // passing the `sequelize` instance is required
});
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [Auth]
});

View File

@@ -1,20 +1,15 @@
import {
Association, DataTypes, HasManyAddAssociationMixin, HasManyCountAssociationsMixin,
HasManyCreateAssociationMixin, HasManyGetAssociationsMixin, HasManyHasAssociationMixin,
HasManySetAssociationsMixin, HasManyAddAssociationsMixin, HasManyHasAssociationsMixin,
HasManyRemoveAssociationMixin, HasManyRemoveAssociationsMixin, Model, ModelDefined, Optional,
Sequelize, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ForeignKey, BelongsTo, BelongsToGetAssociationMixin, UUIDV4, UUID,
VirtualDataType,
HasOneGetAssociationMixin,
HasOneCreateAssociationMixin
} from 'sequelize';
import { UserPerms } from './UserPerms';
import { Auth } from './Auth';
import { Post } from './Post';
import { User } from './User';
import { Auth } from './Auth';
import { UserPerms } from './UserPerms';
import { Post } from './Post';
import { Tag } from './Tag';
import { PostTag } from './PostTag';
User.sync();
Auth.sync();
UserPerms.sync();
PostTag.sync();
Tag.sync();
Post.sync();
export { User, Auth, Post, UserPerms }
export { User, Auth, UserPerms, Post, Tag, PostTag }

View File

@@ -1,56 +1,53 @@
import { Association, BelongsToGetAssociationMixin, DataTypes, ForeignKey, Model, NonAttribute, Sequelize } from "sequelize";
import { User } from "./User";
import { Association, BelongsToGetAssociationMixin, CreationOptional, DataTypes, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "@sequelize/core";import { User } from "./User";
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'db.sqlite'
});
import { SqliteDialect } from '@sequelize/sqlite3';
import { Attribute, AutoIncrement, BelongsTo, BelongsToMany, CreatedAt, HasMany, NotNull, PrimaryKey, Unique, UpdatedAt } from "@sequelize/core/decorators-legacy";
import { Tag } from "./Tag";
import { PostTag } from "./PostTag";
export type PostAttributes = {
id: number;
title: string;
content: string;
date: number;
user_id:ForeignKey<User['id']>;
}
export type PostCreationAttributes = {
title: string;
content: string;
date: number;
user_id:number;
}
export class Post extends Model<PostAttributes, PostCreationAttributes> {
declare id: number;
declare user:NonAttribute<User>;
export class Post extends Model<InferAttributes<Post>, InferCreationAttributes<Post>> {
// Attributes
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
@Unique
declare id: CreationOptional<number>;
@Attribute(DataTypes.INTEGER)
@NotNull
declare user_id:ForeignKey<User['id']>;
@Attribute(DataTypes.STRING)
declare title:string
@Attribute(DataTypes.STRING)
declare content:string
// Date thingies
@CreatedAt
declare createdAt: CreationOptional<Date>;
@UpdatedAt
declare updatedAt: CreationOptional<Date>;
// Associatoins
@BelongsTo(()=>User, { foreignKey: 'user_id', inverse: { type: 'hasMany', as: 'posts' } })
declare user:NonAttribute<User>;
@BelongsToMany(()=>Tag, { through: { model: ()=>PostTag, unique: false}, inverse: {as: 'taggedPosts'} })
declare postTags?:NonAttribute<Tag[]>;
declare getUser: BelongsToGetAssociationMixin<User>;
declare static associations: {
user: Association<User, Post>;
postTags: Association<Tag, Post>;
};
}
Post.init(
{
id: {
allowNull: false,
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true,
unique: true,
},
content: {
type: DataTypes.STRING
},
title: {
type: DataTypes.STRING
},
date: {
type: DataTypes.DATE
},
},
{
tableName: 'Posts',
sequelize // passing the `sequelize` instance is required
}
);
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [Post]
})

20
src/model/PostTag.ts Normal file
View File

@@ -0,0 +1,20 @@
import Sequelize, { Association, DataTypes, InferAttributes, InferCreationAttributes, Model, NonAttribute } from "@sequelize/core";
import { Attribute, AutoIncrement, NotNull, PrimaryKey, Unique } from "@sequelize/core/decorators-legacy";
import { Post } from "./Post";
import { Tag } from "./Tag";
import { SqliteDialect } from "@sequelize/sqlite3";
class PostTag extends Model<InferAttributes<PostTag>,InferCreationAttributes<PostTag>>
{
declare postId:number;
declare tagId:number;
}
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [PostTag]
})
export { PostTag }

56
src/model/Project.ts Normal file
View File

@@ -0,0 +1,56 @@
import { Association, BelongsToGetAssociationMixin, CreationOptional, DataTypes, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "@sequelize/core";import { User } from "./User";
import { SqliteDialect } from '@sequelize/sqlite3';
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite'
});
export type ProjectAttributes = {
id: number;
title: string;
description: string;
date: number;
user_id:ForeignKey<User['id']>;
}
export type ProjectCreationAttributes = {
title: string;
description: string;
date: number;
user_id:number;
}
export class Project extends Model<ProjectAttributes, ProjectCreationAttributes> {
declare id: number;
declare user:NonAttribute<User>;
declare user_id:ForeignKey<User['id']>;
declare getUser: BelongsToGetAssociationMixin<User>;
declare static associations: {
user: Association<User, Project>;
};
}
Project.init(
{
id: {
allowNull: false,
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true,
unique: true,
},
content: {
type: DataTypes.STRING
},
title: {
type: DataTypes.STRING
},
date: {
type: DataTypes.DATE
},
},
{
tableName: 'Projects',
sequelize // passing the `sequelize` instance is required
}
);

28
src/model/Tag.ts Normal file
View File

@@ -0,0 +1,28 @@
import { Association, BelongsToGetAssociationMixin, BelongsToManyGetAssociationsMixin, DataTypes, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "@sequelize/core";
import { Post } from "./Post";
import { SqliteDialect } from '@sequelize/sqlite3';
import { Attribute, AutoIncrement, BelongsToMany, PrimaryKey, Unique } from "@sequelize/core/decorators-legacy";
export class Tag extends Model<InferAttributes<Tag>, InferCreationAttributes<Tag>> {
@PrimaryKey
@AutoIncrement
@Attribute(DataTypes.INTEGER)
@Unique
declare id: number;
/** Defined by {@link Post.postTags} */
declare taggedPosts?:NonAttribute<Post[]>;
declare user_id:ForeignKey<Tag>;
declare getPost: BelongsToManyGetAssociationsMixin<Tag>;
declare static associations: {
posts: Association<Post, Tag>;
};
}
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [Tag]
})

View File

@@ -1,91 +1,85 @@
import { Association, DataTypes, HasManyGetAssociationsMixin, HasOneCreateAssociationMixin, HasOneGetAssociationMixin, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "sequelize";
import { Association, Attributes, CreationAttributes, CreationOptional, DataTypes, HasManyGetAssociationsMixin, HasOneCreateAssociationMixin, HasOneGetAssociationMixin, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "@sequelize/core";
import { Post } from "./Post";
import { UserPerms } from "./UserPerms";
import { Auth } from "./Auth";
import {
PrimaryKey,
Attribute,
AutoIncrement,
NotNull,
BelongsTo,
Unique,
HasMany,
HasOne,
UpdatedAt,
CreatedAt,
} from '@sequelize/core/decorators-legacy';
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'db.sqlite'
});
import { SqliteDialect } from '@sequelize/sqlite3';
type UserCreationAttributes = {
username:string;
password:string;
perms?:Partial<InferAttributes<UserPerms>>
}
export class User extends Model<InferAttributes<User>, InferCreationAttributes<User>>{
declare id: number|null;
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
@Unique
declare id: CreationOptional<number>;
@Attribute(DataTypes.STRING)
declare username: string;
@Attribute(DataTypes.STRING)
declare password: string;
// Date thingies
@CreatedAt
declare createdAt: CreationOptional<Date>;
@UpdatedAt
declare updatedAt: CreationOptional<Date>;
// Associations
declare getAuthTokens:HasManyGetAssociationsMixin<Auth>;
declare getPosts:HasManyGetAssociationsMixin<Post>;
declare getPerms:HasOneGetAssociationMixin<UserPerms>;
declare createPerms:HasOneCreateAssociationMixin<UserPerms>;
declare perms?:NonAttribute<UserPerms>
/** Defined by {@link Auth.user} */
declare authtokens?:NonAttribute<Auth[]>
/** Defined by {@link UserPerms.user} */
declare perms?:CreationOptional<Partial<CreationAttributes<UserPerms>>>
/** Defined by {@link Post.user} */
declare posts?:CreationOptional<Post[]>
declare static associations: {
perms: Association<UserPerms,User>;
posts: Association<Post,User>
authtokens: Association<Auth,User>;
};
}
User.init(
{
id: {
allowNull: false,
autoIncrement: true,
type: DataTypes.INTEGER,
primaryKey: true,
unique: true,
},
username: {
allowNull: false,
type: DataTypes.STRING,
},
password: {
allowNull: false,
type: DataTypes.STRING,
},
},
{
defaultScope: {
attributes: {
exclude: ['password'],
},
include: [{ association: 'perms' }],
},
tableName: 'Users',
sequelize // passing the `sequelize` instance is required
const sequelize = new Sequelize({
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [User]
});
User.addScope('defaultScope',{
attributes: {
exclude: ['password', 'createdAt', 'updatedAt'],
}
);
Auth.belongsTo(User, {
foreignKey:'user_id',
targetKey:'id',
as: 'user',
})
User.hasMany(Auth, {
sourceKey: 'id',
foreignKey: 'user_id',
as: 'authtokens' // this determines the name in `associations`!
});
Post.belongsTo(User, {
foreignKey:'user_id',
targetKey:'id',
as: 'user'
})
User.hasMany(Post, {
sourceKey: 'id',
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.addScope('withPerms',{
include: [{association: 'perms' }]
})
User.sync();
Auth.sync();
Post.sync();
UserPerms.sync();
User.addScope('withAuthtokens',{
include: [{association: 'authtokens'}]
})

View File

@@ -1,32 +1,46 @@
import { CreationOptional, DataTypes, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "sequelize";
import { CreationOptional, DataTypes, ForeignKey, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize } from "@sequelize/core";
import { User } from "./User";
import { SqliteDialect } from '@sequelize/sqlite3';
import { Attribute, AutoIncrement, BelongsTo, CreatedAt, PrimaryKey, Table, Unique, UpdatedAt } from "@sequelize/core/decorators-legacy";
@Table({
tableName: "Perms"
})
export class UserPerms extends Model<InferAttributes<UserPerms>, InferCreationAttributes<UserPerms>> {
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
@Unique
declare id: CreationOptional<number>;
@BelongsTo(()=>User, { foreignKey: 'user_id', inverse: { as: 'perms', type: 'hasOne' } })
declare user:NonAttribute<User>;
@Attribute(DataTypes.INTEGER)
declare user_id:ForeignKey<User['id']>;
@Attribute(DataTypes.BOOLEAN)
declare isAdmin:CreationOptional<boolean>;
@CreatedAt
declare createdAt: CreationOptional<Date>;
@UpdatedAt
declare updatedAt: CreationOptional<Date>;
}
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'db.sqlite'
dialect: SqliteDialect,
storage: 'db.sqlite',
models: [UserPerms],
});
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
UserPerms.addScope('defaultScope',{
attributes: {
exclude: ['createdAt', 'updatedAt'],
}
});
UserPerms.addScope('withTimestamps',{
attributes: {
include: ['createdAt', 'updatedAt'],
}
},
{
tableName: 'Perms',
sequelize // passing the `sequelize` instance is required
});

View File

@@ -1,14 +1,15 @@
'use client'
import { Auth, User } from "@/model/sequelize/NewModels";
import { Auth } from "@/model/Auth";
import { User } from "@/model/User";
import { ReactNode, createContext } from "react";
import { InferAttributes } from "sequelize/types/model";
import { Attributes, InferAttributes } from "@sequelize/core";
export type AuthProps = {
test: string;
auth?: InferAttributes<Auth>
user?: InferAttributes<User>
auth?: Attributes<Auth>
user?: Attributes<User>
}
let p: AuthProps = {
test: "lorem",

3
src/util/DeepPartial.ts Normal file
View File

@@ -0,0 +1,3 @@
export type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;

View File

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