Sérč bar a aktuální počet hlášení
Tento commit je obsažen v:
rodič
59c1052125
revize
e46d858545
2
build.rs
2
build.rs
@ -30,7 +30,7 @@ fn main() -> Result<(), Error> {
|
||||
}
|
||||
|
||||
let html = read_to_string(&path)?;
|
||||
let minified = minify(html)?.replace('\n', "");
|
||||
let minified = minify(html)?.replace('\n', "").replace(" ", " ");
|
||||
|
||||
File::create(path)?.write_all(minified.as_bytes())?;
|
||||
}
|
||||
|
@ -6,13 +6,13 @@ use crate::{ctx::Ctx, error::NekrochanError};
|
||||
impl LocalStats {
|
||||
pub async fn read(ctx: &Ctx) -> Result<Self, NekrochanError> {
|
||||
let (post_count,) = query_as(
|
||||
"SELECT coalesce(sum(last_value)::bigint, 0) FROM pg_sequences WHERE sequencename LIKE 'posts_%_id_seq'",
|
||||
"SELECT COALESCE(SUM(last_value)::bigint, 0) FROM pg_sequences WHERE sequencename LIKE 'posts_%_id_seq'",
|
||||
)
|
||||
.fetch_one(ctx.db())
|
||||
.await?;
|
||||
|
||||
let (file_count, file_size) = query_as(
|
||||
r#"SELECT count(files), coalesce(sum((files->>'size')::bigint)::bigint, 0) FROM (
|
||||
r#"SELECT COUNT(files), COALESCE(SUM((files->>'size')::bigint)::bigint, 0) FROM (
|
||||
SELECT jsonb_array_elements(files) AS files FROM overboard
|
||||
) flatten"#,
|
||||
)
|
||||
|
@ -277,6 +277,41 @@ impl Post {
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub async fn read_by_query(
|
||||
ctx: &Ctx,
|
||||
board: &Board,
|
||||
query: String,
|
||||
page: i64,
|
||||
) -> Result<Vec<Self>, NekrochanError> {
|
||||
let posts = query_as(&format!(
|
||||
"SELECT * FROM posts_{} WHERE LOWER(content_nomarkup) LIKE LOWER($1) LIMIT $2 OFFSET $3",
|
||||
board.id
|
||||
))
|
||||
.bind(format!("%{query}%"))
|
||||
.bind(board.config.0.page_size)
|
||||
.bind((page - 1) * board.config.0.page_size)
|
||||
.fetch_all(ctx.db())
|
||||
.await?;
|
||||
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub async fn read_by_query_overboard(
|
||||
ctx: &Ctx,
|
||||
query: String,
|
||||
page: i64,
|
||||
) -> Result<Vec<Self>, NekrochanError> {
|
||||
let posts =
|
||||
query_as("SELECT * FROM overboard WHERE LOWER(content_nomarkup) LIKE LOWER($1) LIMIT $2 OFFSET $3")
|
||||
.bind(format!("%{query}%"))
|
||||
.bind(GENERIC_PAGE_SIZE)
|
||||
.bind((page - 1) * GENERIC_PAGE_SIZE)
|
||||
.fetch_all(ctx.db())
|
||||
.await?;
|
||||
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub async fn update_user_id(&self, ctx: &Ctx, user_id: String) -> Result<(), NekrochanError> {
|
||||
let post = query_as(&format!(
|
||||
"UPDATE posts_{} SET user_id = $1 WHERE id = $2 RETURNING *",
|
||||
|
@ -74,8 +74,9 @@ async fn run() -> Result<(), Error> {
|
||||
.service(web::overboard::overboard)
|
||||
.service(web::overboard_catalog::overboard_catalog)
|
||||
.service(web::page::page)
|
||||
.service(web::thread_json::thread_json)
|
||||
.service(web::search::search)
|
||||
.service(web::thread::thread)
|
||||
.service(web::thread_json::thread_json)
|
||||
.service(web::actions::appeal_ban::appeal_ban)
|
||||
.service(web::actions::create_post::create_post)
|
||||
.service(web::actions::edit_posts::edit_posts)
|
||||
|
@ -262,9 +262,11 @@ pub async fn create_post(
|
||||
|
||||
let name_cookie = Cookie::build("name", name_raw).path("/").finish();
|
||||
let password_cookie = Cookie::build("password", password_raw).path("/").finish();
|
||||
let email_cookie = Cookie::build("email", email_raw).path("/").finish();
|
||||
|
||||
res.cookie(name_cookie);
|
||||
res.cookie(password_cookie);
|
||||
res.cookie(email_cookie);
|
||||
|
||||
let res = if noko {
|
||||
res.append_header(("Location", post.post_url().as_str()))
|
||||
|
@ -12,6 +12,7 @@ pub mod news;
|
||||
pub mod overboard;
|
||||
pub mod overboard_catalog;
|
||||
pub mod page;
|
||||
pub mod search;
|
||||
pub mod staff;
|
||||
pub mod tcx;
|
||||
pub mod thread;
|
||||
|
84
src/web/search.rs
Normální soubor
84
src/web/search.rs
Normální soubor
@ -0,0 +1,84 @@
|
||||
use actix_web::{
|
||||
get,
|
||||
web::{Data, Query},
|
||||
HttpRequest, HttpResponse,
|
||||
};
|
||||
use askama::Template;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::tcx::TemplateCtx;
|
||||
use crate::{
|
||||
ctx::Ctx,
|
||||
db::models::{Board, Post},
|
||||
error::NekrochanError,
|
||||
filters, web::template_response,
|
||||
};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "search.html")]
|
||||
struct SearchTemplate {
|
||||
tcx: TemplateCtx,
|
||||
board_opt: Option<Board>,
|
||||
boards: HashMap<String, Board>,
|
||||
query: String,
|
||||
posts: Vec<Post>,
|
||||
page: i64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SearchQuery {
|
||||
board: Option<String>,
|
||||
query: String,
|
||||
page: Option<i64>,
|
||||
}
|
||||
|
||||
#[get("/search")]
|
||||
pub async fn search(
|
||||
ctx: Data<Ctx>,
|
||||
req: HttpRequest,
|
||||
Query(query): Query<SearchQuery>,
|
||||
) -> Result<HttpResponse, NekrochanError> {
|
||||
let tcx = TemplateCtx::new(&ctx, &req).await?;
|
||||
|
||||
let board_opt = if let Some(board) = query.board {
|
||||
let board = Board::read(&ctx, board.clone())
|
||||
.await?
|
||||
.ok_or(NekrochanError::BoardNotFound(board))?;
|
||||
|
||||
Some(board)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let boards = if board_opt.is_none() {
|
||||
Board::read_all_map(&ctx).await?
|
||||
} else {
|
||||
HashMap::new()
|
||||
};
|
||||
|
||||
let page = query.page.unwrap_or(1);
|
||||
|
||||
if page <= 0 {
|
||||
return Err(NekrochanError::InvalidPageError);
|
||||
}
|
||||
|
||||
let query = query.query;
|
||||
|
||||
let posts = if let Some(board) = &board_opt {
|
||||
Post::read_by_query(&ctx, board, query.clone(), page).await?
|
||||
} else {
|
||||
Post::read_by_query_overboard(&ctx, query.clone(), page).await?
|
||||
};
|
||||
|
||||
let template = SearchTemplate {
|
||||
tcx,
|
||||
board_opt,
|
||||
boards,
|
||||
query,
|
||||
posts,
|
||||
page,
|
||||
};
|
||||
|
||||
template_response(&template)
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use actix_web::HttpRequest;
|
||||
use redis::{AsyncCommands, Commands, Connection};
|
||||
use sqlx::query_as;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
@ -18,6 +19,7 @@ pub struct TemplateCtx {
|
||||
pub perms: PermissionWrapper,
|
||||
pub ip: IpAddr,
|
||||
pub yous: HashSet<String>,
|
||||
pub report_count: Option<i64>,
|
||||
}
|
||||
|
||||
impl TemplateCtx {
|
||||
@ -37,6 +39,20 @@ impl TemplateCtx {
|
||||
|
||||
let account = account.map(|account| account.username);
|
||||
|
||||
let report_count = if perms.owner() || perms.reports() {
|
||||
let count: Option<Option<(i64,)>> = query_as("SELECT SUM(jsonb_array_length(reports)) FROM overboard WHERE reports != '[]'::jsonb")
|
||||
.fetch_optional(ctx.db())
|
||||
.await
|
||||
.ok();
|
||||
|
||||
match count {
|
||||
Some(Some((count,))) if count != 0 => Some(count),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let tcx = Self {
|
||||
cfg,
|
||||
boards,
|
||||
@ -44,6 +60,7 @@ impl TemplateCtx {
|
||||
ip,
|
||||
yous,
|
||||
account,
|
||||
report_count,
|
||||
};
|
||||
|
||||
Ok(tcx)
|
||||
|
@ -1,6 +1,7 @@
|
||||
$(function () {
|
||||
let name = get_cookie("name");
|
||||
let password = get_cookie("password");
|
||||
let email = get_cookie("email");
|
||||
|
||||
if (password === "") {
|
||||
password = generate_password();
|
||||
@ -9,9 +10,9 @@ $(function () {
|
||||
|
||||
$('input[name="post_name"]').attr("value", name);
|
||||
$('input[name="post_password"]').attr("value", password);
|
||||
});
|
||||
$('input[name="email"]').attr("value", email);
|
||||
|
||||
function generate_password() {
|
||||
function generate_password() {
|
||||
let chars =
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
let password_length = 8;
|
||||
@ -23,9 +24,9 @@ function generate_password() {
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
}
|
||||
|
||||
function get_cookie(cname) {
|
||||
function get_cookie(cname) {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(";");
|
||||
@ -43,8 +44,9 @@ function get_cookie(cname) {
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function set_cookie(cname, cvalue) {
|
||||
function set_cookie(cname, cvalue) {
|
||||
document.cookie = `${cname}=${cvalue};path=/`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ $(function () {
|
||||
|
||||
if (saved_left) {
|
||||
form.css("left", saved_left);
|
||||
form.css("right", "auto")
|
||||
form.css("right", "auto");
|
||||
}
|
||||
|
||||
handle.on("mousedown", start);
|
||||
@ -139,11 +139,12 @@ $(function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect.right > document.documentElement.clientWidth) {
|
||||
if (Math.floor(rect.right) > document.documentElement.clientWidth) {
|
||||
form.css("left", 0);
|
||||
form.css("right", "auto");
|
||||
}
|
||||
|
||||
if (rect.bottom > document.documentElement.clientHeight) {
|
||||
if (Math.floor(rect.bottom) > document.documentElement.clientHeight) {
|
||||
form.css("top", 0);
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,9 @@
|
||||
</span>
|
||||
{% endfor %}
|
||||
<span class="float-r">
|
||||
{% if let Some(report_count) = tcx.report_count %}
|
||||
<span class="link-group"><a href="/staff/reports">Hlášení: {{ report_count }}</a></span>
|
||||
{% endif %}
|
||||
{% if tcx.account.is_some() %}
|
||||
<span class="link-group">
|
||||
<a href="/logout">odhlásit se</a>
|
||||
|
@ -16,6 +16,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<form method="get" action="/search">
|
||||
<input name="board" type="hidden" value="{{ board.id }}">
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<td>
|
||||
<input name="query" type="text">
|
||||
</td>
|
||||
<td>
|
||||
<input class="button" type="submit" value="Hledat">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<hr>
|
||||
<form method="post">
|
||||
<div class="center">
|
||||
{% for thread in threads %}
|
||||
|
@ -7,7 +7,10 @@
|
||||
{% block title %}Příspěvky od [{{ ip }}]{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="title">Příspěvky od [{{ ip }}]</h1>
|
||||
<div class="center">
|
||||
<img class="banner" src="/random-banner">
|
||||
<h1 class="title">Příspěvky od [{{ ip }}]</h1>
|
||||
</div>
|
||||
<hr>
|
||||
<form method="post">
|
||||
<div class="thread">
|
||||
@ -19,7 +22,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
<hr>
|
||||
{% call static_pagination::static_pagination("/ip-posts/{}"|format(ip), page) %}
|
||||
{% call static_pagination::static_pagination("/ip-posts/{}"|format(ip), page, false) %}
|
||||
<hr>
|
||||
{% call post_actions::post_actions() %}
|
||||
</form>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<tr>
|
||||
<td class="label">Email</td>
|
||||
<td>
|
||||
<input name="email" type="text" autocomplete="off">
|
||||
<input name="email" type="text">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -1,13 +1,22 @@
|
||||
{% macro static_pagination(base, current) %}
|
||||
{% macro static_pagination(base, current, chain) %}
|
||||
<div class="pagination box inline-block">
|
||||
{% if current == 1 %}
|
||||
[Předchozí]
|
||||
{% else %}
|
||||
{% if chain %}
|
||||
[<a href="{{ base }}&page={{ current - 1 }}">Předchozí</a>]
|
||||
{% else %}
|
||||
[<a href="{{ base }}?page={{ current - 1 }}">Předchozí</a>]
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
 
|
||||
|
||||
{% if chain %}
|
||||
[<b><a href="{{ base }}&page={{ current }}">{{ current }}</a></b>] 
|
||||
[<a href="{{ base }}&page={{ current + 1 }}">Další</a>]
|
||||
{% else %}
|
||||
[<b><a href="{{ base }}?page={{ current }}">{{ current }}</a></b>] 
|
||||
[<a href="{{ base }}?page={{ current + 1 }}">Další</a>]
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="center">
|
||||
<img class="banner" src="/random-banner">
|
||||
<h1 class="title">Novinky</h1>
|
||||
</div>
|
||||
{% for newspost in news %}
|
||||
<div class="news box">
|
||||
<h2 class="headline">
|
||||
|
@ -15,6 +15,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<form method="get" action="/search">
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<td>
|
||||
<input name="query" type="text">
|
||||
</td>
|
||||
<td>
|
||||
<input class="button" type="submit" value="Hledat">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<hr>
|
||||
<form method="post">
|
||||
<div class="center">
|
||||
{% for thread in threads %}
|
||||
|
47
templates/search.html
Normální soubor
47
templates/search.html
Normální soubor
@ -0,0 +1,47 @@
|
||||
{% import "./macros/post-actions.html" as post_actions %}
|
||||
{% import "./macros/post.html" as post %}
|
||||
{% import "./macros/static-pagination.html" as static_pagination %}
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Vyhledávání ({% if let Some(board) = board_opt %}/{{ board.id }}/{% else %}nadnástěnka{% endif %})
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="center">
|
||||
<img class="banner" src="/random-banner">
|
||||
<h1 class="title">
|
||||
Výsledky pro "{{ query }}" (
|
||||
{% if let Some(board) = board_opt %}
|
||||
<a href="/boards/{{ board.id }}">/{{ board.id }}/</a>
|
||||
{% else %}
|
||||
nadnástěnka
|
||||
{% endif %}
|
||||
)
|
||||
</h1>
|
||||
</div>
|
||||
<hr>
|
||||
<form method="post">
|
||||
<div class="thread">
|
||||
{% for post in posts %}
|
||||
{% if let Some(board) = board_opt %}
|
||||
{% call post::post(board, post, true) %}
|
||||
{% else %}
|
||||
<b>Příspěvek z <a href="/boards/{{ post.board }}">/{{ post.board }}/</a></b>
|
||||
<br>
|
||||
{% call post::post(boards[post.board.as_str()], post, true) %}
|
||||
{% endif %}
|
||||
<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<hr>
|
||||
{% if let Some(board) = board_opt %}
|
||||
{% call static_pagination::static_pagination("/search?board={}&query={}"|format(board.id, query|urlencode_strict), page, true) %}
|
||||
{% else %}
|
||||
{% call static_pagination::static_pagination("/search?query={}"|format(query|urlencode_strict), page, true) %}
|
||||
{% endif %}
|
||||
<hr>
|
||||
{% call post_actions::post_actions() %}
|
||||
</form>
|
||||
{% endblock %}
|
@ -33,7 +33,7 @@
|
||||
</table>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
{% call static_pagination::static_pagination("/staff/reports", page) %}
|
||||
{% call static_pagination::static_pagination("/staff/reports", page, false) %}
|
||||
<hr>
|
||||
{% call post_actions::post_actions() %}
|
||||
</form>
|
||||
|
Načítá se…
Odkázat v novém úkolu
Zablokovat Uživatele