feat(front): add tests for frontend

This commit is contained in:
rick 2022-10-21 03:15:09 +02:00
parent 29472384da
commit 6b4acb5913
Signed by: Rick
GPG key ID: 4A6223D66294EB20
9 changed files with 628 additions and 10 deletions

198
.gitignore vendored
View file

@ -1,7 +1,58 @@
.env
# Created by https://www.toptal.com/developers/gitignore/api/vim,go,rust
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,go,rust
# Created by https://www.toptal.com/developers/gitignore/api/node,go,vim,rust,emacs
# Edit at https://www.toptal.com/developers/gitignore?templates=node,go,vim,rust,emacs
### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
dist/
# Flycheck
flycheck_*.el
# server auth directory
/server/
# projectiles files
.projectile
# directory configuration
.dir-locals.el
# network security
/network-security.data
### Go ###
# If you prefer the allow list template instead of the deny list, see community template:
@ -30,6 +81,146 @@ go.work
/vendor/
/Godeps/
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
### Rust ###
# Generated by Cargo
# will have compiled files and executables
@ -61,10 +252,9 @@ Sessionx.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
# End of https://www.toptal.com/developers/gitignore/api/vim,go,rust
# End of https://www.toptal.com/developers/gitignore/api/node,go,vim,rust,emacs

View file

