use std::collections::HashMap;
use std::sync::RwLock;
use lazy_static::*;
use config::{Config, File, FileFormat};
use handlebars::Handlebars;
use serde_json::value::{Map, Value as Json};
use reqwest::Url;
use authorization::Authorization;
use ::log::*;
use chrono::{DateTime, Local};
pub mod comment_server;
pub mod log;
pub mod filters;
pub mod handlers;
pub mod models;
lazy_static!{
static ref SETTINGS: HashMap<String, String> = get_settings();
static ref TEMPLATES: Handlebars<'static> = get_templates();
static ref AUTHZN: RwLock<Authorization> = get_authorization();
static ref SESSION_ID: RwLock<String> = RwLock::new( String::new() );
}
fn get_settings() -> HashMap<String, String> {
let mut config = Config::default();
config.merge(File::new("Settings", FileFormat::Toml)).unwrap();
let settings = config.try_into::<HashMap<String, String>>().unwrap();
settings
}
pub fn config(key: &str) -> String {
SETTINGS.get(key).unwrap().to_string()
}
fn get_templates() -> Handlebars<'static> {
let mut hb = Handlebars::new();
hb.register_template_file("index_page", "./templates/index_page.hbs").unwrap();
hb.register_template_file("comments_page", "./templates/comments_page.hbs").unwrap();
hb.register_template_file("reply_page_partial", "./templates/reply_page_partial.hbs").unwrap();
hb
}
fn get_authorization() -> RwLock<Authorization> {
let authzn = Authorization::load( &config("resource_permissions"), &config("user_roles") );
RwLock::new(authzn)
}
fn set_session_id(sid: String) {
info!("setting session id into lazy static.........{:?}", &sid);
let mut session_id = SESSION_ID.write().unwrap();
*session_id = sid;
}
fn get_session_id() -> String {
let sid = SESSION_ID.read().unwrap();
sid.to_string()
}
pub fn allows_add(cid: &str, res: &str, data: &Map<String, Json>) -> bool {
allows("add", cid, res, data)
}
pub fn allows_view(cid: &str, res: &str, data: &Map<String, Json>) -> bool {
allows("view", cid, res, data)
}
pub fn allows_edit(cid: &str, res: &str, data: &Map<String, Json>) -> bool {
allows("edit", cid, res, data)
}
pub fn allows_delete(cid: &str, res: &str, data: &Map<String, Json>) -> bool {
allows("delete", cid, res, data)
}
fn allows(op: &str, cid: &str, res: &str, data: &Map<String, Json>) -> bool {
debug!("Authzn: op: {:?}, cid: {:?}, resource: {:?}.............", op, cid, res);
{
let authzn_r = AUTHZN.read().unwrap();
if authzn_r.has_permissions_for(cid) {
return match op {
"add" => authzn_r.allows_add(cid, res, data),
"view" => authzn_r.allows_view(cid, res, data),
"edit" => authzn_r.allows_edit(cid, res, data),
"delete" => authzn_r.allows_delete(cid, res, data),
_ => false
}
}
}
let mut authzn_w = AUTHZN.write().unwrap();
authzn_w.set_permissions_for(cid);
match op {
"add" => authzn_w.allows_add(cid, res, data),
"view" => authzn_w.allows_view(cid, res, data),
"edit" => authzn_w.allows_edit(cid, res, data),
"delete" => authzn_w.allows_delete(cid, res, data),
_ => false
}
}
pub fn render(template_name: &str, data: &Map<String, Json>) -> String {
TEMPLATES.render(template_name, data)
.unwrap_or_else(|err| err.to_string())
}
pub fn comments_url() -> Url {
let ip = config("backend_server_ip_address");
let path = config("backend_server_comments_path");
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("comments_url: {}", url);
url
}
pub fn comments_total_url() -> Url {
let ip = config("backend_server_ip_address");
let path = config("backend_server_comments_total_path");
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("comments_total_url: {}", url);
url
}
pub fn replies_url() -> Url {
let ip = config("backend_server_ip_address");
let path = config("backend_server_replies_path");
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("replies_url: {}", url);
url
}
pub fn replies_url_with(addl_path: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_replies_path");
if addl_path.len() > 0 {
path = path.to_owned() + "/" + addl_path;
}
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("replies_url_with: {}", url);
url
}
pub fn session_url() -> Url {
let ip = config("app_server_local_ip_address");
let path = config("app_server_session_path");
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
info!("session_url: {}.................................................................", url);
url
}
pub fn session_url_with(sid: &str) -> Url {
let ip = config("app_server_local_ip_address");
let mut path = config("app_server_session_path");
if sid.len() > 0 {
path = path.to_owned() + "/" + sid;
}
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
info!("session_url: {}.................................................................", url);
url
}
pub fn commenter_url_with(addl_path: &str) -> Url {
let ip = config("app_server_local_ip_address");
let mut path = config("app_server_commenter_path");
if addl_path.len() > 0 {
path = path.to_owned() + "/" + addl_path;
}
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("commenter_url_with: {}", url);
url
}
pub fn avatar_url_path() -> String {
let ip = config("app_server_named_ip_address");
let path = config("app_server_avatar_path");
ip + &path
}
pub fn status_update_url(status: &str, cid: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_comment_path");
path = path.to_owned() + "/" + status + "/" + cid;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("status_update_url: {}", url);
url
}
pub fn comment_msg_update_url(cid: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_comment_message_path");
path = path.to_owned() + "/" + cid;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("comment_msg_update_url: {}", url);
url
}
pub fn comments_trash_url(uid: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_comments_path");
path = path.to_owned() + "/" + uid;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("comments_trash_url: {}", url);
url
}
pub fn reply_msg_update_url(cid: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_reply_message_path");
path = path.to_owned() + "/" + cid;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("reply_msg_update_url: {}", url);
url
}
pub fn replies_trash_url(uid: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_replies_path");
path = path.to_owned() + "/" + uid;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("replies_trash_url: {}", url);
url
}
pub fn more_comments_url(count: usize) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_more_comments_path");
path = path.to_owned() + "/" + &count.to_string();
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("more_comments_url: {}", url);
url
}
pub fn upvote_url() -> Url {
let ip = config("backend_server_ip_address");
let path = config("backend_server_upvote_path");
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("upvote_url: {}", url);
url
}
pub fn upvotes_count_url(comment_id: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_upvotes_count_path");
path = path.to_owned() + "/" + &comment_id;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("upvotes_count_url: {}", url);
url
}
pub fn downvote_url() -> Url {
let ip = config("backend_server_ip_address");
let path = config("backend_server_downvote_path");
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("downvote_url: {}", url);
url
}
pub fn downvotes_count_url(comment_id: &str) -> Url {
let ip = config("backend_server_ip_address");
let mut path = config("backend_server_downvotes_count_path");
path = path.to_owned() + "/" + &comment_id;
let mut url = Url::parse(&ip).unwrap();
url.set_path(&path);
debug!("downvotes_count_url: {}", url);
url
}
pub fn time_ago(dt_str: &str) -> String {
let dt = DateTime::parse_from_str(dt_str, "%Y-%m-%d %H:%M:%S%.9f %z").unwrap();
let now = Local::now();
let mut elapsed = now.timestamp_millis() - dt.timestamp_millis();
elapsed = elapsed / 1000;
let mut plural = "";
if elapsed > 1 { plural = "s" };
if elapsed < 60 { return format!("{} second{} ago", &elapsed, plural); }
elapsed = elapsed / 60;
plural = if elapsed == 1 { "" } else { "s" };
if elapsed < 60 { return format!("{} minute{} ago", &elapsed, plural); }
elapsed = elapsed / 60;
plural = if elapsed == 1 { "" } else { "s" };
if elapsed < 24 { return format!("{} hour{} ago", &elapsed, plural); }
elapsed = elapsed / 24;
plural = if elapsed == 1 { "" } else { "s" };
if elapsed < 7 { return format!("{} day{} ago", &elapsed, plural); }
elapsed = elapsed / 7;
plural = if elapsed == 1 { "" } else { "s" };
if elapsed <= 4 { return format!("{} week{} ago", &elapsed, plural); }
let now_year = now.format("%Y").to_string();
if dt_str.contains( &now_year ) {
dt.format("%d %B").to_string()
} else {
dt.format("%d %B %Y").to_string()
}
}