mod json_ld;
use json_ld::*;
use std::sync::Arc;
use parking_lot::RwLock;
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct BaseEntity {
title: Option<String>,
description: Option<String>,
author: Option<String>,
robots: Option<String>,
googlebot: Option<String>,
application_name: Option<String>,
theme_color: Option<String>,
canonical: Option<String>,
icon: Option<(String, String)>,
apple_touch_icon: Option<String>,
manifest: Option<String>,
}
impl BaseEntity {
pub fn to_html(&self) -> String {
let mut html = String::new();
if let Some(ref value) = self.title {
html.push_str(format!(r#"<title>{}</title>"#, value).as_str());
}
if let Some(ref value) = self.description {
html.push_str(format!(r#"<meta name="description" content="{}">"#, value).as_str());
}
if let Some(ref value) = self.author {
html.push_str(format!(r#"<meta name="author" content="{}">"#, value).as_str());
}
if let Some(ref value) = self.robots {
html.push_str(format!(r#"<meta name="robots" content="{}">"#, value).as_str());
}
if let Some(ref value) = self.googlebot {
html.push_str(format!(r#"<meta name="googlebot" content="{}">"#, value).as_str());
}
if let Some(ref value) = self.application_name {
html.push_str(format!(r#"<meta name="application-name" content="{}">"#, value).as_str());
}
if let Some(ref value) = self.theme_color {
html.push_str(format!(r#"<meta name="theme-color" content="{}">"#, value).as_str());
}
if let Some(ref value) = self.canonical {
html.push_str(format!(r#"<link rel="canonical" href="{}">"#, value).as_str());
}
if let Some((ref mime, ref value)) = self.icon {
html.push_str(format!(r#"<link rel="icon" type="{}" href="{}">"#, mime, value).as_str());
}
if let Some(ref value) = self.apple_touch_icon {
html.push_str(format!(r#"<link rel="apple-touch-icon" href="{}">"#, value).as_str());
}
if let Some(ref value) = self.manifest {
html.push_str(format!(r#"<link rel="manifest" href="{}">"#, value).as_str());
}
html
}
}
#[derive(Default)]
struct BaseMeta {
base: Option<BaseEntity>,
open_graph: Option<OpenGraphEntity>,
twitter: Option<TwitterEntity>
}
impl BaseMeta {
pub fn to_html(&self) -> String {
let mut html = String::new();
if let Some(ref entity) = self.base {
html.push_str(&entity.to_html());
}
if let Some(ref entity) = self.open_graph {
html.push_str(&entity.to_html());
}
if let Some(ref entity) = self.twitter {
html.push_str(&entity.to_html());
}
html
}
}
pub struct Seo {
bing_token: Option<String>,
google_token: Option<String>,
json: Arc<RwLock<JsonLD>>,
meta: Arc<RwLock<BaseMeta>>,
}
impl Seo {
pub fn new(bing_token: Option<String>, google_token: Option<String>) -> Self {
Self {
bing_token,
google_token,
json: Arc::new(RwLock::new(JsonLD::default())),
meta: Arc::new(RwLock::new(BaseMeta::default())),
}
}
pub fn bing_verification(&self) -> Option<String> {
if let Some(ref token) = self.bing_token {
return Some(format!(r#"<meta name="msvalidate.01" content="{}">\n"#, token));
}
None
}
pub fn google_verification(&self) -> Option<String> {
if let Some(ref token) = self.google_token {
return Some(format!(r#"<meta name="google-site-verification" content="{}">\n"#, token));
}
None
}
pub fn set_base_entity(&self, base: BaseEntity) {
let mut meta = self.meta.write();
meta.base = Some(base);
drop(meta);
}
pub fn set_og_entity(&self, base: OpenGraphEntity) {
let mut meta = self.meta.write();
meta.open_graph = Some(base);
drop(meta);
}
pub fn set_twitter_entity(&self, base: TwitterEntity) {
let mut meta = self.meta.write();
meta.twitter = Some(base);
drop(meta);
}
pub fn set_json_grapth(&self, base: Vec<GraphEntity>) {
let mut meta = self.json.write();
meta.set_grapth(base);
drop(meta);
}
pub fn push_json_grapth(&self, base: GraphEntity) {
let mut meta = self.json.write();
meta.push_grapth(base);
drop(meta);
}
pub fn meta_to_html(&self) -> String {
let mut html = String::new();
let meta = self.meta.write();
html.push_str(&meta.to_html());
drop(meta);
if let Some(ref value) = self.bing_verification() {
html.push_str(&value);
}
if let Some(ref value) = self.google_verification() {
html.push_str(&value);
}
html
}
pub fn meta_to_html_with_jsonld(&self) -> String {
let mut html = String::new();
let meta = self.meta.write();
html.push_str(&meta.to_html());
drop(meta);
if let Some(ref value) = self.bing_verification() {
html.push_str(&value);
}
if let Some(ref value) = self.google_verification() {
html.push_str(&value);
}
html
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct OpenGraphEntity {
#[serde(rename = "og:type")]
kind : String,
#[serde(rename = "og:site_name")]
site_name : String,
#[serde(rename = "og:title")]
title : String,
#[serde(rename = "og:description")]
description : String,
#[serde(rename = "og:url")]
url : String,
#[serde(rename = "og:locale")]
locale : String,
#[serde(rename = "og:image")]
image : Option<String>,
#[serde(rename = "og:image:alt")]
image_alt : Option<String>,
}
impl Default for OpenGraphEntity {
fn default() -> Self {
Self {
kind: "website".to_string(),
site_name: "example".to_string(),
title: "example | Website".to_string(),
description: "The Website of example com.".to_string(),
url: "https://example.com/".to_string(),
locale: "en_US".to_string(),
image: None,
image_alt: None,
}
}
}
impl OpenGraphEntity {
pub fn to_html(&self) -> String {
let mut html = String::new();
html.push_str(format!(r#"<meta property="og:type" content="{}">\n"#, self.kind).as_str());
html.push_str(format!(r#"<meta property="og:site_name" content="{}">\n"#, self.site_name).as_str());
html.push_str(format!(r#"<meta property="og:title" content="{}">\n"#, self.title).as_str());
html.push_str(format!(r#"<meta property="og:description" content="{}">\n"#, self.description).as_str());
html.push_str(format!(r#"<meta property="og:url" content="{}">\n"#, self.url).as_str());
html.push_str(format!(r#"<meta property="og:locale" content="{}">\n"#, self.locale).as_str());
if let Some(ref value) = self.image {
html.push_str(format!(r#"<meta property="og:image" content="{}">\n"#, value).as_str());
}
if let Some(ref value) = self.image_alt {
html.push_str(format!(r#"<meta property="og:image:alt" content="{}">\n"#, value).as_str());
}
html
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TwitterEntity {
#[serde(rename = "twitter:card")]
card : String,
#[serde(rename = "twitter:title")]
title : String,
#[serde(rename = "twitter:description")]
description : String,
#[serde(rename = "twitter:image")]
image : Option<String>,
}
impl Default for TwitterEntity {
fn default() -> Self {
Self {
card: "website".to_string(),
title: "example | Website".to_string(),
description: "The Website of example com.".to_string(),
image: None
}
}
}
impl TwitterEntity {
pub fn to_html(&self) -> String {
let mut html = String::new();
html.push_str(format!(r#"<meta property="twitter:card" content="{}">\n"#, self.card).as_str());
html.push_str(format!(r#"<meta property="twitter:title" content="{}">\n"#, self.title).as_str());
html.push_str(format!(r#"<meta property="twitter:description" content="{}">\n"#, self.description).as_str());
if let Some(ref value) = self.image {
html.push_str(format!(r#"<meta property="twitter:image" content="{}">\n"#, value).as_str());
}
html
}
}