@ -8,23 +8,42 @@
* routes : configuration des routes
* views : fichiers html dynamiques
* dao : fichiers pour faire des requetes en BDD
* models : structures utilisées pour manipuler le contenu de la base de données
* models : structures utilisées pour manipuler le contenu de la base de
données
## Lancement
### Frontend
Le frontend utilise **Rust** et **WASM**. Il vous faut Trunk en plus de Cargo
pour pouvoir compiler les fichiers Rust en WASM. Il faut en premier installer
les dépendances JS puis compiler les fichiers avec cargo puis Trunk.
```
cd front
npm install
cargo build
trunk build
```
JS est nécessaire pour une crate qui permet d'utiliser les propriétés d'une
bibliothèque JS.
### Backend
Il faut mettre en place une base de données [MongoDB](https://www.mongodb.com/).
Il est nécessaire d'avoir [une application Discord](https://discord.com/developers/)
et [une clé d'API Steam](https://steamcommunity.com/dev).
Configurez ensuite le fichier `example.env` et renommez le en `.env`.
Il faut mettre en place une base de données
[MongoDB](https://www.mongodb.com/). Il est nécessaire d'avoir [une
application Discord](https://discord.com/developers/) et [une clé d'API
Steam](https://steamcommunity.com/dev). Configurez ensuite le fichier
`example.env` et renommez le en `.env`.
Lancez le serveur avec `go run main.go`.
### Documentation
Installer swager avec Go et lancer le. Vous pouvez démarrer le serveur et aller
sur le lien [de la documentation](localhost:8080/swagger) pour pouvoir la lire en ligne.
sur le lien [de la documentation](localhost:8080/swagger) pour pouvoir la lire
en ligne.
```
go install github.com/swaggo/swag

17
front/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "front"
version = "0.1.0"
edition = "2021"
[build-dependencies]
reqwest = { version = "0.11.12", features = ["blocking", "json"] }
[dependencies]
yew = "0.19.3"
yew-router = "0.16"
gloo-net = "0.2"
serde = { version = "1.0", features = ["derive"] }
wasm-bindgen-futures = "0.4"
gloo-storage = "0.2.2"
patternfly-yew = "0.2.0"

2
front/Trunk.toml Normal file
View file

@ -0,0 +1,2 @@
[build]
dist = "../dist"

0
front/assets/style.scss Normal file
View file

9
front/index.html Normal file
View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<link data-trunk rel="scss" href="assets/style.scss">
<link data-trunk rel="scss" href="node_modules/@patternfly/patternfly/patternfly.scss">
<link data-trunk rel="scss" href="node_modules/@patternfly/patternfly/patternfly-addons.scss">
<link data-trunk rel="copy-dir" href="node_modules/@patternfly/patternfly/assets">
</head>
</html>

7
front/main.js Normal file
View file

@ -0,0 +1,7 @@
import './node_modules/@patternfly/patternfly/patternfly.scss';
import './node_modules/@patternfly/patternfly/patternfly-addons.scss';
import './static/style.scss';
import("./pkg").then(module => {
module.main();
});

11
front/package.json Normal file
View file

@ -0,0 +1,11 @@
{
"name": "patternfly-yew",
"version": "0.0.1",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@patternfly/patternfly": "^4.159.1"
}
}

363
front/src/main.rs Normal file
View file

@ -0,0 +1,363 @@
use gloo_net::http::Request;
use gloo_net::Error;
use gloo_storage::errors::StorageError;
use gloo_storage::{LocalStorage, Storage};
use patternfly_yew::{Toast, ToastDispatcher, ToastViewer, Type};
use serde::{Deserialize, Serialize};
use yew::prelude::*;
use yew_router::prelude::*;
#[derive(Clone, Deserialize, PartialEq, Serialize)]
struct User {
id: String,
banned: bool,
blacklisted: bool,
experience: u32,
level: u32,
money: u32,
moneylimit: u32,
discordname: String,
}
#[derive(Clone, Routable, PartialEq)]
enum Route {
#[at("/")]
Home,
#[at("/about")]
About,
#[at("/test")]
Test,
#[at("/404")]
NotFound,
}
#[function_component(About)]
fn about() -> Html {
let _history = use_history().unwrap();
//LocalStorage::set("test", "coucou");
let test: String = LocalStorage::get("test").unwrap_or(String::from("nop"));
//let onclick = Callback::once(move |_| history.push(Route::Home));
html! {
<>
<h1>{ "À propos" }</h1>
<p>{ test }</p>
//<a {onclick}>{ "Index" }</a>
</>
}
}
struct Home {
value: String,
user: Option<User>,
}
#[derive(PartialEq)]
enum TestMessage {
Test,
Toast(ToastType),
ConnexionOk(User),
}
#[derive(PartialEq)]
struct ToastFields {
pub title: String,
pub body: String,
}
#[derive(PartialEq)]
enum ToastType {
Info(ToastFields),
Error(ToastFields),
}
impl Component for Home {
type Message = TestMessage;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {
value: String::from("coucou"),
user: None,
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let user: Result<User, StorageError> = LocalStorage::get("auth");
if let Ok(user) = user {
if let None = self.user {
ctx.link().send_message(TestMessage::ConnexionOk(user));
}
} else {
ctx.link().send_future_batch(async {
match Request::get("/api/users/current").send().await {
Ok(resp) => {
if resp.ok() {
let json: Result<User, Error> = resp.json().await;
match json {
Ok(json) => {
let user = json.clone();
match LocalStorage::set("auth", json) {
Ok(_) => vec![
TestMessage::Toast(ToastType::Info(ToastFields {
title: String::from("Connexion réussie !"),
body: String::new(),
})),
TestMessage::ConnexionOk(user),
],
Err(err) => vec![TestMessage::Toast(ToastType::Error(
ToastFields {
title: String::from("Error from the promise"),
body: err.to_string(),
},
))],
}
}
Err(err) => {
LocalStorage::delete("auth");
vec![TestMessage::Toast(ToastType::Error(ToastFields {
title: String::from("Error from the promise"),
body: err.to_string(),
}))]
}
}
} else {
vec![TestMessage::Toast(ToastType::Error(ToastFields {
title: String::from("Error from the promise"),
body: String::from("L'API ne retourne pas un code 200."),
}))]
}
}
Err(err) => vec![TestMessage::Toast(ToastType::Error(ToastFields {
title: String::from("Error from the promise"),
body: err.to_string(),
}))],
}
});
}
let onclick = ctx.link().callback(|_| TestMessage::Test);
html! {
<>
<ToastViewer />
if let Some(user) = &self.user {
<h1>{ format!("Bienvenue {} !", user.discordname) }</h1>
} else {
<p><a href="/login/discord">{ "SE CONNECTER VIA DISCORD ICI" }</a></p>
<p><a href="/login/steam">{ "SE CONNECTER VIA STEAM ICI" }</a></p>
}
<button {onclick}>{"test"}</button>
</>
}
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
TestMessage::ConnexionOk(user) => {
self.user = Some(user);
return true;
}
TestMessage::Toast(toast) => match toast {
ToastType::Info(infos) => ToastDispatcher::new().toast(Toast {
title: infos.title,
r#type: Type::Info,
..Default::default()
}),
ToastType::Error(infos) => ToastDispatcher::new().toast(Toast {
title: infos.title,
r#type: Type::Danger,
body: html! { <p>{ infos.body }</p> },
..Default::default()
}),
},
//_ => ToastDispatcher::new().toast(html! {<Alert title="Coucou"></Alert>}),
_ => ToastDispatcher::new().toast(Toast {
title: String::from("Un callback n'a pas été implémenté !"),
r#type: Type::Warning,
..Default::default()
}),
}
false
/*
if msg == TestMessage::Test {
self.value = String::from("nouveau");
true
} else if let TestMessage::StatusConnection(_) = msg {
self.value = String::from("yes ça marche");
true
} else {
false
}
*/
}
}
/*
#[function_component(Home)]
fn home() -> Html {
// check if the cookie is set
let state = use_state(|| StatusConnection::NotConnected);
//let connected = use_state_eq(|| false);
{
let state = state.clone();
use_effect(move || {
//let connected = connected.clone();
wasm_bindgen_futures::spawn_local(async move {
if let Ok(resp) = Request::get("/api/users/current").send().await {
if resp.ok() {
let json: Result<User, Error> = resp.json().await;
if let Ok(json) = json {
LocalStorage::set("auth", json);
state.set(StatusConnection::UpdateConnection);
} else if let Err(err) = json {
LocalStorage::delete("auth");
state.set(StatusConnection::Error(err.to_string()));
}
} else {
state.set(StatusConnection::NotConnected);
}
}
});
|| ()
});
}
/*
let client = Client::new();
if let Ok(resp) = client.get("/users/current").send() {
if resp.status() == StatusCode::OK {
if let Ok(json) = resp.json::<User>() {
LocalStorage::set("auth", json);
}
}
}
*/
let _user: Result<User, StorageError> = LocalStorage::get("auth");
if let Ok(user) = LocalStorage::get("auth") {
if *state == StatusConnection::UpdateConnection {
let state = state.clone();
state.set(StatusConnection::Connected(user));
}
}
match &*state {
StatusConnection::NotConnected => {
html! {
<>
<p><a href="/login/discord">{ "SE CONNECTER VIA DISCORD ICI" }</a></p>
<p><a href="/login/steam">{ "SE CONNECTER VIA STEAM ICI" }</a></p>
</>
}
},
StatusConnection::UpdateConnection => {
html!{ <p>{ "Connexion en cours..." }</p> }
},
StatusConnection::Connected(user) => html!{ <h1>{ format!("Bienvenue {} !", user.discordname) }</h1> },
StatusConnection::Error(err) => {
html! {
<>
<h1>{ "Erreur !!" }</h1>
<p>{ err }</p>
</>
}
}
}
/*
let tmp: Result<User, StorageError> = LocalStorage::get("auth");
if let Ok(o) = tmp {
} else {
let check_auth = use_state(|| None::<User>);
wasm_bindgen_futures::spawn_local(async move {
if let Ok(resp) = Request::get("/users/current").send().await {
if let Ok(user) = resp.json().await {
check_auth.set(Some(user))
}
};
});
if let Some(user) = (*check_auth).clone() {
LocalStorage::set("auth", user);
}
//html! { "Vous êtes connecté !" }
}
*/
}
*/
fn switch(route: &Route) -> Html {
match route {
Route::Home => html! { <Home /> },
Route::About => html! { <About /> },
Route::NotFound => html! { <h1>{"404, déso"}</h1> },
Route::Test => html! { <Test /> },
}
}
#[function_component(App)]
fn app() -> Html {
html! {
<BrowserRouter>
<Switch<Route> render={Switch::render(switch)} />
</BrowserRouter>
}
/*
html! {
<div>
<h1>{ "Chasseurs De Succès" }</h1>
<h2>{ "Bienvenue sur le site pour gérer les groupes de chasses" }</h2>
</div>
}
*/
}
fn main() {
yew::start_app::<App>();
}
/*
#[derive(Clone, Deserialize, PartialEq, Serialize)]
struct Group {
name: String,
}
struct ListGroups {
list: Vec<Group>,
}
impl Component for ListGroups {
fn create(_ctx: &Context<Self>) -> Self {
Self {
}
}
}
*/
#[function_component(Test)]
fn test() -> Html {
let test = use_state(|| String::from(""));
{
let test = test.clone();
wasm_bindgen_futures::spawn_local(async move {
if let Ok(o) = Request::get("/test").send().await {
test.set(o.text().await.unwrap())
} else {
test.set(String::from("Pas de connexion !!"))
};
});
}
html! {
<>
<h1>{ "Moi !!!" }</h1>
<p>{ (*test).clone() }</p>
</>
}
}