Compare commits

...

3 commits

Author SHA1 Message Date
Imbus
f7a8069859 Captcha error silence 2023-11-22 15:40:29 +01:00
Imbus
cc712a0e99 Formatting 2023-11-22 15:31:58 +01:00
Imbus
22a3ca1769 Restructure 2023-11-22 15:29:27 +01:00
25 changed files with 602 additions and 440 deletions

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
"preview": "vite preview", "preview": "vite preview",
"format": "prettier --config .prettierrc '**/*.ts' '**/*.tsx' '**/*.js' '**/*.json' --write",
"fmt": "prettier --config .prettierrc 'src/**/*.ts' 'src/**/*.tsx' --write && npx eslint --fix 'src/**/*.ts' 'src/**/*.tsx'" "fmt": "prettier --config .prettierrc 'src/**/*.ts' 'src/**/*.tsx' --write && npx eslint --fix 'src/**/*.ts' 'src/**/*.tsx'"
}, },
"dependencies": { "dependencies": {

View file

@ -3,4 +3,4 @@ export default {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
}, },
} };

View file

@ -1,7 +1,7 @@
import { JSXElement, Show, createSignal, useContext } from "solid-js"; import { JSXElement, Show, createSignal, useContext } from "solid-js";
import { LoginContext, ModalContext } from "../GlobalState"; import { LoginContext, ModalContext } from "../Context/GlobalState";
import { AuthResponse, submitLogin } from "../api"; import { AuthResponse, submitLogin } from "../Util/api";
export function LoginForm(): JSXElement { export function LoginForm(): JSXElement {
const modal_ctx = useContext(ModalContext)!; const modal_ctx = useContext(ModalContext)!;

View file

@ -1,7 +1,7 @@
import { JSXElement, Show, useContext } from "solid-js"; import { JSXElement, Show, useContext } from "solid-js";
import { LoginContext, ModalContext } from "./GlobalState"; import { LoginContext, ModalContext } from "../Context/GlobalState";
import { UserCircle } from "./Icons"; import { UserCircle } from "../Util/Icons";
export function LoginButton(): JSXElement { export function LoginButton(): JSXElement {
const modal_ctx = useContext(ModalContext)!; const modal_ctx = useContext(ModalContext)!;

View file

@ -1,8 +1,8 @@
import { A } from "@solidjs/router"; import { A } from "@solidjs/router";
import { JSXElement, Show, useContext } from "solid-js"; import { JSXElement, Show, useContext } from "solid-js";
import { LoginContext } from "./GlobalState"; import { LoginContext } from "../Context/GlobalState";
import { Home, Plus } from "./Icons"; import { Home, Plus } from "../Util/Icons";
// Represents a single list item in the menu bar // Represents a single list item in the menu bar
export function MenuItem(props: { export function MenuItem(props: {

View file

@ -1,8 +1,8 @@
import { useNavigate } from "@solidjs/router"; import { useNavigate } from "@solidjs/router";
import { JSXElement, Show, createSignal, onMount, useContext } from "solid-js"; import { JSXElement, Show, createSignal, onMount, useContext } from "solid-js";
import { LoginContext } from "./GlobalState"; import { LoginContext } from "../Context/GlobalState";
import { NewPost, createPost } from "./api"; import { NewPost, createPost } from "../Util/api";
export function NewPostInputArea(): JSXElement { export function NewPostInputArea(): JSXElement {
const [content, setContent] = createSignal(""); const [content, setContent] = createSignal("");

View file

@ -1,8 +1,8 @@
import { useNavigate } from "@solidjs/router"; import { useNavigate } from "@solidjs/router";
import { For, JSXElement, Show, createSignal } from "solid-js"; import { For, JSXElement, Show, createSignal } from "solid-js";
import { Arrow, loadSpinner } from "./Icons"; import { Arrow, loadSpinner } from "../Util/Icons";
import { Post, getPosts } from "./api"; import { Post, getPosts } from "../Util/api";
export function Posts(): JSXElement { export function Posts(): JSXElement {
const [posts, setPosts] = createSignal([] as Post[]); const [posts, setPosts] = createSignal([] as Post[]);

View file

@ -1,7 +1,7 @@
import { JSXElement, Show, createSignal, useContext } from "solid-js"; import { JSXElement, Show, createSignal, useContext } from "solid-js";
import { LoginContext, ModalContext } from "../GlobalState"; import { LoginContext, ModalContext } from "../Context/GlobalState";
import { AuthResponse, submitRegistration } from "../api"; import { AuthResponse, submitRegistration } from "../Util/api";
export function RegisterForm(): JSXElement { export function RegisterForm(): JSXElement {
const modal_ctx = useContext(ModalContext)!; const modal_ctx = useContext(ModalContext)!;

View file

@ -1,9 +1,9 @@
import { useParams } from "@solidjs/router"; import { useParams } from "@solidjs/router";
import { JSXElement, Show, Suspense, createResource } from "solid-js"; import { JSXElement, Show, Suspense, createResource } from "solid-js";
import { loadSpinner } from "./Icons"; import { loadSpinner } from "../Util/Icons";
import { getPost } from "../Util/api";
import { PostSegment } from "./Posts"; import { PostSegment } from "./Posts";
import { getPost } from "./api";
export function SinglePost(): JSXElement { export function SinglePost(): JSXElement {
const params = useParams(); const params = useParams();

View file

@ -17,7 +17,7 @@ export function Footer(): JSXElement {
viewBox="0 0 24 24" viewBox="0 0 24 24"
class="fill-current" class="fill-current"
> >
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path> <path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" />
</svg> </svg>
</a> </a>
<a> <a>
@ -28,7 +28,7 @@ export function Footer(): JSXElement {
viewBox="0 0 24 24" viewBox="0 0 24 24"
class="fill-current" class="fill-current"
> >
<path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path> <path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z" />
</svg> </svg>
</a> </a>
<a> <a>
@ -39,7 +39,7 @@ export function Footer(): JSXElement {
viewBox="0 0 24 24" viewBox="0 0 24 24"
class="fill-current" class="fill-current"
> >
<path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path> <path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z" />
</svg> </svg>
</a> </a>
</div> </div>

View file

@ -1,8 +1,8 @@
import { JSXElement, Show, onCleanup, useContext } from "solid-js"; import { JSXElement, Show, onCleanup, useContext } from "solid-js";
import { ModalContext } from "./GlobalState"; import { LoginForm } from "../Components/Login";
import { LoginForm } from "./RegLogin/Login"; import { RegisterForm } from "../Components/Register";
import { RegisterForm } from "./RegLogin/Register"; import { ModalContext } from "../Context/GlobalState";
export function LoginModal(): JSXElement { export function LoginModal(): JSXElement {
const modal_ctx = useContext(ModalContext)!; const modal_ctx = useContext(ModalContext)!;

View file

@ -1,9 +1,9 @@
import { A } from "@solidjs/router"; import { A } from "@solidjs/router";
import { JSXElement } from "solid-js"; import { JSXElement } from "solid-js";
import { Flake } from "./Icons"; import { LoginButton } from "../Components/LoginButton";
import { LoginButton } from "./LoginButton"; import { Menu } from "../Components/Menu";
import { Menu } from "./Menu"; import { Flake } from "../Util/Icons";
export function Navbar(): JSXElement { export function Navbar(): JSXElement {
return ( return (

View file

@ -1,9 +1,9 @@
import { Route, Routes } from "@solidjs/router"; import { Route, Routes } from "@solidjs/router";
import { JSXElement } from "solid-js"; import { JSXElement } from "solid-js";
import { NewPostInputArea } from "./NewPost"; import { NewPostInputArea } from "../Components/NewPost";
import { Posts } from "./Posts"; import { Posts } from "../Components/Posts";
import { SinglePost } from "./SinglePost"; import { SinglePost } from "../Components/SinglePost";
// Primary is the section of the page that holds the main content // Primary is the section of the page that holds the main content
export function Primary(): JSXElement { export function Primary(): JSXElement {

View file

@ -1,10 +1,10 @@
import { JSXElement } from "solid-js"; import { JSXElement } from "solid-js";
import { GlobalStateProvider } from "./GlobalState"; import { GlobalStateProvider } from "../Context/GlobalState";
import { Footer } from "./Footer";
import { LoginModal } from "./LoginModal"; import { LoginModal } from "./LoginModal";
import { Navbar } from "./Navbar"; import { Navbar } from "./Navbar";
import { Primary } from "./Primary"; import { Primary } from "./Primary";
import { Footer } from "./Footer";
function Root(): JSXElement { function Root(): JSXElement {
return ( return (
@ -14,7 +14,7 @@ function Root(): JSXElement {
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<Navbar /> <Navbar />
<LoginModal /> <LoginModal />
<div class="flex w-full min-h-[65vh] flex-col items-center mb-8 space-y-2 px-2 md:max-w-3xl"> <div class="mb-8 flex min-h-[65vh] w-full flex-col items-center space-y-2 px-2 md:max-w-3xl">
<Primary /> <Primary />
</div> </div>
<Footer /> <Footer />

View file

@ -47,7 +47,7 @@ export function GlobalStateProvider(props: {
return token() != "" && username() != ""; return token() != "" && username() != "";
} }
function logIn (username: string, token: string): void { function logIn(username: string, token: string): void {
setUsername(username); setUsername(username);
setToken(token); setToken(token);
localStorage.setItem("token", token); localStorage.setItem("token", token);
@ -63,9 +63,19 @@ export function GlobalStateProvider(props: {
return ( return (
<> <>
<ModalContext.Provider value={{ isOpen: loginModalOpen, setOpen: setLoginModalOpen }}> <ModalContext.Provider
value={{ isOpen: loginModalOpen, setOpen: setLoginModalOpen }}
>
<LoginContext.Provider <LoginContext.Provider
value={{ token, setToken, username, setUsername, loggedIn, logOut, logIn }} value={{
token,
setToken,
username,
setUsername,
loggedIn,
logOut,
logIn,
}}
> >
{props.children} {props.children}
</LoginContext.Provider> </LoginContext.Provider>

View file

@ -1,7 +1,7 @@
import { Router } from "@solidjs/router"; import { Router } from "@solidjs/router";
import { render } from "solid-js/web"; import { render } from "solid-js/web";
import Root from "./Root"; import Root from "./Containers/Root";
import "./index.css"; import "./index.css";
const root = document.getElementById("root"); const root = document.getElementById("root");

View file

@ -1,32 +1,27 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: [ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
daisyui: { daisyui: {
themes: [ themes: [
{ {
mytheme: { mytheme: {
"primary": "#64279e", primary: "#64279e",
"secondary": "#9454af", secondary: "#9454af",
"accent": "#6ff7c5", accent: "#6ff7c5",
"neutral": "#1f2329", neutral: "#1f2329",
"base-100": "#2a3a47", "base-100": "#2a3a47",
"info": "#8b9be5", info: "#8b9be5",
"success": "#79e2b4", success: "#79e2b4",
"warning": "#efb261", warning: "#efb261",
"error": "#e1604c", error: "#e1604c",
}, },
}, },
], ],
}, },
theme: { theme: {
extend: {}, extend: {},
}, },
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
plugins: [require("daisyui")], plugins: [require("daisyui")],
} };

View file

@ -3,11 +3,7 @@
"target": "ES2020", "target": "ES2020",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"module": "ESNext", "module": "ESNext",
"lib": [ "lib": ["ES2020", "DOM", "DOM.Iterable"],
"ES2020",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true, "skipLibCheck": true,
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
@ -23,9 +19,7 @@
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true "noFallthroughCasesInSwitch": true
}, },
"include": [ "include": ["src"],
"src"
],
"references": [ "references": [
{ {
"path": "./tsconfig.node.json" "path": "./tsconfig.node.json"

View file

@ -1,6 +1,6 @@
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import solid from 'vite-plugin-solid' import { qrcode } from "vite-plugin-qrcode";
import { qrcode } from 'vite-plugin-qrcode' import solid from "vite-plugin-solid";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
@ -12,12 +12,12 @@ export default defineConfig({
port: 3000, port: 3000,
open: true, open: true,
proxy: { proxy: {
'/api': { "/api": {
target: 'http://localhost:8080/api', target: "http://localhost:8080/api",
changeOrigin: true, changeOrigin: true,
secure: false, secure: false,
rewrite: (path): string => path.replace(/^\/api/, '') rewrite: (path): string => path.replace(/^\/api/, ""),
} },
} },
} },
}) });

View file

@ -32,8 +32,7 @@ build-container-release:
podman build -t fb-server -f container/Containerfile . podman build -t fb-server -f container/Containerfile .
# Builds a release container and runs it # Builds a release container and runs it
start-release: start-postgres-dev clean-podman init-sqlx build-container-release start-release: start-postgres-dev clean-podman init-sqlx build-container-release create-network
podman network create {{network}} --ignore
podman run -d --network {{network}} -e {{env_string}} -p 8080:8080 --name frostbyte fb-server podman run -d --network {{network}} -e {{env_string}} -p 8080:8080 --name frostbyte fb-server
# Initializes the database, runs migrations and then prepares sqlx # Initializes the database, runs migrations and then prepares sqlx
@ -45,10 +44,14 @@ init-sqlx:
# Starts a postgres container for development # Starts a postgres container for development
[private] [private]
start-postgres-dev: start-postgres-dev: create-network
podman rm -f {{pg_container}} podman rm -f {{pg_container}}
podman run --network {{network}} --name {{pg_container}} -e POSTGRES_PASSWORD={{pg_pass}} -d -p {{pg_port}}:5432 docker.io/postgres:16.1-alpine podman run --network {{network}} --name {{pg_container}} -e POSTGRES_PASSWORD={{pg_pass}} -d -p {{pg_port}}:5432 docker.io/postgres:16.1-alpine
[private]
create-network:
podman network create {{network}} --ignore
# Forcefully stops and removes the frostbyte container # Forcefully stops and removes the frostbyte container
[private] [private]
clean-podman: clean-podman:

View file

@ -84,13 +84,14 @@ pub struct CaptchaResponse {
} }
/// Request a captcha from the captcha service /// Request a captcha from the captcha service
#[allow(unreachable_code, unused_variables)]
#[post("/captcha")] #[post("/captcha")]
pub async fn captcha_request(cstate: Data<CaptchaState>) -> Result<impl Responder> { pub async fn captcha_request(cstate: Data<CaptchaState>) -> Result<impl Responder> {
unimplemented!("Captcha is currently disabled"); unimplemented!("Captcha is currently disabled");
return Ok(HttpResponse::InternalServerError().json("Error")); return Ok(HttpResponse::InternalServerError().json("Error"));
// This might block the thread a bit too long // This might block the thread a bit too long
// let (answer, svg) = get_captcha(); let (answer, svg) = get_captcha();
// let id = rand_core::OsRng.next_u32() as i32; // let id = rand_core::OsRng.next_u32() as i32;

View file

@ -1,4 +1,4 @@
use rand::{Rng, RngCore}; use rand::Rng;
// This will do for now // This will do for now
pub fn hex_string(length: usize) -> String { pub fn hex_string(length: usize) -> String {
@ -9,11 +9,9 @@ pub fn hex_string(length: usize) -> String {
} }
mod tests { mod tests {
use super::*;
#[test] #[test]
fn test_random_hex_string() { fn test_random_hex_string() {
let s = hex_string(16); let s = super::hex_string(16);
assert_eq!(s.len(), 16); assert_eq!(s.len(), 16);
} }
} }