/reg/
@ -33,6 +33,7 @@ reply_limit = 1000
|
|||||||
locked = false
|
locked = false
|
||||||
user_ids = false
|
user_ids = false
|
||||||
flags = false
|
flags = false
|
||||||
|
flags_reg = false
|
||||||
thread_captcha = "off"
|
thread_captcha = "off"
|
||||||
reply_captcha = "off"
|
reply_captcha = "off"
|
||||||
board_theme = "yotsuba.css"
|
board_theme = "yotsuba.css"
|
||||||
|
@ -64,6 +64,7 @@ pub struct BoardCfg {
|
|||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
pub user_ids: bool,
|
pub user_ids: bool,
|
||||||
pub flags: bool,
|
pub flags: bool,
|
||||||
|
pub flags_reg: bool,
|
||||||
pub thread_captcha: String,
|
pub thread_captcha: String,
|
||||||
pub reply_captcha: String,
|
pub reply_captcha: String,
|
||||||
pub board_theme: String,
|
pub board_theme: String,
|
||||||
|
@ -20,7 +20,7 @@ impl Banner {
|
|||||||
|
|
||||||
pub async fn read(ctx: &Ctx, id: i32) -> Result<Option<Self>, NekrochanError> {
|
pub async fn read(ctx: &Ctx, id: i32) -> Result<Option<Self>, NekrochanError> {
|
||||||
let banners: Vec<String> = ctx.cache().zrangebyscore("banners", id, id).await?;
|
let banners: Vec<String> = ctx.cache().zrangebyscore("banners", id, id).await?;
|
||||||
let json = banners.get(0);
|
let json = banners.first();
|
||||||
|
|
||||||
let banner = match json {
|
let banner = match json {
|
||||||
Some(json) => Some(serde_json::from_str(json)?),
|
Some(json) => Some(serde_json::from_str(json)?),
|
||||||
|
@ -37,6 +37,7 @@ impl Board {
|
|||||||
files JSONB NOT NULL,
|
files JSONB NOT NULL,
|
||||||
password VARCHAR(64) DEFAULT NULL,
|
password VARCHAR(64) DEFAULT NULL,
|
||||||
country VARCHAR(2) NOT NULL,
|
country VARCHAR(2) NOT NULL,
|
||||||
|
region VARCHAR(64) NOT NULL,
|
||||||
ip INET NOT NULL,
|
ip INET NOT NULL,
|
||||||
bumps INT NOT NULL DEFAULT 0,
|
bumps INT NOT NULL DEFAULT 0,
|
||||||
replies INT NOT NULL DEFAULT 0,
|
replies INT NOT NULL DEFAULT 0,
|
||||||
|
@ -60,6 +60,7 @@ pub struct Post {
|
|||||||
pub files: Json<Vec<File>>,
|
pub files: Json<Vec<File>>,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub country: String,
|
pub country: String,
|
||||||
|
pub region: Option<String>,
|
||||||
pub ip: IpAddr,
|
pub ip: IpAddr,
|
||||||
pub bumps: i32,
|
pub bumps: i32,
|
||||||
pub replies: i32,
|
pub replies: i32,
|
||||||
|
@ -27,13 +27,14 @@ impl Post {
|
|||||||
files: Vec<File>,
|
files: Vec<File>,
|
||||||
password: String,
|
password: String,
|
||||||
country: String,
|
country: String,
|
||||||
|
region: Option<String>,
|
||||||
ip: IpAddr,
|
ip: IpAddr,
|
||||||
bump: bool,
|
bump: bool,
|
||||||
) -> Result<Self, NekrochanError> {
|
) -> Result<Self, NekrochanError> {
|
||||||
let post: Post = query_as(&format!(
|
let post: Post = query_as(&format!(
|
||||||
r#"INSERT INTO posts_{}
|
r#"INSERT INTO posts_{}
|
||||||
(thread, name, tripcode, capcode, email, content, content_nomarkup, files, password, country, ip)
|
(thread, name, tripcode, capcode, email, content, content_nomarkup, files, password, country, region, ip)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||||
RETURNING *"#, board.id)
|
RETURNING *"#, board.id)
|
||||||
)
|
)
|
||||||
.bind(thread)
|
.bind(thread)
|
||||||
@ -46,6 +47,7 @@ impl Post {
|
|||||||
.bind(Json(files))
|
.bind(Json(files))
|
||||||
.bind(password)
|
.bind(password)
|
||||||
.bind(country)
|
.bind(country)
|
||||||
|
.bind(region)
|
||||||
.bind(ip)
|
.bind(ip)
|
||||||
.fetch_one(ctx.db())
|
.fetch_one(ctx.db())
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -26,7 +26,7 @@ pub async fn appeal_ban(
|
|||||||
QsForm(form): QsForm<AppealBanForm>,
|
QsForm(form): QsForm<AppealBanForm>,
|
||||||
) -> Result<HttpResponse, NekrochanError> {
|
) -> Result<HttpResponse, NekrochanError> {
|
||||||
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
||||||
let (ip, _) = ip_from_req(&req)?;
|
let (ip, _, _) = ip_from_req(&req)?;
|
||||||
|
|
||||||
let ban = Ban::read_by_id(&ctx, form.id)
|
let ban = Ban::read_by_id(&ctx, form.id)
|
||||||
.await?
|
.await?
|
||||||
|
@ -49,7 +49,7 @@ pub async fn create_post(
|
|||||||
None => PermissionWrapper::new(0, false),
|
None => PermissionWrapper::new(0, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (ip, country) = ip_from_req(&req)?;
|
let (ip, country, region) = ip_from_req(&req)?;
|
||||||
|
|
||||||
let board = form.board.0;
|
let board = form.board.0;
|
||||||
let board = Board::read(&ctx, board.clone())
|
let board = Board::read(&ctx, board.clone())
|
||||||
@ -238,6 +238,7 @@ pub async fn create_post(
|
|||||||
files,
|
files,
|
||||||
password,
|
password,
|
||||||
country,
|
country,
|
||||||
|
region,
|
||||||
ip,
|
ip,
|
||||||
bump,
|
bump,
|
||||||
)
|
)
|
||||||
|
@ -29,7 +29,7 @@ pub async fn report_posts(
|
|||||||
QsForm(form): QsForm<ReportPostsForm>,
|
QsForm(form): QsForm<ReportPostsForm>,
|
||||||
) -> Result<HttpResponse, NekrochanError> {
|
) -> Result<HttpResponse, NekrochanError> {
|
||||||
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
||||||
let (reporter_ip, reporter_country) = ip_from_req(&req)?;
|
let (reporter_ip, reporter_country, _) = ip_from_req(&req)?;
|
||||||
let bans = Ban::read_by_ip(&ctx, reporter_ip).await?;
|
let bans = Ban::read_by_ip(&ctx, reporter_ip).await?;
|
||||||
|
|
||||||
if let Some(ban) = bans.get(&None) {
|
if let Some(ban) = bans.get(&None) {
|
||||||
|
@ -34,7 +34,7 @@ pub async fn user_post_actions(
|
|||||||
QsForm(form): QsForm<UserPostActionsForm>,
|
QsForm(form): QsForm<UserPostActionsForm>,
|
||||||
) -> Result<HttpResponse, NekrochanError> {
|
) -> Result<HttpResponse, NekrochanError> {
|
||||||
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
||||||
let (ip, _) = ip_from_req(&req)?;
|
let (ip, _, _) = ip_from_req(&req)?;
|
||||||
let bans = Ban::read_by_ip(&ctx, ip).await?;
|
let bans = Ban::read_by_ip(&ctx, ip).await?;
|
||||||
|
|
||||||
if let Some(ban) = bans.get(&None) {
|
if let Some(ban) = bans.get(&None) {
|
||||||
|
@ -18,6 +18,7 @@ pub struct UpdateBoardConfigForm {
|
|||||||
locked: Option<String>,
|
locked: Option<String>,
|
||||||
user_ids: Option<String>,
|
user_ids: Option<String>,
|
||||||
flags: Option<String>,
|
flags: Option<String>,
|
||||||
|
flags_reg: Option<String>,
|
||||||
thread_captcha: String,
|
thread_captcha: String,
|
||||||
reply_captcha: String,
|
reply_captcha: String,
|
||||||
board_theme: String,
|
board_theme: String,
|
||||||
@ -58,6 +59,7 @@ pub async fn update_board_config(
|
|||||||
let locked = form.locked.is_some();
|
let locked = form.locked.is_some();
|
||||||
let user_ids = form.user_ids.is_some();
|
let user_ids = form.user_ids.is_some();
|
||||||
let flags = form.flags.is_some();
|
let flags = form.flags.is_some();
|
||||||
|
let flags_reg = form.flags_reg.is_some();
|
||||||
let thread_captcha = form.thread_captcha;
|
let thread_captcha = form.thread_captcha;
|
||||||
let reply_captcha = form.reply_captcha;
|
let reply_captcha = form.reply_captcha;
|
||||||
let board_theme = form.board_theme;
|
let board_theme = form.board_theme;
|
||||||
@ -81,6 +83,7 @@ pub async fn update_board_config(
|
|||||||
locked,
|
locked,
|
||||||
user_ids,
|
user_ids,
|
||||||
flags,
|
flags,
|
||||||
|
flags_reg,
|
||||||
thread_captcha,
|
thread_captcha,
|
||||||
reply_captcha,
|
reply_captcha,
|
||||||
board_theme,
|
board_theme,
|
||||||
|
@ -34,7 +34,7 @@ impl TemplateCtx {
|
|||||||
None => PermissionWrapper::new(0, false),
|
None => PermissionWrapper::new(0, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (ip, _) = ip_from_req(req)?;
|
let (ip, _, _) = ip_from_req(req)?;
|
||||||
let yous = ctx.cache().zrange(format!("by_ip:{ip}"), 0, -1).await?;
|
let yous = ctx.cache().zrange(format!("by_ip:{ip}"), 0, -1).await?;
|
||||||
|
|
||||||
let account = account.map(|account| account.username);
|
let account = account.map(|account| account.username);
|
||||||
@ -99,7 +99,7 @@ pub async fn account_from_auth_opt(
|
|||||||
Ok(account)
|
Ok(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ip_from_req(req: &HttpRequest) -> Result<(IpAddr, String), NekrochanError> {
|
pub fn ip_from_req(req: &HttpRequest) -> Result<(IpAddr, String, Option<String>), NekrochanError> {
|
||||||
let ip = req
|
let ip = req
|
||||||
.connection_info()
|
.connection_info()
|
||||||
.realip_remote_addr()
|
.realip_remote_addr()
|
||||||
@ -107,10 +107,27 @@ pub fn ip_from_req(req: &HttpRequest) -> Result<(IpAddr, String), NekrochanError
|
|||||||
ip.parse().unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED))
|
ip.parse().unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED))
|
||||||
});
|
});
|
||||||
|
|
||||||
let country = req.headers().get("X-Country-Code").map_or_else(
|
let country = req
|
||||||
|| "xx".into(),
|
.headers()
|
||||||
|hdr| hdr.to_str().unwrap_or("xx").to_ascii_lowercase(),
|
.get("X-Country-Code")
|
||||||
);
|
.and_then(|hdr| hdr.to_str().ok())
|
||||||
|
.unwrap_or("xx")
|
||||||
|
.to_ascii_lowercase();
|
||||||
|
|
||||||
Ok((ip, country))
|
let region = req
|
||||||
|
.headers()
|
||||||
|
.get("X-Region-Code")
|
||||||
|
.and_then(|hdr| hdr.to_str().ok())
|
||||||
|
.unwrap_or("xx")
|
||||||
|
.to_ascii_lowercase();
|
||||||
|
|
||||||
|
let region = if country == "cz" {
|
||||||
|
Some(region)
|
||||||
|
} else if country == "ru" && region == "kgd" {
|
||||||
|
Some("kralovec".into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((ip, country, region))
|
||||||
}
|
}
|
||||||
|
binární
static/flags/reg/10.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/20.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/31.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/32.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/41.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/42.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/51.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/52.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/53.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/63.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/64.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/71.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/72.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/80.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/kralovec.png
Normální soubor
Za Šířka: | Výška: | Velikost: 1.0 KiB |
binární
static/flags/reg/xx.png
Spustitelný soubor
Za Šířka: | Výška: | Velikost: 447 B |
@ -23,6 +23,11 @@
|
|||||||
{% if board.config.0.flags %}
|
{% if board.config.0.flags %}
|
||||||
<img title="Země: {{ post.country }}" class="icon" src="/static/flags/{{ post.country }}.png"> 
|
<img title="Země: {{ post.country }}" class="icon" src="/static/flags/{{ post.country }}.png"> 
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if board.config.0.flags_reg %}
|
||||||
|
{% if let Some(region) = post.region %}
|
||||||
|
<img title="Region: {{ region }}" class="icon" src="/static/flags/reg/{{ region }}.png"> 
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
<time datetime="{{ post.created }}">{{ post.created|czech_datetime }}</time> 
|
<time datetime="{{ post.created }}">{{ post.created|czech_datetime }}</time> 
|
||||||
{% if board.config.0.user_ids %}
|
{% if board.config.0.user_ids %}
|
||||||
<span class="user-id" style="background-color: #{{ post.user_id }};">{{ post.user_id }}</span> 
|
<span class="user-id" style="background-color: #{{ post.user_id }};">{{ post.user_id }}</span> 
|
||||||
|
@ -69,6 +69,15 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="label">Vlajky Regionů</td>
|
||||||
|
<td>
|
||||||
|
<div class="input-wrapper">
|
||||||
|
<input name="flags_reg" type="checkbox" {% if board.config.0.flags_reg %}checked=""{% endif %}>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="label">CAPTCHA (vlákno)</td>
|
<td class="label">CAPTCHA (vlákno)</td>
|
||||||
<td>
|
<td>
|
||||||
|