Compare commits
5 Commits
5e9d0bf554
...
c2cb1f861d
Author | SHA1 | Date |
---|---|---|
Augusto Gunsch | c2cb1f861d | |
Augusto Gunsch | 8925fb87a9 | |
Augusto Gunsch | 47f65f8a96 | |
Augusto Gunsch | 191146da4b | |
Augusto Gunsch | ce485b733e |
|
@ -1,7 +1,10 @@
|
|||
use std::fs;
|
||||
use std::io::ErrorKind;
|
||||
use std::process::exit;
|
||||
|
||||
use reqwest;
|
||||
use rusqlite::{Connection, Transaction};
|
||||
use rusqlite::{Connection, Transaction, ErrorCode};
|
||||
use rusqlite::Error::SqliteFailure;
|
||||
use rusqlite::params;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
|
@ -10,34 +13,63 @@ use serde_json;
|
|||
use crate::language::Language;
|
||||
use crate::entry::{WiktionaryEntries, WiktionaryEntry};
|
||||
use crate::entry::Form;
|
||||
use crate::{MAJOR, MINOR, PATCH};
|
||||
|
||||
const DB_DIR: &str = "/usr/share/inflectived/";
|
||||
const CACHE_DIR: &str = "/var/cache/";
|
||||
|
||||
/// A database of Wiktionary entries
|
||||
pub struct WordDb {
|
||||
connection: String
|
||||
db_path: String
|
||||
}
|
||||
|
||||
impl WordDb {
|
||||
pub fn new(db_path: &str) -> Self {
|
||||
Self {
|
||||
connection: String::from(db_path)
|
||||
}
|
||||
pub fn new(db_name: &str) -> Self {
|
||||
let mut db_path = String::from(DB_DIR);
|
||||
db_path.push_str(db_name);
|
||||
|
||||
Self { db_path }
|
||||
}
|
||||
|
||||
pub fn connect(&self) -> Connection {
|
||||
Connection::open(&self.connection).unwrap()
|
||||
Connection::open(&self.db_path).unwrap()
|
||||
}
|
||||
|
||||
pub fn clean_tables(&mut self, lang: &Language) {
|
||||
let mut conn = self.connect();
|
||||
let transaction = conn.transaction().unwrap();
|
||||
|
||||
if let Err(e) = transaction.execute("
|
||||
CREATE TABLE IF NOT EXISTS langs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
code TINYTEXT UNIQUE NOT NULL,
|
||||
name TINYTEXT NOT NULL,
|
||||
major INTEGER NOT NULL,
|
||||
minor INTEGER NOT NULL,
|
||||
patch INTEGER NOT NULL
|
||||
)", []) {
|
||||
match e {
|
||||
SqliteFailure(f, _) => match f.code {
|
||||
ErrorCode::ReadOnly => {
|
||||
eprintln!("Could not write to database: Permission denied");
|
||||
eprintln!("Please run as root");
|
||||
exit(1);
|
||||
},
|
||||
_ => panic!("{}", e)
|
||||
},
|
||||
_ => panic!("{}", e)
|
||||
}
|
||||
}
|
||||
|
||||
transaction.execute("DELETE FROM langs WHERE code = ?", [&lang.code]).unwrap();
|
||||
|
||||
transaction.execute(&format!("DROP TABLE IF EXISTS {0}_words", &lang.code), []).unwrap();
|
||||
transaction.execute(&format!("DROP TABLE IF EXISTS {0}_types", &lang.code), []).unwrap();
|
||||
|
||||
transaction.execute(&format!("
|
||||
CREATE TABLE {0}_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name TINYTEXT UNIQUE NOT NULL
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name TINYTEXT UNIQUE NOT NULL
|
||||
)", &lang.code), []).unwrap();
|
||||
|
||||
for type_ in &lang.types {
|
||||
|
@ -50,12 +82,12 @@ impl WordDb {
|
|||
|
||||
transaction.execute(&format!("
|
||||
CREATE TABLE {0}_words (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
word TINYTEXT NOT NULL,
|
||||
type_id INTEGER NOT NULL,
|
||||
content MEDIUMTEXT NOT NULL,
|
||||
FOREIGN KEY (type_id)
|
||||
REFERENCES {0}_types (id)
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
word TINYTEXT NOT NULL,
|
||||
type_id INTEGER NOT NULL,
|
||||
content MEDIUMTEXT NOT NULL,
|
||||
FOREIGN KEY (type_id)
|
||||
REFERENCES {0}_types (id)
|
||||
)", &lang.code), []).unwrap();
|
||||
|
||||
transaction.execute(&format!("
|
||||
|
@ -63,6 +95,11 @@ impl WordDb {
|
|||
ON {0}_words (word)
|
||||
", &lang.code), []).unwrap();
|
||||
|
||||
transaction.execute("
|
||||
INSERT INTO langs (code, name, major, minor, patch)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
", params![&lang.code, &lang.name, MAJOR, MINOR, PATCH]).unwrap();
|
||||
|
||||
transaction.commit().unwrap();
|
||||
}
|
||||
|
||||
|
@ -169,9 +206,24 @@ impl WordDb {
|
|||
transaction.commit().unwrap();
|
||||
}
|
||||
|
||||
fn try_create_dir(&self, dir: &str) {
|
||||
match fs::create_dir(dir) {
|
||||
Err(e) => match e.kind() {
|
||||
ErrorKind::AlreadyExists => {},
|
||||
_ => panic!("{}", e)
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn upgrade_lang(&mut self, lang: &Language) {
|
||||
self.try_create_dir(DB_DIR);
|
||||
|
||||
println!("Trying to read cached data...");
|
||||
let cached_data = fs::read_to_string("Polish.json");
|
||||
let mut cache_file = String::from(CACHE_DIR);
|
||||
cache_file.push_str("Polish.json");
|
||||
|
||||
let cached_data = fs::read_to_string(&cache_file);
|
||||
let mut request = None;
|
||||
|
||||
if let Err(_) = cached_data {
|
||||
|
@ -186,8 +238,11 @@ impl WordDb {
|
|||
// Actually, the request was sent before
|
||||
println!("Requesting data...");
|
||||
data = request.await.unwrap().text().await.unwrap();
|
||||
println!("Caching data...");
|
||||
fs::write("Polish.json", &data).unwrap();
|
||||
if cfg!(unix) {
|
||||
println!("Caching data...");
|
||||
self.try_create_dir(CACHE_DIR);
|
||||
fs::write(&cache_file, &data).unwrap();
|
||||
}
|
||||
}
|
||||
else {
|
||||
data = cached_data.unwrap();
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
#[derive(Debug)]
|
||||
pub struct Language {
|
||||
pub code: String,
|
||||
pub name: String,
|
||||
pub types: Vec<String>
|
||||
}
|
||||
|
||||
impl Language {
|
||||
pub fn new(code: &str, types: Vec<String>) -> Self {
|
||||
pub fn new(code: &str, name: &str, types: Vec<String>) -> Self {
|
||||
Self {
|
||||
code: String::from(code),
|
||||
name: String::from(name),
|
||||
types
|
||||
}
|
||||
}
|
||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -8,11 +8,16 @@ use clap::{App, AppSettings, Arg, SubCommand};
|
|||
mod database;
|
||||
mod language;
|
||||
mod entry;
|
||||
mod routes;
|
||||
mod views;
|
||||
|
||||
use database::WordDb;
|
||||
use language::Language;
|
||||
|
||||
|
||||
const MAJOR: i32 = 0;
|
||||
const MINOR: i32 = 1;
|
||||
const PATCH: i32 = 0;
|
||||
|
||||
#[rocket::main]
|
||||
async fn main() {
|
||||
let matches = App::new("inflectived")
|
||||
|
@ -49,9 +54,10 @@ async fn main() {
|
|||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.get_matches();
|
||||
|
||||
let mut db = WordDb::new("test.db");
|
||||
let mut db = WordDb::new("inflectived.db");
|
||||
|
||||
let lang = Language::new("polish",
|
||||
let lang = Language::new("pl",
|
||||
"Polish",
|
||||
vec![String::from("adj"),
|
||||
String::from("noun"),
|
||||
String::from("verb"),
|
||||
|
@ -84,9 +90,10 @@ async fn main() {
|
|||
rocket::custom(figment)
|
||||
.manage(db)
|
||||
.mount("/static", FileServer::from("static/"))
|
||||
.mount("/", routes![routes::get_entries,
|
||||
routes::get_entries_like,
|
||||
routes::frontend])
|
||||
.mount("/", routes![views::get_entries,
|
||||
views::get_entries_like,
|
||||
views::get_langs,
|
||||
views::frontend])
|
||||
.launch()
|
||||
.await.unwrap();
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@ use rusqlite::params;
|
|||
|
||||
use crate::database::WordDb;
|
||||
|
||||
#[get("/frontend")]
|
||||
#[get("/")]
|
||||
pub fn frontend() -> Option<content::Html<String>> {
|
||||
match fs::read_to_string("static/index.html") {
|
||||
Ok(file) => Some(content::Html(file)),
|
||||
|
@ -70,3 +70,22 @@ pub fn get_entries_like(db: &State<WordDb>, lang: &str, like: &str, limit: usize
|
|||
|
||||
Json(words)
|
||||
}
|
||||
|
||||
#[get("/langs?<installed>")]
|
||||
pub fn get_langs(db: &State<WordDb>, installed: bool) -> Json<Vec<String>> {
|
||||
let conn = db.connect();
|
||||
|
||||
let mut langs: Vec<String> = Vec::new();
|
||||
|
||||
if installed {
|
||||
let mut statement = conn.prepare("SELECT name FROM langs").unwrap();
|
||||
|
||||
let mut rows = statement.query([]).unwrap();
|
||||
|
||||
while let Some(row) = rows.next().unwrap() {
|
||||
langs.push(row.get(0).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
Json(langs)
|
||||
}
|
|
@ -21,7 +21,7 @@ $(document).ready(() => {
|
|||
appendTo: '#search-form',
|
||||
source: (request, response) => {
|
||||
$.ajax({
|
||||
url: '/langs/polish/words?like=' + request.term + '&limit=20&offset=0',
|
||||
url: '/langs/pl/words?like=' + request.term + '&limit=20&offset=0',
|
||||
success: data => response(data)
|
||||
})
|
||||
},
|
||||
|
@ -44,7 +44,7 @@ $(document).ready(() => {
|
|||
let word = window.location.hash.replace('#', '');
|
||||
|
||||
$.ajax({
|
||||
url: '/langs/polish/words/' + word,
|
||||
url: '/langs/pl/words/' + word,
|
||||
|
||||
success: (data) => {
|
||||
$('#ajax-content').html(generateHtml(word, data))
|
||||
|
@ -163,7 +163,7 @@ $(document).ready(() => {
|
|||
|
||||
if('form_of' in sense) {
|
||||
let word = sense.form_of[0].word;
|
||||
html += sense.glosses[0].replace(new RegExp(`of ${word}$`), '');
|
||||
html += sense.glosses[0].replace(new RegExp(`of ${word}.?$`), '');
|
||||
html += ` of <a href="#${word}" class="link-primary">${word}</a>`;
|
||||
} else {
|
||||
let link = ' of <a href="#$1" class="link-primary">$1</a>';
|
||||
|
|
Loading…
Reference in New Issue