This commit is contained in:
cdricms
2025-01-15 11:54:39 +01:00
parent d18245736f
commit 683a8c3133
13 changed files with 165 additions and 69 deletions

72
backend/auth.go Normal file
View File

@@ -0,0 +1,72 @@
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
)
type LoginInformation struct {
Email string `json:"email"`
Password string `json:"password"`
}
type Claims struct {
UserID string `json:"user_id"`
jwt.RegisteredClaims
}
func HandleLogin(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
log.Fatal("Not post method")
}
if r.Body == nil {
log.Fatal("No body")
}
body, err := io.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
var login LoginInformation
err = json.Unmarshal(body, &login)
if err != nil {
log.Fatal(err)
}
var user User
err = DB.NewSelect().
Model(&user).
Where("email = ? AND password = ?", login.Email, login.Password).
Limit(1).
Scan(context.Background())
if err != nil {
log.Fatal(err)
}
claims := Claims{
UserID: user.UserID.String(),
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "latosa-escrima.fr",
Subject: "authentification",
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signed, err := token.SignedString([]byte("hello"))
if err != nil {
log.Fatal(err)
}
fmt.Println(signed)
}

View File

@@ -3,6 +3,7 @@ module fr.latosa-escrima
go 1.23.4 go 1.23.4
require ( require (
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9

View File

@@ -1,5 +1,9 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=

View File

@@ -43,6 +43,7 @@ func handlerCreateUser(w http.ResponseWriter, r *http.Request) {
LastName: "Doe", LastName: "Doe",
Email: "john.doe@example.com", Email: "john.doe@example.com",
Phone: "1234567890", Phone: "1234567890",
Password: "1234",
} }
_, err := DB.NewInsert().Model(user).Exec(context.Background()) _, err := DB.NewInsert().Model(user).Exec(context.Background())
@@ -79,6 +80,7 @@ func main() {
http.HandleFunc("/", handler) http.HandleFunc("/", handler)
http.HandleFunc("/user/new", handlerCreateUser) http.HandleFunc("/user/new", handlerCreateUser)
http.HandleFunc("/users/login", HandleLogin)
fmt.Printf("Serving on port %s\n", port) fmt.Printf("Serving on port %s\n", port)
err = http.ListenAndServe(fmt.Sprintf(":%s", port), nil) err = http.ListenAndServe(fmt.Sprintf(":%s", port), nil)

View File

@@ -25,6 +25,7 @@ type User struct {
FirstName string `bun:"firstname,notnull"` FirstName string `bun:"firstname,notnull"`
LastName string `bun:"lastname,notnull"` LastName string `bun:"lastname,notnull"`
Email string `bun:"email,unique,notnull"` Email string `bun:"email,unique,notnull"`
Password string `bun:"password,notnull"`
Phone string `bun:"phone,notnull"` Phone string `bun:"phone,notnull"`
Role Role `bun:"role,notnull,default:'user'"` Role Role `bun:"role,notnull,default:'user'"`
CreatedAt time.Time `bun:"created_at,default:current_timestamp"` CreatedAt time.Time `bun:"created_at,default:current_timestamp"`

View File

@@ -1,3 +1,4 @@
"use server";
import { AppSidebar } from "@/components/app-sidebar"; import { AppSidebar } from "@/components/app-sidebar";
import { import {
Breadcrumb, Breadcrumb,
@@ -14,7 +15,7 @@ import {
SidebarTrigger, SidebarTrigger,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
export default function Page() { export default async function Page() {
return ( return (
<SidebarProvider> <SidebarProvider>
<AppSidebar /> <AppSidebar />

View File

@@ -1,35 +1,7 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "@/app/globals.css";
import Navbar from "@/components/nav-bar";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({ export default function RootLayout({
children, children,
}: Readonly<{ }: Readonly<{
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
return ( return <>{children}</>;
<html lang="fr">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
</body>
</html>
);
} }

View File

@@ -1,16 +1,14 @@
"use server" "use server";
export default async function About() { export default async function About() {
const res = await fetch("http://localhost:8000/api");
console.log(res);
return ( return (
<div> <div>
<div> <div>
About us About us will : +explain what we +pricing +plannign for what
will : will come next
+explain what we
+pricing
+plannign for what will come next
</div> </div>
</div> </div>
) );
} }

View File

@@ -1,23 +1,5 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "@/app/globals.css";
import Navbar from "@/components/nav-bar";
import Footer from "@/components/footer"; import Footer from "@/components/footer";
import Navbar from "@/components/nav-bar";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({ export default function RootLayout({
children, children,
@@ -25,14 +7,10 @@ export default function RootLayout({
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
return ( return (
<html lang="fr"> <>
<body <Navbar />
className={`${geistSans.variable} ${geistMono.variable} antialiased`} {children}
> <Footer />
<Navbar /> </>
{children}
<Footer />
</body>
</html>
); );
} }

42
frontend/app/layout.tsx Normal file
View File

@@ -0,0 +1,42 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "@/app/globals.css";
import { SWRConfig } from "swr";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<SWRConfig
value={{
fetcher: (url: string) => fetch(url).then((res) => res.json()),
revalidateOnFocus: false,
}}
>
<html lang="fr">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
</body>
</html>
</SWRConfig>
);
}

19
frontend/deno.lock generated
View File

@@ -27,6 +27,7 @@
"npm:react-dom@19": "19.0.0_react@19.0.0", "npm:react-dom@19": "19.0.0_react@19.0.0",
"npm:react-icons@^5.4.0": "5.4.0_react@19.0.0", "npm:react-icons@^5.4.0": "5.4.0_react@19.0.0",
"npm:react@19": "19.0.0", "npm:react@19": "19.0.0",
"npm:swr@^2.3.0": "2.3.0_react@19.0.0",
"npm:tailwind-merge@^2.6.0": "2.6.0", "npm:tailwind-merge@^2.6.0": "2.6.0",
"npm:tailwindcss-animate@^1.0.7": "1.0.7_tailwindcss@3.4.17__postcss@8.4.49", "npm:tailwindcss-animate@^1.0.7": "1.0.7_tailwindcss@3.4.17__postcss@8.4.49",
"npm:tailwindcss@^3.4.1": "3.4.17_postcss@8.4.49", "npm:tailwindcss@^3.4.1": "3.4.17_postcss@8.4.49",
@@ -1226,6 +1227,9 @@
"object-keys" "object-keys"
] ]
}, },
"dequal@2.0.3": {
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="
},
"detect-libc@2.0.3": { "detect-libc@2.0.3": {
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==" "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="
}, },
@@ -2776,6 +2780,14 @@
"supports-preserve-symlinks-flag@1.0.0": { "supports-preserve-symlinks-flag@1.0.0": {
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
}, },
"swr@2.3.0_react@19.0.0": {
"integrity": "sha512-NyZ76wA4yElZWBHzSgEJc28a0u6QZvhb6w0azeL2k7+Q1gAzVK+IqQYXhVOC/mzi+HZIozrZvBVeSeOZNR2bqA==",
"dependencies": [
"dequal",
"react",
"use-sync-external-store"
]
},
"tailwind-merge@2.6.0": { "tailwind-merge@2.6.0": {
"integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==" "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="
}, },
@@ -2939,6 +2951,12 @@
"tslib" "tslib"
] ]
}, },
"use-sync-external-store@1.4.0_react@19.0.0": {
"integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
"dependencies": [
"react"
]
},
"util-deprecate@1.0.2": { "util-deprecate@1.0.2": {
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
@@ -3051,6 +3069,7 @@
"npm:react-dom@19", "npm:react-dom@19",
"npm:react-icons@^5.4.0", "npm:react-icons@^5.4.0",
"npm:react@19", "npm:react@19",
"npm:swr@^2.3.0",
"npm:tailwind-merge@^2.6.0", "npm:tailwind-merge@^2.6.0",
"npm:tailwindcss-animate@^1.0.7", "npm:tailwindcss-animate@^1.0.7",
"npm:tailwindcss@^3.4.1", "npm:tailwindcss@^3.4.1",

View File

@@ -4,11 +4,16 @@ const nextConfig: NextConfig = {
/* config options here */ /* config options here */
output: "standalone", output: "standalone",
async redirects() { async redirects() {
if (!process.env.BACKEND_PORT) {
throw new Error(
"Environment variable BACKEND_PORT is not defined.",
);
}
return [ return [
{ {
destination: "/api", source: "/api",
source: `http://localhost:${process.env.BACKEND_PORT}`, destination: `http://localhost:${process.env.BACKEND_PORT}`,
permanent: true, permanent: false,
}, },
]; ];
}, },

View File

@@ -28,6 +28,7 @@
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-icons": "^5.4.0", "react-icons": "^5.4.0",
"swr": "^2.3.0",
"tailwind-merge": "^2.6.0", "tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7"
}, },