more refactoring
This commit is contained in:
parent
de148eaf19
commit
1971966099
@ -1,161 +1,148 @@
|
||||
'use server'
|
||||
"use server";
|
||||
|
||||
import { APIError, attemptAPIAction } from "@/util/api/error";
|
||||
import { sequelize, Bucket, Auth, Post, PostTag, Tag, User, dbSync } from "@/models";
|
||||
import { APIError, attemptAPIAction } from "@/util";
|
||||
import {
|
||||
sequelize,
|
||||
Bucket,
|
||||
Auth,
|
||||
Post,
|
||||
PostTag,
|
||||
Tag,
|
||||
User,
|
||||
dbSync,
|
||||
} from "@/models";
|
||||
import { cookies } from "next/headers";
|
||||
import { Attachment } from "@/models";
|
||||
import { UUID } from "crypto";
|
||||
import { mkdir, mkdirSync, writeFile } from "fs";
|
||||
import { where } from "@sequelize/core";
|
||||
import { addToNewBucketForPost } from "../../lib/actions/entityManagement/attachment/attachmentActions";
|
||||
|
||||
async function writeFilesToFS(uuid: UUID, files: any[]): Promise<{ success: boolean, filePaths: string[] }> {
|
||||
|
||||
type FileArrayEntryWithPromise = {
|
||||
name: string;
|
||||
content: Promise<ReadableStreamReadResult<Uint8Array>> | ReadableStreamReadResult<Uint8Array>
|
||||
}
|
||||
type FileArrayEntry = {
|
||||
name: string;
|
||||
content: ReadableStreamReadResult<Uint8Array>
|
||||
};
|
||||
|
||||
// Resolve promises
|
||||
const fileArray: FileArrayEntryWithPromise[] = await Promise.all(files.map((file: File) => {
|
||||
return { 'name': (() => file.name)(), 'content': file.stream().getReader().read() };
|
||||
}));
|
||||
|
||||
|
||||
|
||||
let finalFileArray: FileArrayEntry[] = await (
|
||||
async () => {
|
||||
for (let file in fileArray) {
|
||||
fileArray[file].content = await fileArray[file].content
|
||||
}
|
||||
return [...fileArray as FileArrayEntry[]]
|
||||
})();
|
||||
|
||||
// Make Bucket Directory
|
||||
mkdirSync(`./bucket/${uuid}/`, { recursive: true })
|
||||
|
||||
// Write files to filesystem
|
||||
for (let file in finalFileArray) {
|
||||
writeFile(`./bucket/${uuid}/${finalFileArray[file].name}`
|
||||
, Buffer.from(finalFileArray[file].content.value as Uint8Array)
|
||||
, (e) => { console.log(e) });
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
filePaths: finalFileArray.map((e) => e.name)
|
||||
}
|
||||
}
|
||||
|
||||
async function addToExistingBucket(bucketid: number): Promise<Bucket> {
|
||||
const bucket = await Bucket.findOne({
|
||||
where: { id: bucketid }, include: { association: Bucket.associations.posts }
|
||||
});
|
||||
if (!bucket) throw new APIError({ status: 500, responseText: "invalid bucketid" });
|
||||
return bucket;
|
||||
}
|
||||
|
||||
import {
|
||||
addToExistingBucket,
|
||||
addToNewBucketForPost,
|
||||
writeFilesToFS,
|
||||
} from "@/app/lib/actions/entityManagement/attachment/attachmentActions";
|
||||
import { Attributes } from "@sequelize/core";
|
||||
import { RequestCookie } from "next/dist/compiled/@edge-runtime/cookies";
|
||||
|
||||
export async function tryCreateAttachment(request: Request) {
|
||||
|
||||
// Make sure the DB is ready
|
||||
await dbSync;
|
||||
|
||||
// Prepare data
|
||||
const formData = await request.formData();
|
||||
const requestData: string | Object | undefined = formData.get('data')?.valueOf();
|
||||
const files: FormDataEntryValue[] = formData.getAll('files')
|
||||
const authCkie = await cookies().get("auth");
|
||||
const requestData: string | Object | undefined = formData
|
||||
.get("data")
|
||||
?.valueOf();
|
||||
const files: FormDataEntryValue[] = formData.getAll("files");
|
||||
const authCkie: RequestCookie | undefined = await cookies().get("auth");
|
||||
|
||||
// Sanity check auth cookie
|
||||
if (!authCkie || !authCkie.value) throw new APIError({ status: 500, responseText: "missing auth cookie" });
|
||||
if (!authCkie || !authCkie.value)
|
||||
throw new APIError({
|
||||
status: 500,
|
||||
responseText: "missing auth cookie",
|
||||
});
|
||||
|
||||
// Get JSON from the Cookie
|
||||
const cookieJSON = authCkie.value;
|
||||
const authObject = JSON.parse(cookieJSON);
|
||||
const cookieJSON: string = authCkie.value;
|
||||
const authObject:Attributes<Auth> = JSON.parse(cookieJSON);
|
||||
|
||||
// Fetch User Auth from the database
|
||||
// Fetch User Auth from thse database
|
||||
const auth = await Auth.findOne({
|
||||
include: [
|
||||
{
|
||||
model: User.withScope(['withPerms']),
|
||||
model: User.withScope(["withPerms"]),
|
||||
attributes: {
|
||||
exclude: ['username', 'password', 'updatedAt', 'createdAt']
|
||||
}
|
||||
}
|
||||
exclude: ["username", "password", "updatedAt", "createdAt"],
|
||||
},
|
||||
},
|
||||
],
|
||||
where: { token: authObject.token }
|
||||
where: { token: authObject.token },
|
||||
});
|
||||
|
||||
|
||||
// Sanity check the auth and associated user for authorization
|
||||
if (!auth
|
||||
|| !auth.user) throw new APIError({ status: 401, responseText: "Authentication Error" });
|
||||
if (!auth.user.id) throw new APIError({ status: 401, responseText: "Missing user id" });
|
||||
if (!auth.user.perms
|
||||
|| !auth.user.perms.isAdmin) throw new APIError({ status: 401, responseText: `Unauthorized` });
|
||||
if (!auth || !auth.user)
|
||||
throw new APIError({
|
||||
status: 401,
|
||||
responseText: "Authentication Error",
|
||||
});
|
||||
if (!auth.user.id)
|
||||
throw new APIError({ status: 401, responseText: "Missing user id" });
|
||||
if (!auth.user.perms || !auth.user.perms.isAdmin)
|
||||
throw new APIError({ status: 401, responseText: `Unauthorized` });
|
||||
// Handle incomplete data or other problems
|
||||
if (!files) throw new APIError({ status: 500, responseText: "Missing file" });
|
||||
if (!formData) throw new APIError({ status: 500, responseText: "Empty request body" });
|
||||
if (!requestData) throw new APIError({ status: 500, responseText: "Missing request data" });
|
||||
if (!(typeof requestData == "string")) throw new APIError({ status: 500, responseText: "Malformed request data" });
|
||||
|
||||
if (!files)
|
||||
throw new APIError({ status: 500, responseText: "Missing file" });
|
||||
if (!formData)
|
||||
throw new APIError({ status: 500, responseText: "Empty request body" });
|
||||
if (!requestData)
|
||||
throw new APIError({
|
||||
status: 500,
|
||||
responseText: "Missing request data",
|
||||
});
|
||||
if (!(typeof requestData == "string"))
|
||||
throw new APIError({
|
||||
status: 500,
|
||||
responseText: "Malformed request data",
|
||||
});
|
||||
|
||||
// Parse JSON
|
||||
const data = JSON.parse(requestData);
|
||||
|
||||
// Get or create bucket
|
||||
const bucket: Bucket = (data.postid && !data.bucketid)
|
||||
const bucket: Bucket =
|
||||
data.postid && !data.bucketid
|
||||
? await addToNewBucketForPost(data.postid)
|
||||
: await addToExistingBucket(data.bucketid);
|
||||
|
||||
// Write files to bucket and store as attachments in DB
|
||||
const writeResult = await writeFilesToFS(bucket.id, files);
|
||||
// Handle failure
|
||||
if (!writeResult.success) throw new APIError({ status: 500, responseText: "Error writing files to Bucket" });
|
||||
if (!writeResult.success)
|
||||
throw new APIError({
|
||||
status: 500,
|
||||
responseText: "Error writing files to Bucket",
|
||||
});
|
||||
|
||||
// Write attachments to db
|
||||
const attachments = ((writeResult).filePaths.map(async (fp) => {
|
||||
return (await Attachment.create(
|
||||
const attachments = writeResult.filePaths.map(async (fp) => {
|
||||
return await Attachment.create(
|
||||
{
|
||||
bucket_id: bucket.id,
|
||||
filename: fp
|
||||
filename: fp,
|
||||
},
|
||||
{ include: Attachment.associations.bucket }
|
||||
));
|
||||
}))
|
||||
);
|
||||
});
|
||||
attachments;
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
bucket: await Bucket.findOne({
|
||||
where: { id: bucket.id },
|
||||
include: [Bucket.associations.posts, Bucket.associations.attachments]
|
||||
})
|
||||
include: [
|
||||
Bucket.associations.posts,
|
||||
Bucket.associations.attachments,
|
||||
],
|
||||
}),
|
||||
}),
|
||||
{ status: 200 }
|
||||
);
|
||||
}
|
||||
|
||||
export async function tryFetchAttachments(request: Request) {
|
||||
|
||||
await Post.sync();
|
||||
|
||||
const foundPosts = await Post.findAll({
|
||||
include: [
|
||||
{
|
||||
association: Post.associations.user,
|
||||
attributes: { exclude: ['password', 'createdAt', 'updatedAt'] }
|
||||
}, {
|
||||
association: Post.associations.postTags
|
||||
}]
|
||||
attributes: { exclude: ["password", "createdAt", "updatedAt"] },
|
||||
},
|
||||
{
|
||||
association: Post.associations.postTags,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return new Response(JSON.stringify(foundPosts), { status: 200 });
|
||||
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
|
||||
@ -1,83 +1,72 @@
|
||||
'use server'
|
||||
"use server";
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
import { APIError} from "@/util/api/error"
|
||||
import { UserAuth, parseBasicAuth, getAssociatedUser } from "@/util/api/user"
|
||||
import { APIError, UserAuth, parseBasicAuth, getAssociatedUser } from "@/util";
|
||||
import { Auth, User } from "@/models";
|
||||
|
||||
|
||||
async function tryAuth(request:Request){
|
||||
|
||||
async function tryAuth(request: Request) {
|
||||
// await User.sync();
|
||||
await Auth.sync();
|
||||
|
||||
const auth:string|null = request.headers.get("authorization");
|
||||
const auth: string | null = request.headers.get("authorization");
|
||||
|
||||
if(!auth){
|
||||
return new Response("unauthorized",{status:403});
|
||||
if (!auth) {
|
||||
return new Response("unauthorized", { status: 403 });
|
||||
}
|
||||
|
||||
const userAuth = parseBasicAuth(auth);
|
||||
const user = await getAssociatedUser(userAuth);
|
||||
|
||||
if (!user || !user.id)
|
||||
return new Response("error",{status:500});
|
||||
if (!user || !user.id) return new Response("error", { status: 500 });
|
||||
|
||||
const authentication = await Auth.create({
|
||||
user_id: user.id,
|
||||
})
|
||||
});
|
||||
|
||||
console.log('ok');
|
||||
console.log("ok");
|
||||
const foundAuth = await Auth.findOne({
|
||||
include: {
|
||||
model: User,
|
||||
as: 'user'
|
||||
as: "user",
|
||||
},
|
||||
where: {
|
||||
user_id: user.id
|
||||
}
|
||||
})
|
||||
console.log('ok2');
|
||||
user_id: user.id,
|
||||
},
|
||||
});
|
||||
console.log("ok2");
|
||||
|
||||
if(!foundAuth)
|
||||
return new Response("error",{status:500});
|
||||
if (!foundAuth) return new Response("error", { status: 500 });
|
||||
|
||||
const usr = foundAuth.user;
|
||||
|
||||
|
||||
|
||||
const authUser = await authentication.getUser();
|
||||
|
||||
// @ts-ignore
|
||||
cookies().set('auth', JSON.stringify(authentication));
|
||||
cookies().set("auth", JSON.stringify(authentication));
|
||||
|
||||
return new Response(
|
||||
JSON.stringify(
|
||||
{
|
||||
JSON.stringify({
|
||||
credentials: userAuth,
|
||||
auth: authentication,
|
||||
user: authUser,
|
||||
foundAuth: foundAuth
|
||||
foundAuth: foundAuth,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers:{
|
||||
"Content-Type": "text/JSON"
|
||||
}
|
||||
headers: {
|
||||
"Content-Type": "text/JSON",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function POST(request:Request){
|
||||
try{
|
||||
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{
|
||||
} catch (e) {
|
||||
if (e instanceof APIError) {
|
||||
return new Response(e.info.responseText, { status: e.info.status });
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import { UserAuth, parseBasicAuth, getAssociatedUser } from "@/util/api/user"
|
||||
import { Attachment, Auth, Bucket, DBState, Post, PostTag, Project, Tag, User, UserPerms,dbSync,sequelize} from "@/models";
|
||||
import Sequelize, { CreationAttributes, DataTypes } from "@sequelize/core";
|
||||
import { SqliteColumnsDescription, SqliteDialect, SqliteQueryInterface } from "@sequelize/sqlite3";
|
||||
import { hashPassword } from "@/util/Auth";
|
||||
import { hashpassword } from "@/util/auth";
|
||||
import { copyFile, readFileSync } from "fs";
|
||||
import path from "path";
|
||||
import { Attributes } from '@sequelize/core';
|
||||
@ -19,7 +19,7 @@ async function seedUsers(qif: SqliteQueryInterface<SqliteDialect>){
|
||||
const json: {users: CreationAttributes<User>[]} = JSON.parse(Buffer.from(readFileSync(fp).valueOf()).toString());
|
||||
|
||||
const users = json.users.map(async user=>{
|
||||
user.password = await hashPassword(user.password);
|
||||
user.password = await hashpassword(user.password);
|
||||
return user;
|
||||
})
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
import { APIError } from "@/util/api/error";
|
||||
import { UserAuth } from "@/util/api/user";
|
||||
import { Attachment, Auth, Bucket, DBState, Post, PostTag, Project, Tag, User, UserPerms, addUserScopes, dbSync,sequelize} from "@/models";
|
||||
import { hashPassword } from "@/util/Auth";
|
||||
import { hashpassword } from "@/util/auth";
|
||||
|
||||
|
||||
// Attempt to register a new User
|
||||
@ -32,7 +32,7 @@ async function attemptRegister(request:Request){
|
||||
// Hash the password and create a new user in the database
|
||||
const user = await User.create({
|
||||
username: requestBody.username,
|
||||
password: await hashPassword(requestBody.password),
|
||||
password: await hashpassword(requestBody.password),
|
||||
perms:{
|
||||
isAdmin: false
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use server'
|
||||
|
||||
import { constructAPIUrl } from "@/util/Utils"
|
||||
import { constructAPIUrl } from "@/util/url";
|
||||
import { cookies } from "next/headers"
|
||||
import { parseSetCookie } from "@/util/parseSetCookie";
|
||||
import makeFetchCookie from 'fetch-cookie';
|
||||
|
||||
@ -1,13 +1,65 @@
|
||||
'use server';
|
||||
import { APIError } from "@/util/api/error";
|
||||
import { Bucket, Post } from "@/models";
|
||||
import { randomUUID } from "crypto";
|
||||
import { randomUUID, UUID } from "crypto";
|
||||
import { mkdirSync, writeFile } from "fs";
|
||||
|
||||
export async function addToNewBucketForPost(postid: number): Promise<Bucket> {
|
||||
Post.sync();
|
||||
const post = await Post.findOne({ where: { id: postid } });
|
||||
const post: Post | null = await Post.findOne({ where: { id: postid } });
|
||||
|
||||
if (!post) throw new APIError({ status: 500, responseText: "invalid postid" });
|
||||
const bucket = await post.createBucket({ id: randomUUID() });
|
||||
return bucket;
|
||||
}
|
||||
|
||||
export async function writeFilesToFS(uuid: UUID, files: any[]): Promise<{ success: boolean, filePaths: string[] }> {
|
||||
|
||||
type FileArrayEntryWithPromise = {
|
||||
name: string;
|
||||
content: Promise<ReadableStreamReadResult<Uint8Array>> | ReadableStreamReadResult<Uint8Array>
|
||||
}
|
||||
type FileArrayEntry = {
|
||||
name: string;
|
||||
content: ReadableStreamReadResult<Uint8Array>
|
||||
};
|
||||
|
||||
// Resolve promises
|
||||
const fileArray: FileArrayEntryWithPromise[] = await Promise.all(files.map((file: File) => {
|
||||
return { 'name': (() => file.name)(), 'content': file.stream().getReader().read() };
|
||||
}));
|
||||
|
||||
|
||||
|
||||
let finalFileArray: FileArrayEntry[] = await (
|
||||
async () => {
|
||||
for (let file in fileArray) {
|
||||
fileArray[file].content = await fileArray[file].content
|
||||
}
|
||||
return [...fileArray as FileArrayEntry[]]
|
||||
})();
|
||||
|
||||
// Make Bucket Directory
|
||||
mkdirSync(`./bucket/${uuid}/`, { recursive: true })
|
||||
|
||||
// Write files to filesystem
|
||||
for (let file in finalFileArray) {
|
||||
writeFile(`./bucket/${uuid}/${finalFileArray[file].name}`
|
||||
, Buffer.from(finalFileArray[file].content.value as Uint8Array)
|
||||
, (e) => { console.log(e) });
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
filePaths: finalFileArray.map((e) => e.name)
|
||||
}
|
||||
}
|
||||
|
||||
export async function addToExistingBucket(bucketid: number): Promise<Bucket> {
|
||||
const bucket = await Bucket.findOne({
|
||||
where: { id: bucketid },
|
||||
include: { association: Bucket.associations.posts },
|
||||
});
|
||||
if (!bucket)
|
||||
throw new APIError({ status: 500, responseText: "invalid bucketid" });
|
||||
return bucket;
|
||||
}
|
||||
@ -6,8 +6,8 @@ import ArticlePreview from "@/components/shared/news/article-preview"
|
||||
import ReactDOM from "react";
|
||||
import "/public/global.css"
|
||||
import "./index.css"
|
||||
import { Post } from "@/model/Post";
|
||||
import { constructAPIUrl } from "@/util/Utils";
|
||||
import { Post } from "@/models";
|
||||
import { constructAPIUrl } from "@/util";
|
||||
import Link from "next/link";
|
||||
import { Attributes } from "@sequelize/core";
|
||||
|
||||
|
||||
@ -4,7 +4,13 @@ import EntityManagementTable from "../EntityManagementTable";
|
||||
import toast from "react-hot-toast";
|
||||
import { EditorRenderer, EditorState, PostTableCallbacks } from "./PostEditor";
|
||||
import { Attributes, InferAttributes } from "@sequelize/core";
|
||||
import { Project, Post, Bucket, User, PostAttributesWithBuckets } from "@/models";
|
||||
import {
|
||||
Project,
|
||||
Post,
|
||||
Bucket,
|
||||
User,
|
||||
PostAttributesWithBuckets,
|
||||
} from "@/models";
|
||||
import { handleActionResult } from "@/app/lib/actions/clientActionHandler";
|
||||
|
||||
import {
|
||||
@ -13,16 +19,15 @@ import {
|
||||
PostServerActions,
|
||||
} from "@/app/lib/actions/entityManagement/post/postActions";
|
||||
import { PostViewProps } from "@/views/admin/ClientPostView";
|
||||
import { aifa } from "@/util/Utils";
|
||||
import { StateHook } from "@/util/state/stateUtils";
|
||||
import { aifa } from "@/util/utils";
|
||||
import { StateHook } from "@/util/state";
|
||||
|
||||
export type PostTableStateProps = {
|
||||
posts:StateHook<GetPostsAttributes[]>,
|
||||
editor:StateHook<EditorState>
|
||||
}
|
||||
|
||||
export type PostTableProps = PostViewProps & {state:PostTableStateProps};
|
||||
posts: StateHook<GetPostsAttributes[]>;
|
||||
editor: StateHook<EditorState>;
|
||||
};
|
||||
|
||||
export type PostTableProps = PostViewProps & { state: PostTableStateProps };
|
||||
|
||||
export default function PostTable({
|
||||
children,
|
||||
@ -32,8 +37,6 @@ export default function PostTable({
|
||||
actions,
|
||||
state,
|
||||
}: PostTableProps) {
|
||||
|
||||
|
||||
// Define editor controls
|
||||
const editorControls = {
|
||||
closeEditor: () => {
|
||||
@ -93,10 +96,7 @@ export default function PostTable({
|
||||
};
|
||||
|
||||
return (
|
||||
<EntityManagementTable
|
||||
entityName="Post"
|
||||
headings={headings}
|
||||
>
|
||||
<EntityManagementTable entityName="Post" headings={headings}>
|
||||
{state.posts.state.map((post: GetPostsAttributes) => (
|
||||
<React.Fragment key={`postrow-${post.id}`}>
|
||||
<tr>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
import { serverAttemptAuthenticateUser } from "@/app/lib/actions/actions";
|
||||
import { AuthContext } from "@/providers/providers";
|
||||
import { constructAPIUrl } from "@/util/Utils";
|
||||
import { constructAPIUrl } from "@/util/url";
|
||||
import { createContext, useState } from "react";
|
||||
import { useFormState, useFormStatus } from "react-dom";
|
||||
|
||||
|
||||
@ -1,20 +1,34 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import { useRef, MutableRefObject, useLayoutEffect, ChangeEventHandler, useState } from "react";
|
||||
import { StateHook } from '../../../util/types/StateHook';
|
||||
import {
|
||||
useRef,
|
||||
MutableRefObject,
|
||||
useLayoutEffect,
|
||||
ChangeEventHandler,
|
||||
useState,
|
||||
} from "react";
|
||||
import { StateHook } from "@/util";
|
||||
|
||||
export function EntityEditorTextArea({contentHook, className}: {contentHook:StateHook<string>, className:string}){
|
||||
|
||||
let textbox: any = useRef(undefined);
|
||||
|
||||
// Autosize the text area
|
||||
function textAreaAutoSize(
|
||||
// Autosize the text area
|
||||
function textAreaAutoSize(
|
||||
textbox: MutableRefObject<HTMLTextAreaElement>
|
||||
): void {
|
||||
): void {
|
||||
if (!textbox.current || !textbox.current.style) return;
|
||||
textbox.current.style.height = "fit-content";
|
||||
textbox.current.style.height = `${textbox.current.scrollHeight}px`;
|
||||
}
|
||||
}
|
||||
|
||||
type EntityEditorTextAreaProps = {
|
||||
contentHook: StateHook<string>;
|
||||
className: string;
|
||||
};
|
||||
|
||||
export function EntityEditorTextArea({
|
||||
contentHook,
|
||||
className,
|
||||
}: EntityEditorTextAreaProps) {
|
||||
let textbox: any = useRef(undefined);
|
||||
|
||||
useLayoutEffect(() => textAreaAutoSize(textbox));
|
||||
|
||||
// Handle user input on the text area by updating state and autosizing the textfield
|
||||
@ -23,7 +37,8 @@ export function EntityEditorTextArea({contentHook, className}: {contentHook:Stat
|
||||
textAreaAutoSize(textbox); // Autosize the text area
|
||||
};
|
||||
|
||||
return <textarea
|
||||
return (
|
||||
<textarea
|
||||
key="input-content"
|
||||
onChange={onTextAreaChange}
|
||||
ref={textbox}
|
||||
@ -31,4 +46,5 @@ export function EntityEditorTextArea({contentHook, className}: {contentHook:Stat
|
||||
style={{ height: "100%" }}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -8,7 +8,7 @@ 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";
|
||||
import { truncateString } from "@/util/utils";
|
||||
// @ts-ignore
|
||||
import { MDXRemote } from "next-mdx-remote/rsc";
|
||||
import { ExampleComponent } from "./article";
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
'server only'
|
||||
|
||||
import { hash, compare } from "bcrypt";
|
||||
|
||||
|
||||
export async function validatePassword(password:string, hashString:string){
|
||||
const result = await compare(password, hashString);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function hashPassword(password:string){
|
||||
const hashString = await hash(password, 10);
|
||||
return hashString;
|
||||
}
|
||||
|
||||
export default { validatePassword, hashPassword };
|
||||
@ -1,25 +1,6 @@
|
||||
'server only'
|
||||
import { ReactNode } from "react";
|
||||
import Gens from "./gens";
|
||||
// import Auth from "./Auth";
|
||||
|
||||
|
||||
function getAPIEnv(){
|
||||
return {
|
||||
'schema': process.env.API_SCHEMA,
|
||||
'host': process.env.API_HOST,
|
||||
'port': process.env.API_PORT,
|
||||
'basepath': process.env.API_BASEPATH
|
||||
};
|
||||
}
|
||||
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) + "...";
|
||||
@ -29,5 +10,5 @@ function truncateString(str:string = '', num:number = 255) {
|
||||
}
|
||||
|
||||
|
||||
export { Gens, constructAPIUrl, constructUrl, truncateString }
|
||||
export { Gens, truncateString }
|
||||
export const aifa = (a: ReactNode, b: ReactNode) => (a ? a : b);
|
||||
|
||||
2
src/util/api/index.ts
Normal file
2
src/util/api/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './error';
|
||||
export * from './user';
|
||||
@ -1,34 +1,44 @@
|
||||
// import { MUser } from "@/model/sequelize/User";
|
||||
// import { MAuth } from "@/model/sequelize/Auth";
|
||||
|
||||
import { validatePassword } from "@/util/Auth";
|
||||
import { validatepassword } from "@/util/auth";
|
||||
import { APIError } from "@/util/api/error";
|
||||
import { User } from "@/models";
|
||||
|
||||
export function parseBasicAuth(authb64:string):UserAuth
|
||||
{
|
||||
const authString:string = Buffer.from(authb64.split(" ")[1] as any, "base64").toString("utf8");
|
||||
var userAuth:UserAuth = {
|
||||
username:authString.split(":")[0] as any,
|
||||
password:authString.split(":")[1] as any
|
||||
export function parseBasicAuth(authb64: string): UserAuth {
|
||||
const authString: string = Buffer.from(
|
||||
authb64.split(" ")[1] as any,
|
||||
"base64"
|
||||
).toString("utf8");
|
||||
var userAuth: UserAuth = {
|
||||
username: authString.split(":")[0] as any,
|
||||
password: authString.split(":")[1] as any,
|
||||
};
|
||||
return userAuth
|
||||
return userAuth;
|
||||
}
|
||||
|
||||
export type UserAuth = {
|
||||
username: string,
|
||||
password: string
|
||||
}
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export async function getAssociatedUser(auth:UserAuth)
|
||||
{
|
||||
let foundUser = await User.findOne({ attributes: {include: ['password']}, where: {username: auth.username} });
|
||||
export async function getAssociatedUser(auth: UserAuth) {
|
||||
let foundUser = await User.findOne({
|
||||
attributes: { include: ["password"] },
|
||||
where: { username: auth.username },
|
||||
});
|
||||
|
||||
if (!foundUser)
|
||||
throw new APIError({status: 401, responseText:"Unauthorized: Invalid Username"});
|
||||
throw new APIError({
|
||||
status: 401,
|
||||
responseText: "Unauthorized: Invalid Username",
|
||||
});
|
||||
|
||||
if (!(await validatePassword(auth.password, foundUser.password)))
|
||||
throw new APIError({status: 401, responseText:"Unauthorized: Invalid Password"});
|
||||
if (!(await validatepassword(auth.password, foundUser.password)))
|
||||
throw new APIError({
|
||||
status: 401,
|
||||
responseText: "Unauthorized: Invalid Password",
|
||||
});
|
||||
|
||||
return foundUser;
|
||||
}
|
||||
8
src/util/auth/hashpassword.ts
Normal file
8
src/util/auth/hashpassword.ts
Normal file
@ -0,0 +1,8 @@
|
||||
'server only'
|
||||
|
||||
import { hash } from "bcrypt";
|
||||
|
||||
export async function hashpassword(password:string){
|
||||
const hashString = await hash(password, 10);
|
||||
return hashString;
|
||||
}
|
||||
2
src/util/auth/index.ts
Normal file
2
src/util/auth/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './hashpassword';
|
||||
export * from './validatepassword';
|
||||
9
src/util/auth/validatepassword.ts
Normal file
9
src/util/auth/validatepassword.ts
Normal file
@ -0,0 +1,9 @@
|
||||
'server only';
|
||||
import { compare } from "bcrypt";
|
||||
|
||||
|
||||
|
||||
export async function validatepassword(password: string, hashString: string) {
|
||||
const result = await compare(password, hashString);
|
||||
return result;
|
||||
}
|
||||
10
src/util/getAPIEnv.ts
Normal file
10
src/util/getAPIEnv.ts
Normal file
@ -0,0 +1,10 @@
|
||||
'server only';
|
||||
// import Auth from "./Auth";
|
||||
export function getAPIEnv() {
|
||||
return {
|
||||
'schema': process.env.API_SCHEMA,
|
||||
'host': process.env.API_HOST,
|
||||
'port': process.env.API_PORT,
|
||||
'basepath': process.env.API_BASEPATH
|
||||
};
|
||||
}
|
||||
10
src/util/index.ts
Normal file
10
src/util/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export * from './api';
|
||||
export * from './auth';
|
||||
export * from './Cookies';
|
||||
export * from './DeepPartial';
|
||||
export * from './gens';
|
||||
export * from './getAPIEnv';
|
||||
export * from './parseSetCookie';
|
||||
export * from './state';
|
||||
export * from './url';
|
||||
export * from './utils';
|
||||
2
src/util/state/index.ts
Normal file
2
src/util/state/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './statetypes';
|
||||
export * from './stateutils';
|
||||
@ -1,12 +1,4 @@
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
export type StateHook<T> = {
|
||||
state: T;
|
||||
setState: Dispatch<SetStateAction<T>>;
|
||||
};
|
||||
export type StateHookArray<T> = [
|
||||
T,Dispatch<SetStateAction<T>>
|
||||
]
|
||||
import { StateHookArray, StateHook } from "./statetypes";
|
||||
|
||||
export function parseStateHook<T>(hook:StateHookArray<T>):StateHook<T>{
|
||||
const stateHook:Partial<StateHook<T>> = {};
|
||||
|
||||
9
src/util/state/statetypes.ts
Normal file
9
src/util/state/statetypes.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
export type StateHook<T> = {
|
||||
state: T;
|
||||
setState: Dispatch<SetStateAction<T>>;
|
||||
};
|
||||
export type StateHookArray<T> = [
|
||||
T,Dispatch<SetStateAction<T>>
|
||||
]
|
||||
1
src/util/url/index.ts
Normal file
1
src/util/url/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./urlConstructor"
|
||||
12
src/util/url/urlConstructor.ts
Normal file
12
src/util/url/urlConstructor.ts
Normal file
@ -0,0 +1,12 @@
|
||||
'use server'
|
||||
|
||||
import { getAPIEnv } from "../getAPIEnv";
|
||||
|
||||
export function constructAPIUrl(endpoint:string){
|
||||
const { schema, host, port, basepath } = getAPIEnv();
|
||||
return `${schema}://${host}:${port}/${basepath}/${endpoint}`
|
||||
}
|
||||
export function constructUrl(endpoint:string){
|
||||
const { schema, host, port, basepath } = getAPIEnv();
|
||||
return `${schema}://${host}:${port}/${endpoint}`
|
||||
}1
|
||||
@ -11,7 +11,7 @@ import { EditorState } from "@/components/client/admin/PostEditor";
|
||||
import { Project } from "@/models";
|
||||
import { Dispatch, ReactNode, SetStateAction, useState } from "react";
|
||||
import { Attributes } from "@sequelize/core";
|
||||
import { parseStateHook, StateHookArray } from "@/util/state/stateUtils";
|
||||
import { parseStateHook } from "@/util/state";
|
||||
|
||||
export type PostViewProps = {
|
||||
children?: ReactNode;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
cache: "no-store";
|
||||
|
||||
import { tryFetchPosts } from "@/app/api/post/route";
|
||||
import { constructAPIUrl } from "@/util/Utils";
|
||||
import { constructAPIUrl } from "@/util/utils";
|
||||
import { ReactNode, useEffect } from "react";
|
||||
import EntityManagementTable from "../../components/client/EntityManagementTable";
|
||||
import PostTable from "@/components/client/admin/PostTable";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user