Some frontend improvements / bd testing was cpmpleted
This commit is contained in:
parent
6b4fe31d67
commit
ae9bd6f9d6
@ -1,53 +1,20 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import "@radix-ui/themes/styles.css";
|
import "@radix-ui/themes/styles.css";
|
||||||
import {
|
import {
|
||||||
Badge,
|
|
||||||
Button,
|
|
||||||
Callout,
|
|
||||||
Container,
|
|
||||||
Flex,
|
|
||||||
Separator,
|
|
||||||
Text,
|
|
||||||
Theme,
|
Theme,
|
||||||
ThemePanel,
|
ThemePanel,
|
||||||
} from "@radix-ui/themes";
|
} from "@radix-ui/themes";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Router,
|
|
||||||
Route,
|
|
||||||
createBrowserRouter,
|
createBrowserRouter,
|
||||||
createRoutesFromElements,
|
|
||||||
RouterProvider,
|
RouterProvider,
|
||||||
Routes,
|
|
||||||
useRouteError,
|
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import MainPage from "./Pages/MainPage/MainPage";
|
|
||||||
import { QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClientProvider } from "@tanstack/react-query";
|
||||||
import queryClient from "./api/QueryClient/QueryClient";
|
import queryClient from "./api/QueryClient/QueryClient";
|
||||||
|
import { routes } from "./routes/routes";
|
||||||
function ErrorBoundary() {
|
|
||||||
let error = useRouteError();
|
|
||||||
console.error(error);
|
|
||||||
|
|
||||||
return <div>Dang! This route does not exist... Yet ;)</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = createBrowserRouter(
|
const router = createBrowserRouter(
|
||||||
createRoutesFromElements(
|
routes
|
||||||
<>
|
|
||||||
<Route
|
|
||||||
path="/"
|
|
||||||
errorElement={<ErrorBoundary />}
|
|
||||||
element={<MainPage />}
|
|
||||||
>
|
|
||||||
<Route index element={<Text>Cringer path</Text>} />
|
|
||||||
<Route
|
|
||||||
path="/a?/c"
|
|
||||||
element={<Text>Cringer path, but this a</Text>}
|
|
||||||
></Route>
|
|
||||||
</Route>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button, Text } from "@radix-ui/themes";
|
import { Button, Card, ChevronDownIcon, Text } from "@radix-ui/themes";
|
||||||
import * as NavigationMenu from "@radix-ui/react-navigation-menu";
|
import * as NavigationMenu from "@radix-ui/react-navigation-menu";
|
||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
@ -10,10 +10,31 @@ export default function NavBar() {
|
|||||||
className="flex justify-center"
|
className="flex justify-center"
|
||||||
>
|
>
|
||||||
<NavigationMenu.List className="flex justify-center gap-2">
|
<NavigationMenu.List className="flex justify-center gap-2">
|
||||||
<NavItem text="Cringer" to="/"/>
|
<NavItem text="Cringer" to="/" />
|
||||||
|
|
||||||
<NavItem text="C-Cringer" to="/c"/>
|
<NavItem text="C-Cringer" to="/c" />
|
||||||
|
|
||||||
|
<NavigationMenu.Item className="text-center">
|
||||||
|
<NavigationMenu.Trigger className="flex items-center">
|
||||||
|
<Button
|
||||||
|
asChild
|
||||||
|
className="w-fit h-fit rounded-full m-0 p-0 pr-2 pl-2 mt-2 mb-2 duration-[50ms]"
|
||||||
|
variant="ghost"
|
||||||
|
highContrast
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
size={"3"}
|
||||||
|
className="flex items-center gap-1"
|
||||||
|
>
|
||||||
|
Cringer 123 <ChevronDownIcon />
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</NavigationMenu.Trigger>
|
||||||
|
|
||||||
|
<NavigationMenu.Content className="absolute data-[motion=from-start]:scale-150">
|
||||||
|
<Card>asd</Card>
|
||||||
|
</NavigationMenu.Content>
|
||||||
|
</NavigationMenu.Item>
|
||||||
</NavigationMenu.List>
|
</NavigationMenu.List>
|
||||||
</NavigationMenu.Root>
|
</NavigationMenu.Root>
|
||||||
</nav>
|
</nav>
|
||||||
@ -26,26 +47,20 @@ type TNavItem = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function NavItem(props: TNavItem) {
|
function NavItem(props: TNavItem) {
|
||||||
|
const navigate = useNavigate();
|
||||||
const navigate = useNavigate()
|
const location = useLocation();
|
||||||
const location = useLocation()
|
|
||||||
|
|
||||||
console.log(location);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationMenu.Item>
|
<NavigationMenu.Item>
|
||||||
<NavigationMenu.Link>
|
<NavigationMenu.Link>
|
||||||
<Button
|
<Button
|
||||||
className="w-fit h-fit rounded-full m-0 p-0 pr-2 pl-2 mt-2 mb-2"
|
className="w-fit h-fit rounded-full m-0 p-0 pr-2 pl-2 mt-2 mb-2 duration-[50ms]"
|
||||||
|
highContrast
|
||||||
highContrast
|
variant={location.pathname === props.to ? "solid" : "ghost"}
|
||||||
|
onClick={() => navigate(props.to)}
|
||||||
variant={location.pathname === props.to ? 'solid' : 'ghost'}
|
>
|
||||||
onClick={() => navigate(props.to)}
|
<Text size={"3"}>{props.text}</Text>
|
||||||
>
|
</Button>
|
||||||
<Text size={"3"}>{props.text}</Text>
|
|
||||||
</Button>
|
|
||||||
</NavigationMenu.Link>
|
</NavigationMenu.Link>
|
||||||
</NavigationMenu.Item>
|
</NavigationMenu.Item>
|
||||||
);
|
);
|
||||||
|
|||||||
27
enshi/src/routes/routes.tsx
Normal file
27
enshi/src/routes/routes.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { createRoutesFromElements, Route, useRouteError } from "react-router-dom"
|
||||||
|
import MainPage from "../Pages/MainPage/MainPage"
|
||||||
|
import {Text} from "@radix-ui/themes";
|
||||||
|
|
||||||
|
|
||||||
|
function ErrorBoundary() {
|
||||||
|
let error = useRouteError();
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
return <div>Dang! This route does not exist... Yet ;)</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const routes = createRoutesFromElements(
|
||||||
|
<>
|
||||||
|
<Route
|
||||||
|
path="/"
|
||||||
|
errorElement={<ErrorBoundary />}
|
||||||
|
element={<MainPage />}
|
||||||
|
>
|
||||||
|
<Route index element={<Text>Cringer path</Text>} />
|
||||||
|
<Route
|
||||||
|
path="/a?/c"
|
||||||
|
element={<Text>Cringer path, but this a</Text>}
|
||||||
|
></Route>
|
||||||
|
</Route>
|
||||||
|
</>
|
||||||
|
)
|
||||||
@ -5,7 +5,16 @@ content: [
|
|||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {
|
||||||
|
animation: {
|
||||||
|
'appear': 'appear 0.25s'
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
appear: {
|
||||||
|
'100%': {opacity: '1'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
|||||||
44
enshi_back/db/go_queries/favorites_queries.sql.go
Normal file
44
enshi_back/db/go_queries/favorites_queries.sql.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.27.0
|
||||||
|
// source: favorites_queries.sql
|
||||||
|
|
||||||
|
package db_repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createFavorite = `-- name: CreateFavorite :one
|
||||||
|
INSERT INTO public.favorites
|
||||||
|
(user_id, blog_id, favorited_at)
|
||||||
|
VALUES($1, $2, CURRENT_TIMESTAMP)
|
||||||
|
RETURNING user_id, blog_id, favorited_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateFavoriteParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
BlogID int64 `json:"blog_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateFavorite(ctx context.Context, arg CreateFavoriteParams) (Favorite, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createFavorite, arg.UserID, arg.BlogID)
|
||||||
|
var i Favorite
|
||||||
|
err := row.Scan(&i.UserID, &i.BlogID, &i.FavoritedAt)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteFavorite = `-- name: DeleteFavorite :exec
|
||||||
|
DELETE FROM public.favorites
|
||||||
|
WHERE user_id=$1 AND blog_id=$2
|
||||||
|
`
|
||||||
|
|
||||||
|
type DeleteFavoriteParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
BlogID int64 `json:"blog_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) DeleteFavorite(ctx context.Context, arg DeleteFavoriteParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteFavorite, arg.UserID, arg.BlogID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
48
enshi_back/db/go_queries/multi_queries.sql.go
Normal file
48
enshi_back/db/go_queries/multi_queries.sql.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.27.0
|
||||||
|
// source: multi_queries.sql
|
||||||
|
|
||||||
|
package db_repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getFavoriteBlogsInfosByUserId = `-- name: GetFavoriteBlogsInfosByUserId :many
|
||||||
|
SELECT blogs.blog_id, blogs.user_id, blogs.title, blogs.description, blogs.category_id, blogs.created_at
|
||||||
|
FROM favorites
|
||||||
|
JOIN blogs on blogs.blog_id = favorites.blog_id
|
||||||
|
WHERE favorites.user_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetFavoriteBlogsInfosByUserIdRow struct {
|
||||||
|
Blog Blog `json:"blog"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetFavoriteBlogsInfosByUserId(ctx context.Context, userID int64) ([]GetFavoriteBlogsInfosByUserIdRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getFavoriteBlogsInfosByUserId, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetFavoriteBlogsInfosByUserIdRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetFavoriteBlogsInfosByUserIdRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.Blog.BlogID,
|
||||||
|
&i.Blog.UserID,
|
||||||
|
&i.Blog.Title,
|
||||||
|
&i.Blog.Description,
|
||||||
|
&i.Blog.CategoryID,
|
||||||
|
&i.Blog.CreatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
@ -25,4 +25,6 @@ CREATE TABLE "public"."post_tags" ("post_id" bigint NOT NULL, "tag_id" integer N
|
|||||||
-- Create "post_votes" table
|
-- Create "post_votes" table
|
||||||
CREATE TABLE "public"."post_votes" ("post_id" bigint NOT NULL, "user_id" bigint NOT NULL, "vote" boolean NOT NULL, PRIMARY KEY ("post_id", "user_id"), CONSTRAINT "post_votes_post_id_fkey" FOREIGN KEY ("post_id") REFERENCES "public"."posts" ("post_id") ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT "post_votes_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."users" ("user_id") ON UPDATE NO ACTION ON DELETE NO ACTION);
|
CREATE TABLE "public"."post_votes" ("post_id" bigint NOT NULL, "user_id" bigint NOT NULL, "vote" boolean NOT NULL, PRIMARY KEY ("post_id", "user_id"), CONSTRAINT "post_votes_post_id_fkey" FOREIGN KEY ("post_id") REFERENCES "public"."posts" ("post_id") ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT "post_votes_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."users" ("user_id") ON UPDATE NO ACTION ON DELETE NO ACTION);
|
||||||
-- Create "profiles" table
|
-- Create "profiles" table
|
||||||
CREATE TABLE "public"."profiles" ("profile_id" bigint NOT NULL, "user_id" bigint NULL, "bio" text NULL, "avatar_url" character varying(255) NULL, "website_url" character varying(100) NULL, PRIMARY KEY ("profile_id"), CONSTRAINT "profiles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."users" ("user_id") ON UPDATE NO ACTION ON DELETE CASCADE);
|
CREATE TABLE "public"."profiles" ("profile_id" bigint NOT NULL, "user_id" bigint NOT NULL, "bio" text NULL, "avatar_url" character varying(255) NULL, "website_url" character varying(100) NULL, PRIMARY KEY ("profile_id"), CONSTRAINT "profiles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."users" ("user_id") ON UPDATE NO ACTION ON DELETE CASCADE);
|
||||||
|
-- Create index "profiles_user_id_idx" to table: "profiles"
|
||||||
|
CREATE UNIQUE INDEX "profiles_user_id_idx" ON "public"."profiles" ("user_id");
|
||||||
|
|||||||
9
enshi_back/db/queries/favorites_queries.sql
Normal file
9
enshi_back/db/queries/favorites_queries.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-- name: CreateFavorite :one
|
||||||
|
INSERT INTO public.favorites
|
||||||
|
(user_id, blog_id, favorited_at)
|
||||||
|
VALUES($1, $2, CURRENT_TIMESTAMP)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteFavorite :exec
|
||||||
|
DELETE FROM public.favorites
|
||||||
|
WHERE user_id=$1 AND blog_id=$2;
|
||||||
6
enshi_back/db/queries/multi_queries.sql
Normal file
6
enshi_back/db/queries/multi_queries.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
-- name: GetFavoriteBlogsInfosByUserId :many
|
||||||
|
SELECT sqlc.embed(blogs)
|
||||||
|
FROM favorites
|
||||||
|
JOIN blogs on blogs.blog_id = favorites.blog_id
|
||||||
|
WHERE favorites.user_id = $1;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transaction
|
// Transaction
|
||||||
tx, _ := utils.Dbx_connection.Begin(context.Background())
|
tx, _ := utils.Dbx.Begin(context.Background())
|
||||||
defer tx.Rollback(context.Background())
|
defer tx.Rollback(context.Background())
|
||||||
|
|
||||||
repo := db_repo.New(tx)
|
repo := db_repo.New(tx)
|
||||||
|
|||||||
@ -20,9 +20,9 @@ type Argon2Hash struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HashSalt struct {
|
type HashSalt struct {
|
||||||
hash []byte
|
Hash []byte
|
||||||
salt []byte
|
salt []byte
|
||||||
stringToStore string
|
StringToStore string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializer for algorithm
|
// Initializer for algorithm
|
||||||
@ -75,7 +75,7 @@ func (a *Argon2Hash) HashGen(password, salt []byte) (*HashSalt, error) {
|
|||||||
stringToStore := fmt.Sprintf("$m=%d,t=%d$%s$%s", a.memory, a.time, saltDecoded, hashDecoded)
|
stringToStore := fmt.Sprintf("$m=%d,t=%d$%s$%s", a.memory, a.time, saltDecoded, hashDecoded)
|
||||||
|
|
||||||
// This is unnecessary structure i created following the guide 0_0
|
// This is unnecessary structure i created following the guide 0_0
|
||||||
return &HashSalt{hash: hash, salt: salt, stringToStore: stringToStore}, nil
|
return &HashSalt{Hash: hash, salt: salt, StringToStore: stringToStore}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ func (a *Argon2Hash) Compare(hash, salt, password []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comparing hashes
|
// Comparing hashes
|
||||||
if !bytes.Equal(hash, hashSalt.hash) {
|
if !bytes.Equal(hash, hashSalt.Hash) {
|
||||||
return fmt.Errorf("invalid password (hashes does not match)")
|
return fmt.Errorf("invalid password (hashes does not match)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +153,6 @@ func Test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fmt.Println(testDbString)
|
// fmt.Println(testDbString)
|
||||||
fmt.Printf("%s", cringe.stringToStore)
|
fmt.Printf("%s", cringe.StringToStore)
|
||||||
fmt.Print("\n\n\n\n")
|
fmt.Print("\n\n\n\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -206,7 +206,7 @@ func registerUser(c *gin.Context) {
|
|||||||
|
|
||||||
rowsToClose, errr := Dbx.Query(context.Background(), "INSERT INTO users "+
|
rowsToClose, errr := Dbx.Query(context.Background(), "INSERT INTO users "+
|
||||||
"(user_id, username, user_name, user_password) "+
|
"(user_id, username, user_name, user_password) "+
|
||||||
"VALUES($1, $2, $3, $4);", newUuid, body.Username, body.Name, hashedPassword.stringToStore)
|
"VALUES($1, $2, $3, $4);", newUuid, body.Username, body.Name, hashedPassword.StringToStore)
|
||||||
|
|
||||||
if errr != nil {
|
if errr != nil {
|
||||||
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": errr.Error()})
|
c.IndentedJSON(http.StatusInternalServerError, gin.H{"error": errr.Error()})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user