diff --git a/.env b/.env
new file mode 100644
index 00000000..83632568
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+DATABASE_URL=postgres://admin:password@localhost/fabricate
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 00000000..7fb4bfd3
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ postgresql
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/postgres
+
+
+
\ No newline at end of file
diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
new file mode 100644
index 00000000..6df4889b
--- /dev/null
+++ b/.idea/sqldialects.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index c674092b..4b1d7e4c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -92,7 +92,7 @@ dependencies = [
"percent-encoding",
"pin-project",
"rand",
- "regex",
+ "regex 1.3.7",
"serde",
"serde_json",
"serde_urlencoded",
@@ -120,7 +120,7 @@ dependencies = [
"bytestring",
"http",
"log",
- "regex",
+ "regex 1.3.7",
"serde",
]
@@ -260,7 +260,7 @@ dependencies = [
"mime",
"net2",
"pin-project",
- "regex",
+ "regex 1.3.7",
"serde",
"serde_json",
"serde_urlencoded",
@@ -285,6 +285,15 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "aho-corasick"
version = "0.7.10"
@@ -500,6 +509,29 @@ dependencies = [
"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]]
name = "digest"
version = "0.8.1"
@@ -509,6 +541,15 @@ dependencies = [
"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]]
name = "dtoa"
version = "0.4.5"
@@ -549,6 +590,8 @@ dependencies = [
"actix-files",
"actix-rt",
"actix-web",
+ "diesel",
+ "dotenv",
"handlebars",
"meilisearch-sdk",
"serde",
@@ -1203,6 +1246,15 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "proc-macro-hack"
version = "0.5.15"
@@ -1286,16 +1338,38 @@ version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "regex"
version = "1.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
dependencies = [
- "aho-corasick",
+ "aho-corasick 0.7.10",
"memchr",
- "regex-syntax",
- "thread_local",
+ "regex-syntax 0.6.17",
+ "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]]
@@ -1459,6 +1533,15 @@ dependencies = [
"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]]
name = "thread_local"
version = "1.0.1"
@@ -1587,6 +1670,12 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+[[package]]
+name = "ucd-util"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236"
+
[[package]]
name = "unicase"
version = "2.6.0"
@@ -1643,6 +1732,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed"
+[[package]]
+name = "utf8-ranges"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
+
[[package]]
name = "v_escape"
version = "0.7.4"
@@ -1674,6 +1769,12 @@ dependencies = [
"v_escape",
]
+[[package]]
+name = "vcpkg"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
+
[[package]]
name = "version_check"
version = "0.1.5"
diff --git a/Cargo.toml b/Cargo.toml
index 473513ee..dcfc13b7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,3 +15,5 @@ serde_derive = "1.0.107"
serde = {version="1.0", features=["derive"]}
meilisearch-sdk = "0.1.1"
actix-files = "0.2.1"
+diesel = { version = "1.0.0", features = ["postgres"] }
+dotenv = "0.9.0"
diff --git a/diesel.toml b/diesel.toml
new file mode 100644
index 00000000..92267c82
--- /dev/null
+++ b/diesel.toml
@@ -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"
diff --git a/migrations/.gitkeep b/migrations/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql
new file mode 100644
index 00000000..a9f52609
--- /dev/null
+++ b/migrations/00000000000000_diesel_initial_setup/down.sql
@@ -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();
diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql
new file mode 100644
index 00000000..d68895b1
--- /dev/null
+++ b/migrations/00000000000000_diesel_initial_setup/up.sql
@@ -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;
diff --git a/migrations/2020-05-15-055106_create_mods/down.sql b/migrations/2020-05-15-055106_create_mods/down.sql
new file mode 100644
index 00000000..f060b72f
--- /dev/null
+++ b/migrations/2020-05-15-055106_create_mods/down.sql
@@ -0,0 +1 @@
+DROP TABLE mods
\ No newline at end of file
diff --git a/migrations/2020-05-15-055106_create_mods/up.sql b/migrations/2020-05-15-055106_create_mods/up.sql
new file mode 100644
index 00000000..e1609e55
--- /dev/null
+++ b/migrations/2020-05-15-055106_create_mods/up.sql
@@ -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
+)
\ No newline at end of file
diff --git a/migrations/2020-05-15-055207_create_versions/down.sql b/migrations/2020-05-15-055207_create_versions/down.sql
new file mode 100644
index 00000000..7a3f850b
--- /dev/null
+++ b/migrations/2020-05-15-055207_create_versions/down.sql
@@ -0,0 +1 @@
+DROP TABLE versions
\ No newline at end of file
diff --git a/migrations/2020-05-15-055207_create_versions/up.sql b/migrations/2020-05-15-055207_create_versions/up.sql
new file mode 100644
index 00000000..5db90b30
--- /dev/null
+++ b/migrations/2020-05-15-055207_create_versions/up.sql
@@ -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
+)
\ No newline at end of file
diff --git a/src/database/database.rs b/src/database/database.rs
new file mode 100644
index 00000000..6625fcfc
--- /dev/null
+++ b/src/database/database.rs
@@ -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))
+}
\ No newline at end of file
diff --git a/src/database/mod.rs b/src/database/mod.rs
new file mode 100644
index 00000000..f9674f87
--- /dev/null
+++ b/src/database/mod.rs
@@ -0,0 +1,6 @@
+mod database;
+mod models;
+
+pub use database::connect;
+pub use models::Mod;
+pub use models::Version;
\ No newline at end of file
diff --git a/src/database/models.rs b/src/database/models.rs
new file mode 100644
index 00000000..13d1a9f8
--- /dev/null
+++ b/src/database/models.rs
@@ -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,
+ 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,
+ pub date_published: String,
+ pub author: String,
+ pub downloads: i32,
+ pub dependencies: Vec,
+ pub game_versions: Vec
+}
+
diff --git a/src/helpers/contains.rs b/src/helpers/contains.rs
new file mode 100644
index 00000000..cca5ce29
--- /dev/null
+++ b/src/helpers/contains.rs
@@ -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::>(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(()),
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs
new file mode 100644
index 00000000..d02c7c60
--- /dev/null
+++ b/src/helpers/mod.rs
@@ -0,0 +1,3 @@
+mod contains;
+
+pub use contains::ContainsHelper;
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 439028ca..4e42ea76 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,179 +1,43 @@
#[macro_use]
extern crate serde_json;
+#[macro_use]
+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 actix_files as fs;
-#[derive(Clone, Copy)]
-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::>(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,
- versions: Vec,
-}
-
-impl Document for Mod {
- type UIDType = usize;
-
- fn get_uid(&self) -> &Self::UIDType {
- &self.mod_id
- }
-}
-
-
-#[derive(Deserialize)]
-pub struct SearchRequest {
- q: Option,
- f: Option,
- v: Option,
-}
-
-#[post("search")]
-async fn search_post(web::Query(info): web::Query, hb: Data>) -> 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, hb: Data>) -> 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) -> Vec {
- 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::(&query).unwrap().hits
-}
-
-#[get("/")]
-async fn index(hb: web::Data>) -> HttpResponse {
- let data = json!({
- "name": "Handlebars"
- });
- let body = hb.render("index", &data).unwrap();
-
- HttpResponse::Ok().body(body)
-}
+mod schema;
+mod routes;
+mod helpers;
+mod database;
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
//Handlebars
let mut handlebars = Handlebars::new();
- handlebars.register_helper("contains", Box::new(ContainsHelper));
+ handlebars.register_helper("contains", Box::new(helpers::ContainsHelper));
handlebars
.register_templates_directory(".hbs", "./templates")
.unwrap();
let handlebars_ref = web::Data::new(handlebars);
- //Search
-
- 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();
+ let database = database::connect();
+ routes::index_mods(database);
//Init App
HttpServer::new(move || {
App::new()
.app_data(handlebars_ref.clone())
.service(fs::Files::new("/static", "./static").show_files_listing())
- .service(index)
- .service(search_get)
- .service(search_post)
+ .service(routes::index_get)
+ .service(routes::search_post)
+ .service(routes::search_get)
})
.bind("127.0.0.1:8000")?
.run()
diff --git a/src/routes/index.rs b/src/routes/index.rs
new file mode 100644
index 00000000..2b13d096
--- /dev/null
+++ b/src/routes/index.rs
@@ -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>) -> HttpResponse {
+ let data = json!({
+ "name": "Handlebars"
+ });
+ let body = hb.render("index", &data).unwrap();
+
+ HttpResponse::Ok().body(body)
+}
\ No newline at end of file
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
new file mode 100644
index 00000000..67e9b83f
--- /dev/null
+++ b/src/routes/mod.rs
@@ -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;
\ No newline at end of file
diff --git a/src/routes/search.rs b/src/routes/search.rs
new file mode 100644
index 00000000..495e51c3
--- /dev/null
+++ b/src/routes/search.rs
@@ -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,
+ versions: Vec,
+}
+
+impl Document for SearchMod {
+ type UIDType = i32;
+
+ fn get_uid(&self) -> &Self::UIDType {
+ &self.mod_id
+ }
+}
+
+#[derive(Deserialize)]
+pub struct SearchRequest {
+ q: Option,
+ f: Option,
+ v: Option,
+}
+
+#[post("search")]
+pub async fn search_post(web::Query(info): web::Query, hb: Data>) -> 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, hb: Data>) -> 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) -> Vec {
+ 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::(&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::(&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::(&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"));
+
+}
\ No newline at end of file
diff --git a/src/schema.rs b/src/schema.rs
new file mode 100644
index 00000000..b74a7ca5
--- /dev/null
+++ b/src/schema.rs
@@ -0,0 +1,33 @@
+table! {
+ mods (id) {
+ id -> Int4,
+ title -> Varchar,
+ description -> Varchar,
+ datepublished -> Date,
+ author -> Varchar,
+ downloads -> Int4,
+ categories -> Array,
+ body_path -> Varchar,
+ icon_path -> Varchar,
+ }
+}
+
+table! {
+ versions (id) {
+ id -> Int4,
+ mod_id -> Int4,
+ title -> Varchar,
+ changelog_path -> Varchar,
+ files_path -> Array,
+ date_published -> Date,
+ author -> Varchar,
+ downloads -> Int4,
+ dependencies -> Array,
+ game_versions -> Array,
+ }
+}
+
+allow_tables_to_appear_in_same_query!(
+ mods,
+ versions,
+);