pastebin/src/models/paste.rs

118 lines
3.2 KiB
Rust

// pastebin.run
// Copyright (C) 2020-2022 Konrad Borowski
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::schema::pastes;
use chrono::{DateTime, Utc};
use diesel::prelude::*;
use log::info;
use rand::seq::SliceRandom;
use rocket::response::{self, Debug, Responder};
use rocket::Request;
use serde::Serialize;
use serde_with::skip_serializing_none;
#[derive(Queryable)]
pub struct Paste {
pub identifier: String,
pub paste: String,
pub delete_at: Option<DateTime<Utc>>,
}
impl Paste {
pub fn delete_old(connection: &PgConnection) -> Result<(), diesel::result::Error> {
let pastes = diesel::delete(pastes::table)
.filter(pastes::delete_at.lt(Utc::now()))
.execute(connection)?;
if pastes > 0 {
info!("Deleted {} paste(s)", pastes);
}
Ok(())
}
}
const CHARACTERS: &[u8] = b"23456789bcdfghjkmnpqrstvwxz-";
#[derive(Insertable)]
#[table_name = "pastes"]
struct InsertPaste<'a> {
identifier: &'a str,
delete_at: Option<DateTime<Utc>>,
paste: &'a str,
}
#[derive(Debug)]
pub enum InsertionError {
Diesel(diesel::result::Error),
}
impl From<diesel::result::Error> for InsertionError {
fn from(e: diesel::result::Error) -> Self {
Self::Diesel(e)
}
}
impl<'r> Responder<'r, 'static> for InsertionError {
fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> {
match self {
Self::Diesel(e) => Debug(e).respond_to(request),
}
}
}
pub fn insert(
connection: &PgConnection,
delete_at: Option<DateTime<Utc>>,
paste: &str,
) -> Result<String, InsertionError> {
let mut rng = rand::thread_rng();
let identifier: String = (0..12)
.map(|_| char::from(*CHARACTERS.choose(&mut rng).expect("a random character")))
.collect();
let insert_paste = InsertPaste {
identifier: &identifier,
delete_at,
paste,
};
diesel::insert_into(pastes::table)
.values(&insert_paste)
.execute(connection)?;
Ok(identifier)
}
#[skip_serializing_none]
#[derive(Serialize)]
pub struct ExternPaste {
pub identifier: Option<String>,
pub paste: String,
pub delete_at: Option<String>,
}
impl ExternPaste {
pub fn from_paste(paste: Paste) -> Self {
let Paste {
identifier,
paste,
delete_at,
} = paste;
Self {
identifier: Some(identifier),
paste,
delete_at: delete_at.map(|delete_at| delete_at.format("%Y-%m-%d %H:%M").to_string()),
}
}
}