init project

This commit is contained in:
2022-11-28 10:06:38 +01:00
commit 594e587724
73 changed files with 62285 additions and 0 deletions

6
.dockerignore Normal file
View File

@@ -0,0 +1,6 @@
medias/
tmp/
target/
persistence-db/
staticbuild/
static/

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
www/*/
!www/default/
!www/static/
!www/home/
/target/
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
/medias
persistence-db
tmp/*
static/sourcefiles/
staticbuild/

30
Cargo.toml Normal file
View File

@@ -0,0 +1,30 @@
[package]
name = "pointcloud"
version = "0.1.0"
edition = "2021"
[dependencies]
actix = "0.13.0"
actix-web = "4.2.1"
actix-files = "0.6"
actix-identity = "0.4"
actix-multipart = "0.4"
actix-form-data = "0.6.2"
actix-web-actors = "4.1.0"
oauth2 = "4.2.3"
jsonwebtoken-google = "0.1.6"
diesel = { version = "1.4.4", features = ["postgres"] }
serde = "1.0.136"
serde_json = "1.0.59"
rand = "0.8.5"
dotenv = "0.15.0"
sha256 = "1.0.3"
walkdir = "2.3.2"
tera = "1.8.0"
futures-util = { version = "0.3.7", default-features = false, features = ["std"] }
sanitize-filename = "0.3"
uuid = { version = "0.8", features = ["v4"] }
tempfile = "3.3.0"
minifier = "0.2.2"
lettre = { version = "0.10.0-beta.2", default-features = false, features = ["smtp-transport", "tokio1-rustls-tls", "hostname", "r2d2", "builder"] }
derive_more = "0.99.17"

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
FROM rust:latest
MAINTAINER Valentin SORLIN
USER root
ENV ROCKET_ADDRESS=0.0.0.0
ENV ROCKET_PORT=80
WORKDIR /usr/src/myapp
COPY ./liblaszip.so /lib/liblaszip.so
RUN rustup default nightly
RUN cargo install cargo-watch
RUN cargo install diesel_cli --no-default-features --features postgres
CMD ["cargo", "watch", "-x", "run", "-i", "/usr/src/myapp/tmp", "--why"]

71
NORME.md Normal file
View File

@@ -0,0 +1,71 @@
Nommage
=====================
Les variable
--------------------
Les variables doivent être en minuscule en [snake_case](https://www.theserverside.com/definition/Snake-case) et sans chiffre et si possible refléter le type de variable
exemple correct:
```
let nb_chat = 5; // c'est une qte alors nb
let chats = Vec<Chat>::new(); // c'est un tableau alors "s"
let is_chat = True; // C'est un booléen du coup is
```
exemple incorrect:
```
let 1chien = 1; // incorrect a cause du chiffre
let mechantChien = Chien::new(); // incorrect car CamelCase
let IS_CHIEN = False;// incorrect car majuscule
let nb_chien = Chien::new(); //incorrect la variable s'appel nb et ne représente pas le type de variable qui est ici un instance de Chien
```
Les classes
=====================
les classe/struct doivent commencé par une majuscule et être en un mots
exemple correct:
```
struct User {}
struct Project {}
```
exemple incorrect:
```
struct user{} // incorrect a cause de la majuscule
struct ProjectNuageDePoints // incorrect car en plusieurs mots
```
Structure de code
------------------
Les variable doivent êtres autant que possible en début de fonction
```
fct main() {
let variable_correct = 22;
println("{}", variable_correct);
let variable_incorrect = 35; // incorrect car non déclarré avant première action
}
```
Les variable doivent être type si le type c'est pas défini directement.
```
let tata = String::new("une chaine de caractère"); // pas besoin de spécifier le type car on voit direct que c'est une String
let toto:String; // ici on défini le type de la varible car elle n'est pas assigné directement
toto = "une chaine de caractère mais plus tard";
```
Pour les block le premier crochet toi être sur le même ligne que l'action(if, for, struct, ...)
```
if toto == True {
//correct
}
if toto == True
{
//incorrect
}
if toto = True
//incorrect
```
Autre
---------------
- Le nom des fonction doivent décrire que quel fait.
- Si un block de code revient souvent on créer une fonction.
- La longeur des ligne doivent rentrer dans l'ecrans.
- La hauteur des fonction doivent rentrer dans l'ecrans.
- Les variables dise a quoi elles servent(pas de toto) sauf pour i et j dans les boucle d'intération.
- On ne saute pas des ligne inutilement. Un saut de ligne doit séparée 2 fonctionnement ex: déclaration des variable "\n" utilisation de celle si
- On ne garde les commentaires de code que si il a vocation a être décommenté.
- Les commentaires peuvent être intéressant si le code être trop complexe a lire (ex: un calcul mathématique) mais il n'est pas obligatoire il faut pensé a réécrire le code pour le rendre plus simple plutôt que de faire des truc complexe avec un commentaire.

8
README.md Normal file
View File

@@ -0,0 +1,8 @@
#migrate table
`./diesel.sh migration run`
#Create new table
`./diesel.sh migration generate example_name`
#revert migration
`./diesel.sh migration revert`

1
diesel.sh Executable file
View File

@@ -0,0 +1 @@
sudo docker-compose run pointcloud diesel $@

5
diesel.toml Normal file
View File

@@ -0,0 +1,5 @@
# For documentation on how to configure this file,
# see diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/schema.rs"

69
docker-compose.yml Normal file
View File

@@ -0,0 +1,69 @@
version: "3.3"
services:
maps360:
build: "."
ports:
- "80:80"
volumes:
- .:/usr/src/myapp
environment:
- HOST=maps360.fr
- PORT=80
- DATABASE_URL=postgresql://admin:tempPassword1234@maps360-db/db
- MODE_INSTALL=DEV # DEV, PROD
- RUST_BACKTRACE=1
- TMPDIR=/usr/src/myapp/tmp
depends_on:
- maps360-db
labels:
- traefik.enable=true
- traefik.http.services.maps360.loadbalancer.server.port=80
- traefik.http.routers.maps360-http.entrypoints=http
- traefik.http.routers.maps360-http.rule=Host(`maps360.helodee.fr`)
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
- traefik.http.routers.maps360-http.middlewares=https-redirect@docker
- traefik.http.routers.maps360-https.entrypoints=https
- traefik.http.routers.maps360-https.rule=Host(`maps360.helodee.fr`)
- traefik.http.routers.maps360-https.tls=true
- traefik.http.routers.maps360-https.tls.certresolver=letsencrypt
networks:
- traefik
maps360-db:
image: postgres:latest
environment:
- POSTGRES_DB=db
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=tempPassword1234
volumes:
- ./persistence-db:/var/lib/postgresql/data
networks:
- traefik
maps360-adminer:
image: adminer
ports:
- 8080:8080
labels:
- traefik.enable=true
- traefik.http.services.maps360-adminer.loadbalancer.server.port=80
- traefik.http.routers.maps360-adminer-http.entrypoints=http
- traefik.http.routers.maps360-adminer-http.rule=Host(`maps360admin.helodee.fr`)
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
- traefik.http.routers.maps360-adminer-http.middlewares=https-redirect@docker
- traefik.http.routers.maps360-adminer-https.entrypoints=https
- traefik.http.routers.maps360-adminer-https.rule=Host(`maps360admin.helodee.fr`)
- traefik.http.routers.maps360-adminer-https.tls=true
- traefik.http.routers.maps360-adminer-https.tls.certresolver=letsencrypt
depends_on:
- maps360-db
networks:
- traefik
networks:
traefik:
# external:
# name: web_traefik

BIN
liblaszip.so Executable file

Binary file not shown.

BIN
minify-js Executable file

Binary file not shown.

518
rust-analyzer.json Normal file
View File

@@ -0,0 +1,518 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Setting of https://github.com/rust-analyzer/rust-analyzer",
"properties": {
"rust-analyzer.cargoRunner": {
"type": [
"null",
"string"
],
"default": null,
"description": "Custom cargo runner extension ID."
},
"rust-analyzer.runnableEnv": {
"anyOf": [
{
"type": "null"
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"mask": {
"type": "string",
"description": "Runnable name mask"
},
"env": {
"type": "object",
"description": "Variables in form of { \"key\": \"value\"}"
}
}
}
},
{
"type": "object",
"description": "Variables in form of { \"key\": \"value\"}"
}
],
"default": null,
"markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
},
"rust-analyzer.inlayHints.enable": {
"type": "boolean",
"default": true,
"description": "Whether to show inlay hints."
},
"rust-analyzer.updates.channel": {
"type": "string",
"enum": [
"stable",
"nightly"
],
"default": "stable",
"markdownEnumDescriptions": [
"`stable` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general.",
"`nightly` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**."
],
"markdownDescription": "Choose `nightly` updates to get the latest features and bug fixes every day. While `stable` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs."
},
"rust-analyzer.updates.askBeforeDownload": {
"type": "boolean",
"default": true,
"description": "Whether to ask for permission before downloading any files from the Internet."
},
"rust-analyzer.server.path": {
"type": [
"null",
"string"
],
"default": null,
"markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used"
},
"rust-analyzer.server.extraEnv": {
"type": [
"null",
"object"
],
"default": null,
"markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
},
"rust-analyzer.trace.server": {
"type": "string",
"scope": "window",
"enum": [
"off",
"messages",
"verbose"
],
"enumDescriptions": [
"No traces",
"Error only",
"Full log"
],
"default": "off",
"description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
},
"rust-analyzer.trace.extension": {
"description": "Enable logging of VS Code extensions itself.",
"type": "boolean",
"default": false
},
"rust-analyzer.debug.engine": {
"type": "string",
"enum": [
"auto",
"vadimcn.vscode-lldb",
"ms-vscode.cpptools"
],
"default": "auto",
"description": "Preferred debug engine.",
"markdownEnumDescriptions": [
"First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
"Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
"Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
]
},
"rust-analyzer.debug.sourceFileMap": {
"type": "object",
"description": "Optional source file mappings passed to the debug engine.",
"default": {
"/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
}
},
"rust-analyzer.debug.openDebugPane": {
"markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
"type": "boolean",
"default": false
},
"rust-analyzer.debug.engineSettings": {
"type": "object",
"default": {},
"markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
},
"rust-analyzer.assist.importMergeBehavior": {
"markdownDescription": "The strategy to use when inserting new imports or merging imports.",
"default": "full",
"type": "string",
"enum": [
"none",
"full",
"last"
],
"enumDescriptions": [
"No merging",
"Merge all layers of the import trees",
"Only merge the last layer of the import trees"
]
},
"rust-analyzer.assist.importPrefix": {
"markdownDescription": "The path structure for newly inserted paths to use.",
"default": "plain",
"type": "string",
"enum": [
"plain",
"by_self",
"by_crate"
],
"enumDescriptions": [
"Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
"Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.",
"Force import paths to be absolute by always starting them with `crate` or the crate name they refer to."
]
},
"rust-analyzer.assist.importGroup": {
"markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.",
"default": true,
"type": "boolean"
},
"rust-analyzer.callInfo.full": {
"markdownDescription": "Show function name and docs in parameter hints.",
"default": true,
"type": "boolean"
},
"rust-analyzer.cargo.autoreload": {
"markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` changes.",
"default": true,
"type": "boolean"
},
"rust-analyzer.cargo.allFeatures": {
"markdownDescription": "Activate all available features (`--all-features`).",
"default": false,
"type": "boolean"
},
"rust-analyzer.cargo.features": {
"markdownDescription": "List of features to activate.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.cargo.runBuildScripts": {
"markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.",
"default": true,
"type": "boolean"
},
"rust-analyzer.cargo.noDefaultFeatures": {
"markdownDescription": "Do not activate the `default` feature.",
"default": false,
"type": "boolean"
},
"rust-analyzer.cargo.target": {
"markdownDescription": "Compilation target (target triple).",
"default": null,
"type": [
"null",
"string"
]
},
"rust-analyzer.cargo.noSysroot": {
"markdownDescription": "Internal config for debugging, disables loading of sysroot crates.",
"default": false,
"type": "boolean"
},
"rust-analyzer.checkOnSave.enable": {
"markdownDescription": "Run specified `cargo check` command for diagnostics on save.",
"default": true,
"type": "boolean"
},
"rust-analyzer.checkOnSave.allFeatures": {
"markdownDescription": "Check with all features (`--all-features`).\nDefaults to `#rust-analyzer.cargo.allFeatures#`.",
"default": null,
"type": [
"null",
"boolean"
]
},
"rust-analyzer.checkOnSave.allTargets": {
"markdownDescription": "Check all targets and tests (`--all-targets`).",
"default": true,
"type": "boolean"
},
"rust-analyzer.checkOnSave.command": {
"markdownDescription": "Cargo command to use for `cargo check`.",
"default": "check",
"type": "string"
},
"rust-analyzer.checkOnSave.noDefaultFeatures": {
"markdownDescription": "Do not activate the `default` feature.",
"default": null,
"type": [
"null",
"boolean"
]
},
"rust-analyzer.checkOnSave.target": {
"markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
"default": null,
"type": [
"null",
"string"
]
},
"rust-analyzer.checkOnSave.extraArgs": {
"markdownDescription": "Extra arguments for `cargo check`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.checkOnSave.features": {
"markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.",
"default": null,
"type": [
"null",
"array"
],
"items": {
"type": "string"
}
},
"rust-analyzer.checkOnSave.overrideCommand": {
"markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nchecking. The command should include `--message-format=json` or\nsimilar option.",
"default": null,
"type": [
"null",
"array"
],
"items": {
"type": "string"
}
},
"rust-analyzer.completion.addCallArgumentSnippets": {
"markdownDescription": "Whether to add argument snippets when completing functions.",
"default": true,
"type": "boolean"
},
"rust-analyzer.completion.addCallParenthesis": {
"markdownDescription": "Whether to add parenthesis when completing functions.",
"default": true,
"type": "boolean"
},
"rust-analyzer.completion.postfix.enable": {
"markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.",
"default": true,
"type": "boolean"
},
"rust-analyzer.completion.autoimport.enable": {
"markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
"default": true,
"type": "boolean"
},
"rust-analyzer.diagnostics.enable": {
"markdownDescription": "Whether to show native rust-analyzer diagnostics.",
"default": true,
"type": "boolean"
},
"rust-analyzer.diagnostics.enableExperimental": {
"markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.",
"default": true,
"type": "boolean"
},
"rust-analyzer.diagnostics.disabled": {
"markdownDescription": "List of rust-analyzer diagnostics to disable.",
"default": [],
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
},
"rust-analyzer.diagnostics.warningsAsHint": {
"markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.diagnostics.warningsAsInfo": {
"markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.files.watcher": {
"markdownDescription": "Controls file watching implementation.",
"default": "client",
"type": "string"
},
"rust-analyzer.files.excludeDirs": {
"markdownDescription": "These directories will be ignored by rust-analyzer.",
"default": ["**/medias", "**/tmp"],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.hoverActions.debug": {
"markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hoverActions.enable": {
"markdownDescription": "Whether to show HoverActions in Rust files.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hoverActions.gotoTypeDef": {
"markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hoverActions.implementations": {
"markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hoverActions.run": {
"markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hoverActions.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.hoverActions.linksInHover": {
"markdownDescription": "Use markdown syntax for links in hover.",
"default": true,
"type": "boolean"
},
"rust-analyzer.inlayHints.chainingHints": {
"markdownDescription": "Whether to show inlay type hints for method chains.",
"default": true,
"type": "boolean"
},
"rust-analyzer.inlayHints.maxLength": {
"markdownDescription": "Maximum length for inlay hints. Default is unlimited.",
"default": null,
"type": [
"null",
"integer"
],
"minimum": 0
},
"rust-analyzer.inlayHints.parameterHints": {
"markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.",
"default": true,
"type": "boolean"
},
"rust-analyzer.inlayHints.typeHints": {
"markdownDescription": "Whether to show inlay type hints for variables.",
"default": true,
"type": "boolean"
},
"rust-analyzer.lens.debug": {
"markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.lens.enable": {
"markdownDescription": "Whether to show CodeLens in Rust files.",
"default": true,
"type": "boolean"
},
"rust-analyzer.lens.implementations": {
"markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.lens.run": {
"markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
"default": true,
"type": "boolean"
},
"rust-analyzer.lens.methodReferences": {
"markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
"default": false,
"type": "boolean"
},
"rust-analyzer.lens.references": {
"markdownDescription": "Whether to show `References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.",
"default": false,
"type": "boolean"
},
"rust-analyzer.linkedProjects": {
"markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.",
"default": [],
"type": "array",
"items": {
"type": [
"string",
"object"
]
}
},
"rust-analyzer.lruCapacity": {
"markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.",
"default": null,
"type": [
"null",
"integer"
],
"minimum": 0
},
"rust-analyzer.notifications.cargoTomlNotFound": {
"markdownDescription": "Whether to show `can't find Cargo.toml` error message.",
"default": true,
"type": "boolean"
},
"rust-analyzer.procMacro.enable": {
"markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.runBuildScripts#`.",
"default": true,
"type": "boolean"
},
"rust-analyzer.procMacro.server": {
"markdownDescription": "Internal config, path to proc-macro server executable (typically,\nthis is rust-analyzer itself, but we override this in tests).",
"default": null,
"type": [
"null",
"string"
]
},
"rust-analyzer.runnables.overrideCargo": {
"markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
"default": null,
"type": [
"null",
"string"
]
},
"rust-analyzer.runnables.cargoExtraArgs": {
"markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.rustcSource": {
"markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option is not reloaded automatically; you must restart rust-analyzer for it to take effect.",
"default": null,
"type": [
"null",
"string"
]
},
"rust-analyzer.rustfmt.extraArgs": {
"markdownDescription": "Additional arguments to `rustfmt`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.rustfmt.overrideCommand": {
"markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting.",
"default": null,
"type": [
"null",
"array"
],
"items": {
"type": "string"
}
}
}
}

81
src/main.rs Normal file
View File

@@ -0,0 +1,81 @@
#![allow(unused)]
use actix::{Actor, StreamHandler};
use actix_files::{Files, NamedFile};
use actix_form_data::{Error, Field, Value};
use actix_identity::Identity;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_multipart::Multipart;
use actix_web::{
cookie::Cookie, get, http, middleware, post, web, web::Data, web::Form, web::Path as Pathweb,
App, HttpRequest, HttpResponse, HttpServer, Responder,
};
use actix_web_actors::ws;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{fs::*, default};
use std::path::*;
use std::process::Command;
use tera::{Context, Tera};
#[macro_use]
extern crate diesel;
use diesel::prelude::*;
pub mod schema;
pub mod models;
// use models::{User, Project, Entity};
use walkdir::{DirEntry, WalkDir};
mod response;
mod util;
use util::*;
// use response::MyError;
use futures_util::TryStreamExt as _;
use std::io::Write;
use tempfile::tempfile;
use uuid::Uuid;
use std::fs::File;
use std::io::{self, prelude::*, BufReader};
#[get("/")]
async fn index(req: HttpRequest, tmpl: Data<Tera>, id: Identity) -> impl Responder {
let mut context = Context::new();
if let Some(val) = req.peer_addr() {
println!("Address {:?}", &val.ip());
context.insert("ip", &format!("{:?}", &val.ip()));
};
response::template(tmpl, "index.html.twig", &context)
}
async fn not_found(req: HttpRequest, tmpl: Data<Tera>, id: Identity) -> impl Responder {
let context = Context::new();
response::just_404(tmpl)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let tera = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
let mut folder_static = "static/";
App::new()
.app_data(Data::new(tera))
.wrap(IdentityService::new(
CookieIdentityPolicy::new(&[0; 32])
.name("maps360")
.secure(true)
.max_age_secs(60 * 60 * 24 * 7), // 1week
))
.wrap(middleware::Logger::default())
.service(index)
.service(Files::new("/static", folder_static))
.default_service(web::route().to(not_found))
})
.workers(8)
.bind(("0.0.0.0", 80))?
.run()
.await
}

741
src/models.rs Normal file
View File

@@ -0,0 +1,741 @@
use super::util::*;
use crate::schema::*;
use diesel::pg::*;
use diesel::prelude::*;
use rand::prelude::*;
use serde_json::{json, Serializer, Value};
use std::path::Path;
use std::time::*;
use uuid::Uuid;
pub fn db() -> PgConnection {
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
}
// #[derive(Debug, Queryable, Identifiable, Insertable, serde::Serialize)]
// pub struct User {
// pub id: i32,
// pub username: String,
// pub password: String,
// pub salt: String,
// pub image: String,
// pub email: String,
// pub google: String,
// pub email_valid: String,
// }
// impl User {
// pub fn create(username: String, email: String, pass_not_hashed: String) -> Result<Self, String> {
// let mut rng = rand::thread_rng();
// let y: f64 = rng.gen();
// let salt = sha256::digest(y.to_string());
// let pass_hashed = sha256::digest(format!("{}{}", &salt, &pass_not_hashed));
// let uuid = Uuid::new_v4().to_string();
// let result = diesel::insert_into(users::table)
// .values((
// users::dsl::username.eq(username),
// users::dsl::password.eq(pass_hashed),
// users::dsl::salt.eq(salt),
// users::dsl::image.eq("/static/img/default_user.svg".to_string()),
// users::dsl::email_valid.eq(uuid),
// users::dsl::email.eq(email),
// users::dsl::google.eq("".to_string()),
// ))
// .get_result(&db());
// if !result.is_err() {
// let user_session = result.unwrap();
// return Ok(user_session);
// }
// match result.err() {
// Some(x) => {
// if format!("{}", x).contains("email") {
// return Err("Un compte est déjà associé à cet Email".to_string());
// } else if format!("{}", x).contains("username") {
// return Err("Ce nom d'utilisateur est déja utilisé".to_string());
// }
// return Err("Could not create user".to_string());
// },
// None => return Err("Could not create user".to_string())
// }
// Err("Could not create user".to_string())
// }
// pub fn find_all() -> Result<Vec<Self>, String> {
// let result = users::dsl::users.get_results::<User>(&db());
// if !result.is_err() {
// let users = result.unwrap();
// return Ok(users);
// }
// Err(format!("Users not found"))
// }
// pub fn find(id: i32) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::id.eq(id))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user_session = result.unwrap();
// return Ok(user_session);
// }
// Err(format!("User {} not found", id))
// }
// pub fn update(self) -> Result<Self, String> {
// let filter = users::dsl::users.filter(users::dsl::id.eq(self.id));
// let result = diesel::update(filter)
// .set((
// users::dsl::username.eq(self.username),
// users::dsl::password.eq(self.password),
// users::dsl::salt.eq(self.salt),
// users::dsl::image.eq(self.image),
// users::dsl::email.eq(self.email),
// users::dsl::email_valid.eq(self.email_valid),
// users::dsl::google.eq(self.google),
// ))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user_session = result.unwrap();
// return Ok(user_session);
// }
// Err(format!("User {} not update", self.id))
// }
// pub fn find_by_username(username: &str) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::username.eq(&username))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User {} not find", &username))
// }
// pub fn find_by_changepass(changepass: &str) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::password.eq(&changepass))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User {} not find", &changepass))
// }
// pub fn find_by_email(email: &str) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::email.eq(&email))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User {} not find", &email))
// }
// pub fn find_by_key(key: &str) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::username.eq(&key))
// .filter(users::dsl::password.eq(""))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User {} not find", &key))
// }
// pub fn find_by_google(google: &str) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::google.eq(&google))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User by google {} not find", &google))
// }
// pub fn find_by_email_valid(email_valid: &str) -> Result<Self, String> {
// let result = users::dsl::users
// .filter(users::dsl::email_valid.eq(&email_valid))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User by email_valid {} not find", &email_valid))
// }
// pub fn generate_salt(&mut self) {
// let mut rng = rand::thread_rng();
// let y: f64 = rng.gen(); // generates a float between 0 and 1
// self.salt = sha256::digest(y.to_string())
// }
// pub fn get_projects(&self) -> Result<Vec<Project>, String> {
// let result = projects::dsl::projects
// .filter(projects::dsl::creator_id.eq(&self.id))
// .get_results::<Project>(&db());
// if !result.is_err() {
// let projects = result.unwrap();
// return Ok(projects);
// }
// Err(format!("Project {} not fetched", self.id))
// }
// pub fn get_project_accesss(&self) -> Result<Vec<ProjectAccess>, String> {
// let result = project_accesss::dsl::project_accesss
// .filter(project_accesss::dsl::user_id.eq(&self.id))
// .get_results::<ProjectAccess>(&db());
// if !result.is_err() {
// let project_accesss = result.unwrap();
// return Ok(project_accesss);
// }
// Err(format!("ProjectAccesss {} not fetched", self.id))
// }
// pub fn delete(self) -> Result<String, String> {
// let id = self.id.clone();
// let name = self.username.clone();
// let result_projects = self.get_projects();
// let projects = result_projects.unwrap();
// for project in projects {
// project.delete();
// }
// let filter_user = users::dsl::users.filter(users::dsl::id.eq(&id));
// let result_del_user = diesel::delete(filter_user)
// .returning(users::dsl::username)
// .get_result::<String>(&db());
// if result_del_user.is_err() {
// return Err(format!("User cannot be deleted in db()"));
// }
// return Ok("User was deleted".to_string());
// }
// }
// #[derive(Debug, Queryable, Identifiable, Insertable, serde::Serialize)]
// pub struct Project {
// pub id: i32,
// pub creator_id: i32,
// pub uuid: String,
// pub name: String,
// pub password: String,
// pub time_limit: SystemTime,
// pub premium: i32,
// pub is_public: bool,
// pub image: String,
// pub origin_filename: String,
// pub description: String,
// pub data: String,
// }
// impl Project {
// const FREE: i32 = 0;
// const PAID: i32 = 1;
// pub fn create(
// name: String,
// origin_filename: String,
// password: String,
// user: &User,
// ) -> Result<Self, String> {
// let result = diesel::insert_into(projects::table)
// .values((
// projects::dsl::origin_filename.eq(origin_filename),
// projects::dsl::creator_id.eq(user.id),
// projects::dsl::uuid.eq(Uuid::new_v4().to_string()),
// projects::dsl::name.eq(name),
// projects::dsl::password.eq(password),
// projects::dsl::time_limit
// .eq(SystemTime::now() + Duration::new(60 * 60 * 24 * 5, 0)), // calcul pour 5 jour en seconde
// projects::dsl::premium.eq(Project::FREE),
// projects::dsl::is_public.eq(true),
// projects::dsl::description.eq("".to_string()),
// projects::dsl::data.eq("{}".to_string()),
// ))
// .get_result(&db());
// if !result.is_err() {
// let project = result.unwrap();
// return Ok(project);
// }
// Err(format!("Project not created"))
// }
// pub fn find(id: i32) -> Result<Self, String> {
// let result = projects::dsl::projects
// .filter(projects::dsl::id.eq(id))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let project = result.unwrap();
// return Ok(project);
// }
// Err(format!("User {} not found", id))
// }
// pub fn find_by_uuid(uuid: &str) -> Result<Self, String> {
// let result = projects::dsl::projects
// .filter(projects::dsl::uuid.eq(&uuid))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let project = result.unwrap();
// return Ok(project);
// }
// Err(format!("Project {} not find", &uuid))
// }
// pub fn find_by_public(is_public: bool) -> Result<Vec<Self>, String> {
// let result = projects::dsl::projects
// .filter(projects::dsl::is_public.eq(&is_public))
// .get_results::<Project>(&db());
// if !result.is_err() {
// let projects = result.unwrap();
// return Ok(projects);
// }
// Err(format!("User {} not found", &is_public))
// }
// pub fn update(self) -> Result<Self, String> {
// let filter = projects::dsl::projects.filter(projects::dsl::id.eq(self.id));
// let result = diesel::update(filter)
// .set((
// projects::dsl::image.eq(self.image),
// projects::dsl::origin_filename.eq(self.origin_filename),
// projects::dsl::creator_id.eq(self.creator_id),
// projects::dsl::uuid.eq(self.uuid),
// projects::dsl::name.eq(self.name),
// projects::dsl::password.eq(self.password),
// projects::dsl::time_limit.eq(self.time_limit),
// projects::dsl::premium.eq(self.premium),
// projects::dsl::is_public.eq(self.is_public),
// projects::dsl::data.eq(self.data),
// projects::dsl::description.eq(self.description),
// ))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let project = result.unwrap();
// return Ok(project);
// }
// Err(format!("Project {} not update", self.id))
// }
// pub fn get_entitys(&self) -> Result<Vec<Entity>, String> {
// let result = entitys::dsl::entitys
// .filter(entitys::dsl::project_id.eq(&self.id))
// .get_results::<Entity>(&db());
// if !result.is_err() {
// let entitys = result.unwrap();
// return Ok(entitys);
// }
// Err(format!("Project entitys {} not fetched", self.id))
// }
// pub fn get_creator(&self) -> Result<User, String> {
// User::find(self.creator_id)
// }
// pub fn get_project_accesss(&self) -> Result<Vec<ProjectAccess>, String> {
// let result = project_accesss::dsl::project_accesss
// .filter(project_accesss::dsl::project_id.eq(&self.id))
// .get_results::<ProjectAccess>(&db());
// if !result.is_err() {
// let project_accesss = result.unwrap();
// return Ok(project_accesss);
// }
// Err(format!("ProjectAccesss {} not fetched", self.id))
// }
// pub fn delete(self) -> Result<String, String> {
// let result_file = std::fs::remove_dir_all(Path::new("medias").join(self.uuid));
// let filter_entity = entitys::dsl::entitys.filter(entitys::dsl::project_id.eq(&self.id));
// let result_del_entity = diesel::delete(filter_entity)
// .returning(entitys::dsl::name)
// .get_results::<String>(&db());
// if result_del_entity.is_err() {
// return Err(format!("Project delete could not remove entity in db()"));
// }
// let filter_project = projects::dsl::projects.filter(projects::dsl::id.eq(&self.id));
// let result_del_project = diesel::delete(filter_project)
// .returning(projects::dsl::name)
// .get_result::<String>(&db());
// if result_del_project.is_err() {
// return Err(format!("Project delete could not remove project in db()"));
// }
// return Ok("Project was deleted".to_string());
// }
// pub fn get_logs(&self) -> String {
// let path = Path::new("./medias")
// .join(self.uuid.clone())
// .join("cmd_logs.txt");
// if path.exists() {
// return String::from_utf8_lossy(&std::fs::read(&path).unwrap()).to_string();
// }
// "".to_string()
// }
// const CONVERTION: i32 = 0;
// const COMPLETE: i32 = 1;
// const CRASHED: i32 = 2;
// pub fn get_status(&self) -> i32 {
// let path = Path::new("./medias")
// .join(self.uuid.clone())
// .join("cmd_logs.txt");
// if path.exists() {
// let metadata = std::fs::metadata(path).unwrap();
// let modified_time = metadata.modified().unwrap().elapsed().unwrap().as_secs();
// // println!("{} > 10", modified_time);
// if modified_time > 300 {
// return Project::CRASHED;
// }
// return Project::CONVERTION;
// }
// Project::COMPLETE
// }
// pub const ACCESSREAD: i32 = 0;
// pub const ACCESSWRITE: i32 = 1;
// pub fn test_access(&self, result_user: &Result<User, String>, access_type: i32) -> bool {
// if access_type == Project::ACCESSREAD && self.is_public {
// return true;
// } else if access_type == Project::ACCESSREAD && !result_user.is_err() {
// let user = result_user.as_ref().unwrap();
// if user.id == self.creator_id {
// return true;
// }
// let result_pa = ProjectAccess::find(user.id,self.id);
// if(!result_pa.is_err()){
// let pa = result_pa.unwrap();
// if(pa.access_type == Project::ACCESSREAD || pa.access_type == Project::ACCESSWRITE){
// return true;
// }
// }
// } else if access_type == Project::ACCESSWRITE && !result_user.is_err() {
// let user = result_user.as_ref().unwrap();
// if user.id == self.creator_id {
// return true;
// }
// let result_pa = ProjectAccess::find(user.id,self.id);
// if(!result_pa.is_err()){
// let pa = result_pa.unwrap();
// if(pa.access_type == Project::ACCESSWRITE){
// return true;
// }
// }
// }
// return false;
// }
// pub fn to_json(&self) -> Value {
// let mut project_value = json!(self);
// project_value["entitys"] = json!(self.get_entitys().unwrap());
// project_value["creator"] = json!(self.get_creator().unwrap());
// project_value["cmd_logs"] = json!(self.get_logs());
// project_value["status"] = json!(self.get_status());
// project_value["data"] = self.get_data();
// let project_accesss = self.get_project_accesss().unwrap();
// let mut project_accesss_json = Vec::new();
// for project_access in project_accesss {
// project_accesss_json.push(project_access.to_json());
// }
// project_value["project_accesss"] = json!(project_accesss_json);
// project_value
// }
// pub fn duplicate(&self) -> Result<Self, String> {
// let user = User::find(self.creator_id)?;
// let mut project = Project::create(self.name.clone()+"_copy", self.origin_filename.clone(), self.password.clone(), &user)?;
// project.description = self.description.clone();
// project.is_public = self.is_public.clone();
// project = project.update().unwrap();
// let copy_result = copy_dir_all(Path::new("./medias").join(self.uuid.clone()), Path::new("./medias").join(project.uuid.clone()));
// if copy_result.is_err() {
// return Err(format!("You cannot copy {} in {}",self.uuid,project.uuid));
// }
// copy_result.unwrap();
// let entitys = self.get_entitys()?;
// for e in entitys {
// let entity = e.duplicate(&project);
// }
// return Ok(project);
// }
// pub fn set_data(&mut self, object: &Value) {
// self.data = object.to_string();
// }
// pub fn get_data(&self) -> Value {
// serde_json::from_str(self.data.as_str()).unwrap()
// }
// }
// #[derive(Debug, Queryable, Identifiable, Insertable, serde::Serialize)]
// pub struct Entity {
// pub id: i32,
// pub project_id: i32,
// pub name: String,
// pub type_entity: i32,
// pub data: String,
// pub parent_id: Option<i32>,
// }
// impl Entity {
// pub const POTREE: i32 = 0;
// pub const MODELE: i32 = 1;
// pub const IMAGE360: i32 = 2;
// pub const POTREEITEM: i32 = 3;
// pub const GROUP: i32 = 3;
// pub fn create(name: String, type_entity: i32, project: &Project) -> Result<Self, String> {
// let result = diesel::insert_into(entitys::table)
// .values((
// entitys::dsl::project_id.eq(project.id),
// entitys::dsl::name.eq(name),
// entitys::dsl::type_entity.eq(type_entity),
// entitys::dsl::data.eq(json!({}).to_string()),
// entitys::dsl::parent_id.eq(None::<i32>),
// ))
// .get_result(&db());
// if !result.is_err() {
// let entity = result.unwrap();
// return Ok(entity);
// }
// Err(format!("Entity not created"))
// }
// pub fn duplicate(&self , project: &Project) -> Result<Self, String> {
// let result = diesel::insert_into(entitys::table)
// .values((
// entitys::dsl::project_id.eq(project.id),
// entitys::dsl::name.eq(self.name.clone()),
// entitys::dsl::type_entity.eq(self.type_entity),
// entitys::dsl::data.eq(self.data.clone()),
// entitys::dsl::parent_id.eq(None::<i32>),
// ))
// .get_result(&db());
// if !result.is_err() {
// let entity = result.unwrap();
// return Ok(entity);
// }
// Err(format!("Entity not created"))
// }
// pub fn find(id: i32) -> Result<Self, String> {
// let result = entitys::dsl::entitys
// .filter(entitys::dsl::id.eq(id))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let entity = result.unwrap();
// return Ok(entity);
// }
// Err(format!("User {} not found", id))
// }
// pub fn update(self) -> Result<Self, String> {
// let filter = entitys::dsl::entitys.filter(entitys::dsl::id.eq(self.id));
// let result = diesel::update(filter)
// .set((
// entitys::dsl::project_id.eq(self.project_id),
// entitys::dsl::name.eq(self.name),
// entitys::dsl::type_entity.eq(self.type_entity),
// entitys::dsl::data.eq(self.data),
// entitys::dsl::parent_id.eq(self.parent_id),
// ))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let entity = result.unwrap();
// return Ok(entity);
// }
// Err(format!("Project {} not update", self.id))
// }
// pub fn set_data(&mut self, object: &Value) {
// self.data = object.to_string();
// }
// pub fn get_data(&self) -> Value {
// serde_json::from_str(self.data.as_str()).unwrap()
// }
// pub fn get_project(&self) -> Result<Project, String> {
// let result = projects::dsl::projects
// .filter(projects::dsl::id.eq(self.project_id))
// .get_result::<Project>(&db());
// if !result.is_err() {
// let project = result.unwrap();
// return Ok(project);
// }
// Err(format!("User {} not found", self.project_id))
// }
// pub fn find_by_name_and_project(name: String, project_id: i32) -> Vec<Entity> {
// let result = entitys::dsl::entitys
// .filter(entitys::dsl::name.eq(&name))
// .filter(entitys::dsl::project_id.eq(&project_id))
// .get_results::<Entity>(&db());
// if !result.is_err() {
// let entitys = result.unwrap();
// return entitys;
// }
// Vec::<Entity>::new()
// }
// pub fn delete(self) -> Result<String, String> {
// let id = self.id.clone();
// let name = self.name.clone();
// let result_project = self.get_project();
// if result_project.is_err() {
// return Err(format!("Entity delete could not find project"));
// }
// let project = result_project.unwrap();
// let entity_with_same_file = Entity::find_by_name_and_project(self.name, self.project_id);
// if self.type_entity != Entity::POTREEITEM && entity_with_same_file.len() <= 1 {
// let entity_path = Path::new("medias").join(project.uuid).join(&name);
// if entity_path.exists() && entity_path.is_dir() {
// let result_file = std::fs::remove_dir_all(entity_path);
// if result_file.is_err() {
// return Err(format!("Entity delete could not remove folder"));
// }
// } else if entity_path.exists() {
// let result_file = std::fs::remove_file(entity_path);
// if result_file.is_err() {
// return Err(format!("Entity delete could not remove file"));
// }
// }
// }
// let filter_entity = entitys::dsl::entitys.filter(entitys::dsl::id.eq(&id));
// let result_del_entity = diesel::delete(filter_entity)
// .returning(entitys::dsl::name)
// .get_result::<String>(&db());
// if result_del_entity.is_err() {
// return Err(format!("Entity delete could not remove project in db()"));
// }
// return Ok("Entity was deleted".to_string());
// }
// }
// #[derive(Debug, Queryable, Identifiable, Insertable, serde::Serialize)]
// pub struct ProjectAccess {
// pub id: i32,
// pub user_id: i32,
// pub project_id: i32,
// pub access_type: i32,
// }
// impl ProjectAccess {
// pub fn create(
// user: &User,
// project: &Project,
// access: i32,
// ) -> Result<Self, String> {
// let project_access_result = ProjectAccess::find(user.id, project.id);
// if !project_access_result.is_err(){
// let mut project_access = project_access_result.unwrap();
// project_access.access_type = access;
// project_access = project_access.update().unwrap();
// return Ok(project_access);
// }
// if ProjectAccess::find(user.id, project.id).is_err() {
// let result = diesel::insert_into(project_accesss::table)
// .values((
// project_accesss::dsl::user_id.eq(user.id),
// project_accesss::dsl::project_id.eq(project.id),
// project_accesss::dsl::access_type.eq(access),
// ))
// .get_result(&db());
// let pa_project = project_accesss::dsl::project_accesss
// .filter(project_accesss::dsl::project_id.eq(project.id))
// .get_results::<ProjectAccess>(&db())
// .unwrap();
// if !result.is_err() {
// let project_access = result.unwrap();
// return Ok(project_access);
// }
// }
// Err(format!("Project_Access not created"))
// }
// pub fn get_user(&self) -> Result<User, String> {
// let result = users::dsl::users
// .filter(users::dsl::id.eq(&self.user_id))
// .get_result::<User>(&db());
// if !result.is_err() {
// let user = result.unwrap();
// return Ok(user);
// }
// Err(format!("User {} not found", self.user_id))
// }
// pub fn get_project(&self) -> Result<Project, String> {
// let result = projects::dsl::projects
// .filter(projects::dsl::id.eq(&self.project_id))
// .get_result::<Project>(&db());
// if !result.is_err() {
// let project = result.unwrap();
// return Ok(project);
// }
// Err(format!("Project {} not found", self.project_id))
// }
// pub fn find(user_id: i32, project_id: i32) -> Result<Self, String> {
// let result = project_accesss::dsl::project_accesss
// .filter(project_accesss::dsl::user_id.eq(user_id))
// .filter(project_accesss::dsl::project_id.eq(project_id))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let project_access = result.unwrap();
// return Ok(project_access);
// }
// Err(format!("Project Access with project_id{} and user_id{} not found", project_id, user_id))
// }
// pub fn find_id(id: i32) -> Result<Self, String> {
// let result = project_accesss::dsl::project_accesss
// .filter(project_accesss::dsl::id.eq(id))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let project_access = result.unwrap();
// return Ok(project_access);
// }
// Err(format!("ProjectAccess {} not found", id))
// }
// pub fn update(self) -> Result<Self, String> {
// let filter = project_accesss::dsl::project_accesss.filter(project_accesss::dsl::id.eq(self.id));
// let result = diesel::update(filter)
// .set((
// project_accesss::dsl::user_id.eq(self.user_id),
// project_accesss::dsl::project_id.eq(self.project_id),
// project_accesss::dsl::access_type.eq(self.access_type),
// ))
// .get_result::<Self>(&db());
// if !result.is_err() {
// let project_access = result.unwrap();
// return Ok(project_access);
// }
// Err(format!("ProjectAccess {} not update", self.id))
// }
// pub fn delete(self) -> Result<String, String> {
// let id = self.id.clone();
// let filter_pa = project_accesss::dsl::project_accesss.filter(project_accesss::dsl::id.eq(&id));
// let result_del_pa = diesel::delete(filter_pa)
// .returning(project_accesss::dsl::id)
// .get_result::<i32>(&db());
// if result_del_pa.is_err() {
// return Err(format!("ProjectAccess cannot be deleted in db()"));
// }
// return Ok("ProjectAccess was deleted".to_string());
// }
// pub fn to_json(self) -> Value {
// let mut project_access_value = json!(self);
// project_access_value["user"] = json!(self.get_user().unwrap());
// project_access_value["project"] = json!(self.get_project().unwrap());
// project_access_value
// }
// }

79
src/response.rs Normal file
View File

@@ -0,0 +1,79 @@
use actix_files::{Files, NamedFile};
use actix_identity::Identity;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{
cookie::Cookie, get, http, middleware, post, web, web::Data, web::Form, App, HttpRequest,
HttpResponse, HttpServer, Responder,
http::{header::ContentType, StatusCode}, error::ResponseError
};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tera::{Context, Tera};
use serde_json::{json, Value};
use derive_more::{Display, Error};
// #[derive(Debug, Display)]
// pub struct MyError {
// tmpl: Tera,
// message_erreur: String,
// }
// impl MyError {
// pub fn new(_tmpl: Tera, message: &String) -> Self {
// MyError {
// tmpl: _tmpl,
// message_erreur: message.to_string(),
// }
// }
// }
// impl ResponseError for MyError {
// fn error_response(&self) -> HttpResponse {
// let context = Context::new();
// context.insert("message_erreur", &self.message_erreur);
// let result_tmpl = self.tmpl.render("catch/500.html.twig", &context);
// let body = "internal error".to_string();
// if !result_tmpl.is_err() {
// body = result_tmpl.unwrap();
// }
// HttpResponse::build(StatusCode::INTERNAL_SERVER_ERROR)
// .insert_header(ContentType::html())
// .body(body)
// }
// // fn status_code(&self) -> StatusCode {
// // match *self {
// // MyError::InternalError => StatusCode::INTERNAL_SERVER_ERROR,
// // MyError::BadClientData => StatusCode::BAD_REQUEST,
// // MyError::Timeout => StatusCode::GATEWAY_TIMEOUT,
// // }
// // }
// }
pub fn json(obj: Value) -> HttpResponse {
HttpResponse::Ok().insert_header(ContentType::json()).body(obj.to_string())
}
pub fn text(s: String) -> HttpResponse {
HttpResponse::Ok().body(s)
}
pub fn template(tmpl: Data<Tera>, name: &'static str, context: &Context) -> HttpResponse {
HttpResponse::Ok().body(tmpl.render(name, context).unwrap())
}
pub fn redirect(uri: &str) -> HttpResponse {
HttpResponse::Found()
.append_header((http::header::LOCATION, uri))
.finish()
}
pub fn just_404(tmpl: Data<Tera>) -> HttpResponse {
let context = Context::new();
HttpResponse::NotFound().body(tmpl.render("catch/404.html.twig", &context).unwrap())
// HttpResponse::NotFound().finish()
}
pub fn file(req: HttpRequest, path: PathBuf) -> HttpResponse {
NamedFile::open(path).unwrap().into_response(&req)
}

0
src/schema.rs Normal file
View File

333
src/util.rs Normal file
View File

@@ -0,0 +1,333 @@
#![allow(unused)]
// #[macro_use]
// extern crate diesel;
extern crate dotenv;
use diesel::pg::PgConnection;
use diesel::prelude::*;
use dotenv::dotenv;
use std::collections::HashMap;
use std::io::{self, Read, Seek, Write};
use std::path::Path;
use std::process::Command;
use actix_identity::Identity;
use actix_multipart::Multipart;
use futures_util::TryStreamExt as _;
use serde_json::{json, Value};
use std::fs::File;
use std::process::*;
use tempfile::NamedTempFile;
use uuid::Uuid;
use actix_web::web::Data;
use std::io::prelude::*;
use std::iter::Iterator;
// use zip::result::ZipError;
// use zip::write::FileOptions;
use walkdir::{DirEntry, WalkDir};
// use reqwest::blocking::Client;
use tera::{Context, Tera};
#[derive(Debug, Clone, serde::Serialize)]
pub struct FormData {
pub name: String,
pub content_type: String,
pub value: String,
pub filename: String,
pub path: String,
}
impl FormData {
pub fn new(_name: String, _content_type: String) -> Self {
FormData {
name: _name,
content_type: _content_type,
value: "".to_string(),
filename: "".to_string(),
path: "".to_string(),
}
}
pub fn save_file<P: AsRef<Path>>(self, path: P) {
let content = String::from_utf8_lossy(&std::fs::read(&self.path).unwrap()).to_string();
if content != "" {
std::fs::create_dir_all(&path.as_ref().parent().unwrap()).unwrap();
std::fs::rename(self.path, &path.as_ref());
}
}
}
// enum FormDataVec {
// FormData(FormData),
// FormDataVec(Vec<FormData>),
// }
pub async fn get_form_data(mut payload: Multipart) -> HashMap<String, FormData> {
let mut form_datas: HashMap<String, FormData> = HashMap::new();
let mut is_finish = false;
while !is_finish {
let mut field_result = &mut payload.try_next().await;
if field_result.is_ok() {
if let Some(field) = field_result.as_mut().unwrap() {
let mut form_data =
FormData::new(field.name().to_string(), field.content_type().to_string());
let content_disposition = field.content_disposition();
let filename_option = content_disposition.get_filename();
if filename_option.is_some() {
form_data.filename = filename_option.unwrap().to_string();
let mut f = NamedTempFile::new().unwrap();
form_data.path = f.into_temp_path().to_str().unwrap().to_string();
let mut file = std::fs::File::create(form_data.path.clone()).unwrap();
while let Some(chunk) = field.try_next().await.unwrap() {
file.write_all(&chunk);
}
} else {
let mut value = String::new();
while let Some(chunk) = field.try_next().await.unwrap() {
let str_chunk = std::str::from_utf8(&chunk).unwrap();
value.push_str(str_chunk);
}
form_data.value = value;
// field.get_result()
}
form_datas.insert(form_data.name.clone(), form_data);
} else {
is_finish = true;
}
} else {
is_finish = true;
println!("{:?}", "this form is not enctype=multipart/form-data");
}
}
return form_datas;
}
pub fn generate_key() -> String {
use rand::Rng;
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789";
const PASSWORD_LEN: usize = 10;
let mut rng = rand::thread_rng();
let password: String = (0..PASSWORD_LEN)
.map(|_| {
let idx = rng.gen_range(0..CHARSET.len());
CHARSET[idx] as char
})
.collect();
return password;
}
// pub fn get_user_session(id: &Identity) -> Result<User, String> {
// if let Some(user_id) = id.identity() {
// let result = User::find(user_id.parse::<i32>().unwrap());
// return result;
// }
// Err("Not cookie found".to_string())
// }
pub async fn convert_video<P: AsRef<Path>, Q: AsRef<Path>>(
from: P,
to: Q,
data: &Value,
quality: &'static str,
) {
let mut buffer: String;
let mut to_folder = to.as_ref().parent().unwrap();
let stdout_path = to_folder.join(format!(
"{}{}",
to.as_ref().file_name().unwrap().to_str().unwrap(),
"_stdout.txt"
));
let data_path = to_folder.join(format!(
"{}{}",
to.as_ref().file_name().unwrap().to_str().unwrap(),
"_data.json"
));
std::fs::write(&data_path, data.to_string());
let mut final_name = to.as_ref().as_os_str().to_str().unwrap();
// let mut str = final_name.to_string();
// str = str.replace(".mp4", format!("{}.mp4", quality).as_str());
// final_name = str.as_str();
println!(
"converting {:?} to {:?}",
from.as_ref().as_os_str().to_str().unwrap(),
&final_name
);
let mut cmd = Command::new("./src/soft/ffmpeg");
cmd.stdout(Stdio::from(File::create(&stdout_path).unwrap()))
.stderr(Stdio::null())
.stdin(Stdio::null())
.args([
"-y",
"-progress",
"-",
"-i",
from.as_ref().as_os_str().to_str().unwrap(),
"-vcodec",
"libx264",
"-acodec",
"aac",
"-scodec",
"mov_text",
"-map",
"V",
"-map",
"a?",
"-map",
"s?",
]);
if quality != "copy" {
cmd.args(["-s", &quality]);
}
cmd.arg(final_name);
let mut ffmpeg = cmd.spawn().expect("failed to execute child");
ffmpeg.wait();
std::fs::remove_file(&stdout_path);
std::fs::write(&data_path, get_video_data(&to).unwrap().to_string());
println!(
"converting end {:?} to {:?}",
from.as_ref().as_os_str().to_str().unwrap(),
to.as_ref().as_os_str().to_str().unwrap()
);
}
pub fn convert_e57_las<P: AsRef<Path>>(path: P) -> Result<String, String> {
let stdout_path = path.as_ref().parent().unwrap().join("cmd_logs.txt");
let mut cmd = Command::new("wine"); // wine ./src/soft/e572las.exe -v -i \"{e57filepath}\" -o \"{e57filepath}.las\
cmd.stdout(Stdio::null())
.stderr(Stdio::from(File::create(&stdout_path).unwrap()))
.stdin(Stdio::null())
.args([
"./src/soft/e572las.exe",
"-v",
"-i",
format!("{}", path.as_ref().as_os_str().to_str().unwrap()).as_str(),
"-o",
format!("{}.las", path.as_ref().as_os_str().to_str().unwrap()).as_str(),
]);
println!("{:?}", cmd);
let mut ffmpeg = cmd.spawn().expect("failed to execute wine e572las");
ffmpeg.wait();
std::fs::remove_file(&stdout_path);
// let mut output = cmd.output().expect("failed to execute wine e572las");
// let result = String::from_utf8_lossy(&output.stderr).to_string();
println!("convert_e57_las");
Ok("result".to_string())
}
pub fn convert_las_potree<P: AsRef<Path>>(path: P) -> Result<String, String> {
let stdout_path = path.as_ref().parent().unwrap().join("cmd_logs.txt");
let mut cmd = Command::new("./src/e57extractor/PotreeConverter"); // wine ./src/soft/e572las.exe -v -i \"{e57filepath}\" -o \"{e57filepath}.las\
cmd.stdout(Stdio::from(File::create(&stdout_path).unwrap()))
.stderr(Stdio::null())
.stdin(Stdio::null())
.args([
// "./src/e57extractor/PotreeConverter.exe",
format!("{}", path.as_ref().as_os_str().to_str().unwrap()).as_str(),
]);
println!("{:?}", cmd);
let mut output = cmd.output().expect("failed to execute PotreeConverter");
let fs = std::fs::File::create(
format!(
"{}_converted/sources.json",
path.as_ref().as_os_str().to_str().unwrap()
)
.as_str(),
);
let mut ffmpeg = cmd.spawn().expect("failed to execute PotreeConverter");
ffmpeg.wait();
std::fs::remove_file(&stdout_path);
// let mut output = cmd.output().expect("failed to execute PotreeConverter");
// let result = String::from_utf8_lossy(&output.stdout).to_string();
println!("convert_las_potree");
Ok("result".to_string())
}
pub fn convert_e57_images<P: AsRef<Path>>(path: P) -> Result<String, String> {
let stdout_path = path.as_ref().parent().unwrap().join("cmd_logs.txt");
let mut cmd = Command::new("python3"); // wine ./src/soft/e572las.exe -v -i \"{e57filepath}\" -o \"{e57filepath}.las\
cmd.stdout(Stdio::from(File::create(&stdout_path).unwrap()))
.stderr(Stdio::from(File::create(&stdout_path).unwrap()))
.stdin(Stdio::null())
.args([
"./src/e57extractor/",
format!("{}", path.as_ref().as_os_str().to_str().unwrap()).as_str(),
"--only-images",
]);
println!("{:?}", cmd);
let mut ffmpeg = cmd.spawn().expect("failed to execute PotreeConverter");
ffmpeg.wait();
let output = String::from_utf8_lossy(&std::fs::read(&stdout_path).unwrap()).to_string();
std::fs::remove_file(&stdout_path);
if output.contains("File contains no 2D images. Exiting...") || output.contains("E57_ERROR") {
println!("No image found");
return Err("No image found".to_string());
}
println!("convert_e57_images");
println!("{}", output);
Ok("result".to_string())
}
pub fn get_video_data<P: AsRef<Path>>(path: P) -> Result<Value, serde_json::Error> {
let mut output = Command::new("./src/soft/ffprobe")
.args([
"-print_format",
"json",
"-show_format",
"-show_streams",
"-show_chapters",
path.as_ref().as_os_str().to_str().unwrap(),
])
.output()
.expect("failed to execute ffprobe");
let str = String::from_utf8_lossy(&output.stdout).to_string();
let result: Result<Value, serde_json::Error> = serde_json::from_str(&str);
result
}
pub fn save_file_field(field: &FormData) -> String {
let extension = Path::new(&field.filename)
.extension()
.unwrap()
.to_str()
.unwrap()
.to_string();
let uuid = Uuid::new_v4().to_string();
let final_path_local =
Path::new("./static/sourcefiles").join(format!("{}.{}", uuid, extension));
let final_path = Path::new("/static/sourcefiles")
.join(format!("{}.{}", uuid, extension))
.to_str()
.unwrap()
.to_string();
std::fs::create_dir_all("./static/sourcefiles");
std::fs::rename(&field.path, &final_path_local);
return final_path;
}
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
std::fs::create_dir_all(&dst)?;
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
}
}
Ok(())
}

BIN
static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
static/img/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
static/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

6812
static/scripts/bootstrap.bundle.js vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/scripts/bootstrap.bundle.min.js vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4999
static/scripts/bootstrap.esm.js vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/scripts/bootstrap.esm.min.js vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5048
static/scripts/bootstrap.js vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/scripts/bootstrap.min.js vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
static/scripts/popper.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

5051
static/styles/bootstrap-grid.css vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/styles/bootstrap-grid.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5050
static/styles/bootstrap-grid.rtl.css vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/styles/bootstrap-grid.rtl.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

481
static/styles/bootstrap-reboot.css vendored Executable file
View File

@@ -0,0 +1,481 @@
/*!
* Bootstrap Reboot v5.1.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

8
static/styles/bootstrap-reboot.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

478
static/styles/bootstrap-reboot.rtl.css vendored Executable file
View File

@@ -0,0 +1,478 @@
/*!
* Bootstrap Reboot v5.1.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

8
static/styles/bootstrap-reboot.rtl.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4866
static/styles/bootstrap-utilities.css vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/styles/bootstrap-utilities.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4857
static/styles/bootstrap-utilities.rtl.css vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11222
static/styles/bootstrap.css vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/styles/bootstrap.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11198
static/styles/bootstrap.rtl.css vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7
static/styles/bootstrap.rtl.min.css vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,53 @@
.bg-darker {
background: #111111 !important;
}
.text-shadow {
color: white;
text-shadow: 1px 1px 1px black, -1px -1px 1px black, 1px -1px 1px black, -1px 1px 1px black;
}
.border-intern {
outline: 3px solid var(--bs-success);
outline-offset: -4px;
box-shadow: 2px 2px 0 var(--bs-success) inset, -2px -2px 0 var(--bs-success) inset !important;
}
.border-intern::after {
content: "";
outline: 3px solid var(--bs-success);
outline-offset: -4px;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
box-shadow: 2px 2px 0 var(--bs-success) inset, -2px -2px 0 var(--bs-success) inset !important;
pointer-events:none;
}
/* @media (prefers-color-scheme: dark) {
body, .card {
background: var(--bs-dark);
color: var(--bs-light);
}
* {
color: var(--bs-light);
}
.navbar {
background: black;
}
#logo {
filter: invert(1);
}
} */
.color-hover{
color:#8A8787
}
.color-hover:hover {
color:#545050
}

15
templates/base.html.twig Executable file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{% endblock title %} - MAPS360</title>
{% block head %}
{% include 'includecss.html.twig' %}
{% endblock head %}
</head>
<body>
{% block body %}{% endblock body %}
{% block footer %}{% include 'includescript.html.twig' %}{% endblock footer %}
</body>
</html>

28
templates/catch/404.html.twig Executable file
View File

@@ -0,0 +1,28 @@
{% extends 'base.html.twig' %}
{% block title %}Erreur 404{% endblock %}
{% block body %}
<div class="text-center pt-5" style="height:100vh;">
<img src="/static/img/404.png" alt="404" class="zoom-hover" style="max-width:100vw;">
<i class="h5 d-block pb-4"> La page que vous essayez d'atteindre n'existe pas ou vous n'êtes pas autorisé à la voir.</i>
<hr class="mx-5 mb-4">
<a href="/" class="btn btn-primary mdi mdi-arrow-left me-2"> Page d'accueil</a>
<a href="/login" class="btn btn-outline-primary ms-2"> Login <span class="mdi mdi-arrow-right"></span> <a/>
</div>
<style media="screen">
.zoom-hover {
transition: transform .5s ease;
}
.zoom-hover:hover {
transform: scale(1.2);
}
</style>
{% endblock %}

View File

@@ -0,0 +1,22 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Pointcloud viewer">
<meta name="author" content="https://pradierh.fr/, https://sorlinv.fr/">
<!-- Favicons -->
<link rel="apple-touch-icon" href="/static/favicon.png" sizes="180x180">
<link rel="icon" href="/static/favicon.png" type="image/png">
<link rel="mask-icon" href="/static/favicon.png" color="#7952b3">
<meta name="theme-color" content="#333333">
<link href="https://vjs.zencdn.net/7.17.0/video-js.css" rel="stylesheet" />
<link href="https://unpkg.com/@videojs/themes@1/dist/fantasy/index.css" rel="stylesheet">
<link rel="stylesheet" href="/static/styles/bootstrap.css">
<link rel="stylesheet" href="/static/styles/specific.css">
<link rel="stylesheet" href="//cdn.materialdesignicons.com/5.3.45/css/materialdesignicons.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@6.6.96/css/materialdesignicons.min.css">
<script src="https://accounts.google.com/gsi/client" async defer></script>

View File

@@ -0,0 +1,14 @@
<script src="/static/scripts/jquery-3.2.1.slim.min.js"></script>
<script src="/static/scripts/popper.min.js"></script>
<script src="/static/scripts/bootstrap.min.js"></script>
<script src="https://unpkg.com/petite-vue"></script>
<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/tippy.js@6"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" integrity="sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>
<script type="module" src="/static/scripts/specific.js"></script>

4
templates/index.html.twig Executable file
View File

@@ -0,0 +1,4 @@
{% extends 'base.html.twig' %}
{% block title %}Acceuil{% endblock %}
{% block body %}
{% endblock %}