You've already forked AstralRinth
forked from didirus/AstralRinth
Basic Database
This commit is contained in:
1
.env
Normal file
1
.env
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DATABASE_URL=postgres://admin:password@localhost/fabricate
|
||||||
11
.idea/dataSources.xml
generated
Normal file
11
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="postgres@localhost/fabricate" uuid="78c95043-78e4-4469-8d73-d6d45e07a4f1">
|
||||||
|
<driver-ref>postgresql</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:postgresql://localhost:5432/postgres</jdbc-url>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/sqldialects.xml
generated
Normal file
6
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="PROJECT" dialect="PostgreSQL" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
113
Cargo.lock
generated
113
Cargo.lock
generated
@@ -92,7 +92,7 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex 1.3.7",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
@@ -120,7 +120,7 @@ dependencies = [
|
|||||||
"bytestring",
|
"bytestring",
|
||||||
"http",
|
"http",
|
||||||
"log",
|
"log",
|
||||||
"regex",
|
"regex 1.3.7",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ dependencies = [
|
|||||||
"mime",
|
"mime",
|
||||||
"net2",
|
"net2",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"regex",
|
"regex 1.3.7",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
@@ -285,6 +285,15 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.6.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
@@ -500,6 +509,29 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel"
|
||||||
|
version = "1.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33d7ca63eb2efea87a7f56a283acc49e2ce4b2bd54adf7465dc1d81fef13d8fc"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"byteorder",
|
||||||
|
"diesel_derives",
|
||||||
|
"pq-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel_derives"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@@ -509,6 +541,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dotenv"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "400b347fe65ccfbd8f545c9d9a75d04b0caf23fec49aaa838a9a05398f94c019"
|
||||||
|
dependencies = [
|
||||||
|
"regex 0.2.11",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
@@ -549,6 +590,8 @@ dependencies = [
|
|||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
"diesel",
|
||||||
|
"dotenv",
|
||||||
"handlebars",
|
"handlebars",
|
||||||
"meilisearch-sdk",
|
"meilisearch-sdk",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1203,6 +1246,15 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pq-sys"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
|
||||||
|
dependencies = [
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.15"
|
version = "0.5.15"
|
||||||
@@ -1286,16 +1338,38 @@ version = "0.1.56"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick 0.6.10",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax 0.5.6",
|
||||||
|
"thread_local 0.3.6",
|
||||||
|
"utf8-ranges",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.3.7"
|
version = "1.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
|
checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick 0.7.10",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.6.17",
|
||||||
"thread_local",
|
"thread_local 1.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||||
|
dependencies = [
|
||||||
|
"ucd-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1459,6 +1533,15 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -1587,6 +1670,12 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ucd-util"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@@ -1643,6 +1732,12 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed"
|
checksum = "3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-ranges"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "v_escape"
|
name = "v_escape"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
@@ -1674,6 +1769,12 @@ dependencies = [
|
|||||||
"v_escape",
|
"v_escape",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|||||||
@@ -15,3 +15,5 @@ serde_derive = "1.0.107"
|
|||||||
serde = {version="1.0", features=["derive"]}
|
serde = {version="1.0", features=["derive"]}
|
||||||
meilisearch-sdk = "0.1.1"
|
meilisearch-sdk = "0.1.1"
|
||||||
actix-files = "0.2.1"
|
actix-files = "0.2.1"
|
||||||
|
diesel = { version = "1.0.0", features = ["postgres"] }
|
||||||
|
dotenv = "0.9.0"
|
||||||
|
|||||||
5
diesel.toml
Normal file
5
diesel.toml
Normal 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"
|
||||||
0
migrations/.gitkeep
Normal file
0
migrations/.gitkeep
Normal file
6
migrations/00000000000000_diesel_initial_setup/down.sql
Normal file
6
migrations/00000000000000_diesel_initial_setup/down.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
-- This file was automatically created by Diesel to setup helper functions
|
||||||
|
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||||
|
-- changes will be added to existing projects as new migrations.
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
|
||||||
|
DROP FUNCTION IF EXISTS diesel_set_updated_at();
|
||||||
36
migrations/00000000000000_diesel_initial_setup/up.sql
Normal file
36
migrations/00000000000000_diesel_initial_setup/up.sql
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
-- This file was automatically created by Diesel to setup helper functions
|
||||||
|
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||||
|
-- changes will be added to existing projects as new migrations.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Sets up a trigger for the given table to automatically set a column called
|
||||||
|
-- `updated_at` whenever the row is modified (unless `updated_at` was included
|
||||||
|
-- in the modified columns)
|
||||||
|
--
|
||||||
|
-- # Example
|
||||||
|
--
|
||||||
|
-- ```sql
|
||||||
|
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
|
||||||
|
--
|
||||||
|
-- SELECT diesel_manage_updated_at('users');
|
||||||
|
-- ```
|
||||||
|
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
|
||||||
|
BEGIN
|
||||||
|
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
|
||||||
|
BEGIN
|
||||||
|
IF (
|
||||||
|
NEW IS DISTINCT FROM OLD AND
|
||||||
|
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
|
||||||
|
) THEN
|
||||||
|
NEW.updated_at := current_timestamp;
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
1
migrations/2020-05-15-055106_create_mods/down.sql
Normal file
1
migrations/2020-05-15-055106_create_mods/down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE mods
|
||||||
11
migrations/2020-05-15-055106_create_mods/up.sql
Normal file
11
migrations/2020-05-15-055106_create_mods/up.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE mods (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
title VARCHAR NOT NULL,
|
||||||
|
description VARCHAR NOT NULL,
|
||||||
|
datePublished DATE NOT NULL,
|
||||||
|
author VARCHAR NOT NULL,
|
||||||
|
downloads INTEGER NOT NULL DEFAULT 0,
|
||||||
|
categories TEXT[] NOT NULL,
|
||||||
|
body_path VARCHAR NOT NULL,
|
||||||
|
icon_path VARCHAR NOT NULL
|
||||||
|
)
|
||||||
1
migrations/2020-05-15-055207_create_versions/down.sql
Normal file
1
migrations/2020-05-15-055207_create_versions/down.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE versions
|
||||||
12
migrations/2020-05-15-055207_create_versions/up.sql
Normal file
12
migrations/2020-05-15-055207_create_versions/up.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
CREATE TABLE versions (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
mod_id SERIAL NOT NULL,
|
||||||
|
title VARCHAR NOT NULL,
|
||||||
|
changelog_path VARCHAR NOT NULL,
|
||||||
|
files_path TEXT[] NOT NULL,
|
||||||
|
date_published DATE NOT NULL,
|
||||||
|
author VARCHAR NOT NULL,
|
||||||
|
downloads INTEGER NOT NULL DEFAULT 0,
|
||||||
|
dependencies TEXT[] NOT NULL,
|
||||||
|
game_versions TEXT[] NOT NULL
|
||||||
|
)
|
||||||
11
src/database/database.rs
Normal file
11
src/database/database.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::pg::PgConnection;
|
||||||
|
use dotenv::dotenv;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub fn connect() -> PgConnection{
|
||||||
|
dotenv.ok();
|
||||||
|
|
||||||
|
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set!");
|
||||||
|
PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
|
||||||
|
}
|
||||||
6
src/database/mod.rs
Normal file
6
src/database/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
mod database;
|
||||||
|
mod models;
|
||||||
|
|
||||||
|
pub use database::connect;
|
||||||
|
pub use models::Mod;
|
||||||
|
pub use models::Version;
|
||||||
31
src/database/models.rs
Normal file
31
src/database/models.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::schema::mods;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
pub struct Mod {
|
||||||
|
pub id: i32,
|
||||||
|
pub title: String,
|
||||||
|
pub description: String,
|
||||||
|
pub published: String,
|
||||||
|
pub author: String,
|
||||||
|
pub downloads: i32,
|
||||||
|
pub categories: Vec<String>,
|
||||||
|
pub body_path: String,
|
||||||
|
pub icon_path: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
pub struct Version {
|
||||||
|
pub id: i32,
|
||||||
|
pub mod_id: i32,
|
||||||
|
pub title: String,
|
||||||
|
pub changelog_path: String,
|
||||||
|
pub files_path: Vec<String>,
|
||||||
|
pub date_published: String,
|
||||||
|
pub author: String,
|
||||||
|
pub downloads: i32,
|
||||||
|
pub dependencies: Vec<String>,
|
||||||
|
pub game_versions: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
18
src/helpers/contains.rs
Normal file
18
src/helpers/contains.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use handlebars::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct ContainsHelper;
|
||||||
|
|
||||||
|
impl HelperDef for ContainsHelper {
|
||||||
|
fn call<'reg: 'rc, 'rc>(&self, h: &Helper<'reg, 'rc>, r: &'reg Handlebars<'_>, ctx: &'rc Context, rc: &mut RenderContext<'reg, 'rc>, out: &mut dyn Output) -> HelperResult {
|
||||||
|
let array = h.param(0).map(|v| serde_json::from_value::<Vec<String>>(v.value().clone()).unwrap()).ok_or(RenderError::new("Parameter not found!"))?;
|
||||||
|
let value = h.param(1).map(|v| v.value().as_str().unwrap()).ok_or(RenderError::new("Parameter not found!"))?;
|
||||||
|
|
||||||
|
let tmpl = if array.contains(&String::from(value)) { h.template() } else { h.inverse() };
|
||||||
|
|
||||||
|
match tmpl {
|
||||||
|
Some(ref t) => t.render(r, ctx, rc, out),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/helpers/mod.rs
Normal file
3
src/helpers/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
mod contains;
|
||||||
|
|
||||||
|
pub use contains::ContainsHelper;
|
||||||
162
src/main.rs
162
src/main.rs
@@ -1,179 +1,43 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate diesel;
|
||||||
|
|
||||||
use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post};
|
use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post};
|
||||||
use handlebars::*;
|
use handlebars::*;
|
||||||
use meilisearch_sdk::{document::*, indexes::*, client::*, search::*};
|
use meilisearch_sdk::{document::*, indexes::*, client::*, search::*};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use actix_files as fs;
|
use actix_files as fs;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
mod schema;
|
||||||
struct ContainsHelper;
|
mod routes;
|
||||||
|
mod helpers;
|
||||||
impl HelperDef for ContainsHelper {
|
mod database;
|
||||||
fn call<'reg: 'rc, 'rc>(&self, h: &Helper<'reg, 'rc>, r: &'reg Handlebars<'_>, ctx: &'rc Context, rc: &mut RenderContext<'reg, 'rc>, out: &mut dyn Output) -> HelperResult {
|
|
||||||
let array = h.param(0).map(|v| serde_json::from_value::<Vec<String>>(v.value().clone()).unwrap()).ok_or(RenderError::new("Parameter not found!"))?;
|
|
||||||
let value = h.param(1).map(|v| v.value().as_str().unwrap()).ok_or(RenderError::new("Parameter not found!"))?;
|
|
||||||
|
|
||||||
let tmpl = if array.contains(&String::from(value)) { h.template() } else { h.inverse() };
|
|
||||||
|
|
||||||
match tmpl {
|
|
||||||
Some(ref t) => t.render(r, ctx, rc, out),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct Mod {
|
|
||||||
mod_id: usize,
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
keywords: Vec<String>,
|
|
||||||
versions: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Document for Mod {
|
|
||||||
type UIDType = usize;
|
|
||||||
|
|
||||||
fn get_uid(&self) -> &Self::UIDType {
|
|
||||||
&self.mod_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct SearchRequest {
|
|
||||||
q: Option<String>,
|
|
||||||
f: Option<String>,
|
|
||||||
v: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("search")]
|
|
||||||
async fn search_post(web::Query(info): web::Query<SearchRequest>, hb: Data<Handlebars<'_>>) -> HttpResponse {
|
|
||||||
let results = search(web::Query(info));
|
|
||||||
|
|
||||||
let data = json!({
|
|
||||||
"results": results,
|
|
||||||
});
|
|
||||||
|
|
||||||
let body = hb.render("search_results", &data).unwrap();
|
|
||||||
|
|
||||||
HttpResponse::Ok().body(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("search")]
|
|
||||||
async fn search_get(web::Query(info): web::Query<SearchRequest>, hb: Data<Handlebars<'_>>) -> HttpResponse {
|
|
||||||
let results = search(web::Query(info));
|
|
||||||
|
|
||||||
let data = json!({
|
|
||||||
"results": results,
|
|
||||||
});
|
|
||||||
|
|
||||||
let body = hb.render("search", &data).unwrap();
|
|
||||||
|
|
||||||
HttpResponse::Ok().body(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search(web::Query(info): web::Query<SearchRequest>) -> Vec<Mod> {
|
|
||||||
let client = Client::new("http://localhost:7700", "");
|
|
||||||
|
|
||||||
let mut search_query = "".to_string();
|
|
||||||
let mut filters = "".to_string();
|
|
||||||
|
|
||||||
|
|
||||||
if let Some(q) = info.q {
|
|
||||||
search_query = q;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(f) = info.f {
|
|
||||||
filters = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(v) = info.v {
|
|
||||||
if filters.is_empty() {
|
|
||||||
filters = v;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
filters = format!("({}) AND {}", filters, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut query = Query::new(&search_query).with_limit(10);
|
|
||||||
|
|
||||||
if !filters.is_empty() {
|
|
||||||
query = Query::new(&search_query).with_limit(10).with_filters(&filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
client.get_index("mods").unwrap().search::<Mod>(&query).unwrap().hits
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
async fn index(hb: web::Data<Handlebars<'_>>) -> HttpResponse {
|
|
||||||
let data = json!({
|
|
||||||
"name": "Handlebars"
|
|
||||||
});
|
|
||||||
let body = hb.render("index", &data).unwrap();
|
|
||||||
|
|
||||||
HttpResponse::Ok().body(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::main]
|
#[actix_rt::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
//Handlebars
|
//Handlebars
|
||||||
let mut handlebars = Handlebars::new();
|
let mut handlebars = Handlebars::new();
|
||||||
|
|
||||||
handlebars.register_helper("contains", Box::new(ContainsHelper));
|
handlebars.register_helper("contains", Box::new(helpers::ContainsHelper));
|
||||||
handlebars
|
handlebars
|
||||||
.register_templates_directory(".hbs", "./templates")
|
.register_templates_directory(".hbs", "./templates")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let handlebars_ref = web::Data::new(handlebars);
|
let handlebars_ref = web::Data::new(handlebars);
|
||||||
|
|
||||||
//Search
|
let database = database::connect();
|
||||||
|
routes::index_mods(database);
|
||||||
let client = Client::new("http://localhost:7700", "");
|
|
||||||
let mut mods = client.get_or_create("mods").unwrap();
|
|
||||||
|
|
||||||
mods.add_documents(vec![
|
|
||||||
Mod {
|
|
||||||
mod_id: 0,
|
|
||||||
title: String::from("Magic Mod"),
|
|
||||||
description: String::from("An illustrious magic mod for magical wizards"),
|
|
||||||
keywords: vec![String::from("fabric"), String::from("magic"), String::from("library")],
|
|
||||||
versions: vec![String::from("1.15.2"), String::from("1.15.1"), String::from("1.15")],
|
|
||||||
},
|
|
||||||
Mod {
|
|
||||||
mod_id: 1,
|
|
||||||
title: String::from("Tech Mod"),
|
|
||||||
description: String::from("An technological mod for complete NERDS"),
|
|
||||||
keywords: vec![String::from("fabric"), String::from("utility"), String::from("technology")],
|
|
||||||
versions: vec![String::from("1.14.1"), String::from("1.15.1"), String::from("1.15")],
|
|
||||||
},
|
|
||||||
Mod {
|
|
||||||
mod_id: 2,
|
|
||||||
title: String::from("Gamer Mod"),
|
|
||||||
description: String::from("A gamer mod to roleplay as if you were an epic gamer person."),
|
|
||||||
keywords: vec![String::from("cursed"), String::from("adventure"), String::from("forge")],
|
|
||||||
versions: vec![String::from("20w20a"), String::from("1.15.1"), String::from("1.15")],
|
|
||||||
},
|
|
||||||
Mod {
|
|
||||||
mod_id: 3,
|
|
||||||
title: String::from("Adventure Mod"),
|
|
||||||
description: String::from("An epic gamer adventure mod for epic adventure gamers"),
|
|
||||||
keywords: vec![String::from("decoration"), String::from("utility"), String::from("worldgen")],
|
|
||||||
versions: vec![String::from("1.12.2"), String::from("1.15.1"), String::from("1.15")]
|
|
||||||
},
|
|
||||||
], Some("mod_id")).unwrap();
|
|
||||||
|
|
||||||
//Init App
|
//Init App
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(handlebars_ref.clone())
|
.app_data(handlebars_ref.clone())
|
||||||
.service(fs::Files::new("/static", "./static").show_files_listing())
|
.service(fs::Files::new("/static", "./static").show_files_listing())
|
||||||
.service(index)
|
.service(routes::index_get)
|
||||||
.service(search_get)
|
.service(routes::search_post)
|
||||||
.service(search_post)
|
.service(routes::search_get)
|
||||||
})
|
})
|
||||||
.bind("127.0.0.1:8000")?
|
.bind("127.0.0.1:8000")?
|
||||||
.run()
|
.run()
|
||||||
|
|||||||
12
src/routes/index.rs
Normal file
12
src/routes/index.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post};
|
||||||
|
use handlebars::*;
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
pub async fn index_get(hb: web::Data<Handlebars<'_>>) -> HttpResponse {
|
||||||
|
let data = json!({
|
||||||
|
"name": "Handlebars"
|
||||||
|
});
|
||||||
|
let body = hb.render("index", &data).unwrap();
|
||||||
|
|
||||||
|
HttpResponse::Ok().body(body)
|
||||||
|
}
|
||||||
8
src/routes/mod.rs
Normal file
8
src/routes/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
mod search;
|
||||||
|
mod index;
|
||||||
|
|
||||||
|
pub use self::search::search_get;
|
||||||
|
pub use self::search::search_post;
|
||||||
|
pub use self::search::index_mods;
|
||||||
|
|
||||||
|
pub use self::index::index_get;
|
||||||
125
src/routes/search.rs
Normal file
125
src/routes/search.rs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
extern crate diesel;
|
||||||
|
|
||||||
|
use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post};
|
||||||
|
use handlebars::*;
|
||||||
|
use meilisearch_sdk::{document::*, indexes::*, client::*, search::*};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
use crate::database::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use std::ptr::eq;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct SearchMod {
|
||||||
|
mod_id: i32,
|
||||||
|
title: String,
|
||||||
|
description: String,
|
||||||
|
keywords: Vec<String>,
|
||||||
|
versions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Document for SearchMod {
|
||||||
|
type UIDType = i32;
|
||||||
|
|
||||||
|
fn get_uid(&self) -> &Self::UIDType {
|
||||||
|
&self.mod_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct SearchRequest {
|
||||||
|
q: Option<String>,
|
||||||
|
f: Option<String>,
|
||||||
|
v: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("search")]
|
||||||
|
pub async fn search_post(web::Query(info): web::Query<SearchRequest>, hb: Data<Handlebars<'_>>) -> HttpResponse {
|
||||||
|
let results = search(web::Query(info));
|
||||||
|
|
||||||
|
let data = json!({
|
||||||
|
"results": results,
|
||||||
|
});
|
||||||
|
|
||||||
|
let body = hb.render("search_results", &data).unwrap();
|
||||||
|
|
||||||
|
HttpResponse::Ok().body(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("search")]
|
||||||
|
pub async fn search_get(web::Query(info): web::Query<SearchRequest>, hb: Data<Handlebars<'_>>) -> HttpResponse {
|
||||||
|
let results = search(web::Query(info));
|
||||||
|
|
||||||
|
let data = json!({
|
||||||
|
"results": results,
|
||||||
|
});
|
||||||
|
|
||||||
|
let body = hb.render("search", &data).unwrap();
|
||||||
|
|
||||||
|
HttpResponse::Ok().body(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search(web::Query(info): web::Query<SearchRequest>) -> Vec<SearchMod> {
|
||||||
|
let client = Client::new("http://localhost:7700", "");
|
||||||
|
|
||||||
|
let mut search_query = "".to_string();
|
||||||
|
let mut filters = "".to_string();
|
||||||
|
|
||||||
|
|
||||||
|
if let Some(q) = info.q {
|
||||||
|
search_query = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(f) = info.f {
|
||||||
|
filters = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = info.v {
|
||||||
|
if filters.is_empty() {
|
||||||
|
filters = v;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
filters = format!("({}) AND {}", filters, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut query = Query::new(&search_query).with_limit(10);
|
||||||
|
|
||||||
|
if !filters.is_empty() {
|
||||||
|
query = Query::new(&search_query).with_limit(10).with_filters(&filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.get_index("mods").unwrap().search::<SearchMod>(&query).unwrap().hits
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index_mods(conn : PgConnection) {
|
||||||
|
use crate::schema::mods::dsl::*;
|
||||||
|
use crate::schema::versions::dsl::*;
|
||||||
|
|
||||||
|
let client = Client::new("http://localhost:7700", "");
|
||||||
|
let mut mods_index = client.get_or_create("mods").unwrap();
|
||||||
|
|
||||||
|
let results = mods.load::<Mod>(&conn).expect("Error loading mods!");
|
||||||
|
let mut docs_to_add = vec![];
|
||||||
|
|
||||||
|
for result in results {
|
||||||
|
let versions = versions.filter(mod_id.eq(result.id)).load::<Version>(&conn).expect("Error loading versions!");
|
||||||
|
|
||||||
|
let mut mod_versions = vec![];
|
||||||
|
|
||||||
|
for version in versions {
|
||||||
|
mod_versions.append(version.game_versions())
|
||||||
|
}
|
||||||
|
|
||||||
|
docs_to_add.push(SearchMod {
|
||||||
|
mod_id: result.id,
|
||||||
|
title: result.title,
|
||||||
|
description: result.description,
|
||||||
|
keywords: result.categories,
|
||||||
|
versions: vec![]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mods_index.add_documents(docs_to_add, Some("mod_id"));
|
||||||
|
|
||||||
|
}
|
||||||
33
src/schema.rs
Normal file
33
src/schema.rs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
table! {
|
||||||
|
mods (id) {
|
||||||
|
id -> Int4,
|
||||||
|
title -> Varchar,
|
||||||
|
description -> Varchar,
|
||||||
|
datepublished -> Date,
|
||||||
|
author -> Varchar,
|
||||||
|
downloads -> Int4,
|
||||||
|
categories -> Array<Text>,
|
||||||
|
body_path -> Varchar,
|
||||||
|
icon_path -> Varchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
versions (id) {
|
||||||
|
id -> Int4,
|
||||||
|
mod_id -> Int4,
|
||||||
|
title -> Varchar,
|
||||||
|
changelog_path -> Varchar,
|
||||||
|
files_path -> Array<Text>,
|
||||||
|
date_published -> Date,
|
||||||
|
author -> Varchar,
|
||||||
|
downloads -> Int4,
|
||||||
|
dependencies -> Array<Text>,
|
||||||
|
game_versions -> Array<Text>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_tables_to_appear_in_same_query!(
|
||||||
|
mods,
|
||||||
|
versions,
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user