Merge branch 'pr/95'

This commit is contained in:
Daniel Szabo 2022-11-14 21:42:35 +02:00
commit ba784da74e
15 changed files with 198 additions and 53 deletions

154
.github/workflows/gh-release.yml vendored Normal file
View file

@ -0,0 +1,154 @@
name: GitHub Release
on:
push:
tags:
- v[0-9]+.[0-9]+.[0-9]+*
jobs:
release:
name: Publish to Github Releases
outputs:
rc: ${{ steps.check-tag.outputs.rc }}
strategy:
matrix:
include:
- target: aarch64-unknown-linux-musl
os: ubuntu-latest
use-cross: true
cargo-flags: ""
- target: aarch64-apple-darwin
os: macos-latest
use-cross: true
cargo-flags: ""
- target: aarch64-pc-windows-msvc
os: windows-latest
use-cross: true
cargo-flags: "--no-default-features"
- target: x86_64-apple-darwin
os: macos-latest
cargo-flags: ""
- target: x86_64-pc-windows-msvc
os: windows-latest
cargo-flags: ""
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
use-cross: true
cargo-flags: ""
- target: i686-unknown-linux-musl
os: ubuntu-latest
use-cross: true
cargo-flags: ""
- target: i686-pc-windows-msvc
os: windows-latest
use-cross: true
cargo-flags: ""
- target: armv7-unknown-linux-musleabihf
os: ubuntu-latest
use-cross: true
cargo-flags: ""
- target: arm-unknown-linux-musleabihf
os: ubuntu-latest
use-cross: true
cargo-flags: ""
- target: mips-unknown-linux-musl
os: ubuntu-latest
use-cross: true
cargo-flags: "--no-default-features"
- target: mipsel-unknown-linux-musl
os: ubuntu-latest
use-cross: true
cargo-flags: "--no-default-features"
- target: mips64-unknown-linux-gnuabi64
os: ubuntu-latest
use-cross: true
cargo-flags: "--no-default-features"
- target: mips64el-unknown-linux-gnuabi64
os: ubuntu-latest
use-cross: true
cargo-flags: "--no-default-features"
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Check Tag
id: check-tag
shell: bash
run: |
tag=${GITHUB_REF##*/}
echo "::set-output name=version::$tag"
if [[ "$tag" =~ [0-9]+.[0-9]+.[0-9]+$ ]]; then
echo "::set-output name=rc::false"
else
echo "::set-output name=rc::true"
fi
- name: Install Rust Toolchain Components
uses: actions-rs/toolchain@v1
with:
override: true
target: ${{ matrix.target }}
toolchain: stable
profile: minimal # minimal component installation (ie, no documentation)
- name: Show Version Information (Rust, cargo, GCC)
shell: bash
run: |
gcc --version || true
rustup -V
rustup toolchain list
rustup default
cargo -V
rustc -V
- name: Build
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.use-cross }}
command: build
args: --locked --release --target=${{ matrix.target }} ${{ matrix.cargo-flags }}
- name: Build Archive
shell: bash
id: package
env:
target: ${{ matrix.target }}
version: ${{ steps.check-tag.outputs.version }}
run: |
set -euxo pipefail
bin=${GITHUB_REPOSITORY##*/}
src=`pwd`
dist=$src/dist
name=$bin-$version-$target
executable=target/$target/release/$bin
if [[ "$RUNNER_OS" == "Windows" ]]; then
executable=$executable.exe
fi
mkdir $dist
cp $executable $dist
cd $dist
if [[ "$RUNNER_OS" == "Windows" ]]; then
archive=$dist/$name.zip
7z a $archive *
echo "::set-output name=archive::`pwd -W`/$name.zip"
else
archive=$dist/$name.tar.gz
tar czf $archive *
echo "::set-output name=archive::$archive"
fi
- name: Publish Archive
uses: softprops/action-gh-release@v0.1.5
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
draft: false
files: ${{ steps.package.outputs.archive }}
prerelease: ${{ steps.check-tag.outputs.rc == 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -8,6 +8,7 @@ RUN \
DEBIAN_FRONTEND=noninteractive \ DEBIAN_FRONTEND=noninteractive \
apt-get update &&\ apt-get update &&\
apt-get -y install ca-certificates tzdata &&\ apt-get -y install ca-certificates tzdata &&\
CARGO_NET_GIT_FETCH_WITH_CLI=true \
cargo build --release cargo build --release
# https://hub.docker.com/r/bitnami/minideb # https://hub.docker.com/r/bitnami/minideb
@ -25,7 +26,7 @@ COPY --from=build \
/etc/ssl/certs/ca-certificates.crt \ /etc/ssl/certs/ca-certificates.crt \
/etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
# copy built exacutable # copy built executable
COPY --from=build \ COPY --from=build \
/app/target/release/microbin \ /app/target/release/microbin \
/usr/bin/microbin /usr/bin/microbin
@ -33,4 +34,4 @@ COPY --from=build \
# Expose webport used for the webserver to the docker runtime # Expose webport used for the webserver to the docker runtime
EXPOSE 8080 EXPOSE 8080
ENTRYPOINT ["microbin"] ENTRYPOINT ["microbin"]

View file

@ -19,12 +19,12 @@ And run with your custom configuration:
Or get the Docker image from [Dockerhub: danielszabo99/microbin](https://hub.docker.com/r/danielszabo99/microbin) Or get the Docker image from [Dockerhub: danielszabo99/microbin](https://hub.docker.com/r/danielszabo99/microbin)
On our website [microbin.eu](microbin.eu) you will find the following: On our website [microbin.eu](https://microbin.eu) you will find the following:
- [Screenshots](https://microbin.eu/screenshots/) - [Screenshots](https://microbin.eu/screenshots/)
- [Quickstart Guide](https://microbin.eu/quickstart/) - [Quickstart Guide](https://microbin.eu/quickstart/)
- [Documentation](https://microbin.eu/documentation/) - [Documentation](https://microbin.eu/documentation/)
- [Donations and Sponsorhip](https://microbin.eu/donate/) - [Donations and Sponsorships](https://microbin.eu/donate/)
- [Community](https://microbin.eu/community/) - [Community](https://microbin.eu/community/)
### Features ### Features
@ -67,4 +67,4 @@ You can use MicroBin
MicroBin and MicroBin.eu are available under the BSD 3-Clause License. MicroBin and MicroBin.eu are available under the BSD 3-Clause License.
© Dániel Szabó 2022 © Dániel Szabó 2022

View file

@ -122,7 +122,7 @@ pub async fn create(
while let Some(chunk) = field.try_next().await? { while let Some(chunk) = field.try_next().await? {
content.push_str(std::str::from_utf8(&chunk).unwrap().to_string().as_str()); content.push_str(std::str::from_utf8(&chunk).unwrap().to_string().as_str());
} }
if content.len() > 0 { if !content.is_empty() {
new_pasta.content = content; new_pasta.content = content;
new_pasta.pasta_type = if is_valid_url(new_pasta.content.as_str()) { new_pasta.pasta_type = if is_valid_url(new_pasta.content.as_str()) {
@ -152,7 +152,7 @@ pub async fn create(
None => continue, None => continue,
}; };
let mut file = match PastaFile::from_unsanitized(&path) { let mut file = match PastaFile::from_unsanitized(path) {
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(e) => {
warn!("Unsafe file name: {e:?}"); warn!("Unsafe file name: {e:?}");

View file

@ -22,9 +22,9 @@ pub async fn get_edit(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
let id = if ARGS.hash_ids { let id = if ARGS.hash_ids {
hashid_to_u64(&*id).unwrap_or(0) hashid_to_u64(&id).unwrap_or(0)
} else { } else {
to_u64(&*id.into_inner()).unwrap_or(0) to_u64(&id.into_inner()).unwrap_or(0)
}; };
remove_expired(&mut pastas); remove_expired(&mut pastas);
@ -36,14 +36,9 @@ pub async fn get_edit(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
.append_header(("Location", format!("{}/", ARGS.public_path))) .append_header(("Location", format!("{}/", ARGS.public_path)))
.finish(); .finish();
} }
return HttpResponse::Ok().content_type("text/html").body( return HttpResponse::Ok()
EditTemplate { .content_type("text/html")
pasta: &pasta, .body(EditTemplate { pasta, args: &ARGS }.render().unwrap());
args: &ARGS,
}
.render()
.unwrap(),
);
} }
} }
@ -65,9 +60,9 @@ pub async fn post_edit(
} }
let id = if ARGS.hash_ids { let id = if ARGS.hash_ids {
hashid_to_u64(&*id).unwrap_or(0) hashid_to_u64(&id).unwrap_or(0)
} else { } else {
to_u64(&*id.into_inner()).unwrap_or(0) to_u64(&id.into_inner()).unwrap_or(0)
}; };
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
@ -77,20 +72,17 @@ pub async fn post_edit(
let mut new_content = String::from(""); let mut new_content = String::from("");
while let Some(mut field) = payload.try_next().await? { while let Some(mut field) = payload.try_next().await? {
match field.name() { if field.name() == "content" {
"content" => { while let Some(chunk) = field.try_next().await? {
while let Some(chunk) = field.try_next().await? { new_content = std::str::from_utf8(&chunk).unwrap().to_string();
new_content = std::str::from_utf8(&chunk).unwrap().to_string();
}
} }
_ => {}
} }
} }
for (i, pasta) in pastas.iter().enumerate() { for (i, pasta) in pastas.iter().enumerate() {
if pasta.id == id { if pasta.id == id {
if pasta.editable { if pasta.editable {
pastas[i].content.replace_range(.., &*new_content); pastas[i].content.replace_range(.., &new_content);
save_to_file(&pastas); save_to_file(&pastas);
return Ok(HttpResponse::Found() return Ok(HttpResponse::Found()

View file

@ -17,7 +17,7 @@ struct Info<'a> {
#[get("/info")] #[get("/info")]
pub async fn info(data: web::Data<AppState>) -> HttpResponse { pub async fn info(data: web::Data<AppState>) -> HttpResponse {
// get access to the pasta collection // get access to the pasta collection
let mut pastas = data.pastas.lock().unwrap(); let pastas = data.pastas.lock().unwrap();
// todo status report more sophisticated // todo status report more sophisticated
let mut status = "OK"; let mut status = "OK";

View file

@ -6,7 +6,7 @@ use crate::util::animalnumbers::to_u64;
use crate::util::hashids::to_u64 as hashid_to_u64; use crate::util::hashids::to_u64 as hashid_to_u64;
use crate::util::misc::remove_expired; use crate::util::misc::remove_expired;
use crate::AppState; use crate::AppState;
use actix_web::rt::time;
use actix_web::{get, web, HttpResponse}; use actix_web::{get, web, HttpResponse};
use askama::Template; use askama::Template;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
@ -24,9 +24,9 @@ pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
let id = if ARGS.hash_ids { let id = if ARGS.hash_ids {
hashid_to_u64(&*id).unwrap_or(0) hashid_to_u64(&id).unwrap_or(0)
} else { } else {
to_u64(&*id.into_inner()).unwrap_or(0) to_u64(&id.into_inner()).unwrap_or(0)
}; };
// remove expired pastas (including this one if needed) // remove expired pastas (including this one if needed)
@ -45,7 +45,7 @@ pub async fn getpasta(data: web::Data<AppState>, id: web::Path<String>) -> HttpR
if found { if found {
// increment read count // increment read count
pastas[index].read_count = pastas[index].read_count + 1; pastas[index].read_count += 1;
// save the updated read count // save the updated read count
save_to_file(&pastas); save_to_file(&pastas);
@ -88,9 +88,9 @@ pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> Ht
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
let id = if ARGS.hash_ids { let id = if ARGS.hash_ids {
hashid_to_u64(&*id).unwrap_or(0) hashid_to_u64(&id).unwrap_or(0)
} else { } else {
to_u64(&*id.into_inner()).unwrap_or(0) to_u64(&id.into_inner()).unwrap_or(0)
}; };
// remove expired pastas (including this one if needed) // remove expired pastas (including this one if needed)
@ -110,7 +110,7 @@ pub async fn redirecturl(data: web::Data<AppState>, id: web::Path<String>) -> Ht
if found { if found {
// increment read count // increment read count
pastas[index].read_count = pastas[index].read_count + 1; pastas[index].read_count += 1;
// save the updated read count // save the updated read count
save_to_file(&pastas); save_to_file(&pastas);
@ -155,9 +155,9 @@ pub async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> St
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
let id = if ARGS.hash_ids { let id = if ARGS.hash_ids {
hashid_to_u64(&*id).unwrap_or(0) hashid_to_u64(&id).unwrap_or(0)
} else { } else {
to_u64(&*id.into_inner()).unwrap_or(0) to_u64(&id.into_inner()).unwrap_or(0)
}; };
// remove expired pastas (including this one if needed) // remove expired pastas (including this one if needed)
@ -176,7 +176,7 @@ pub async fn getrawpasta(data: web::Data<AppState>, id: web::Path<String>) -> St
if found { if found {
// increment read count // increment read count
pastas[index].read_count = pastas[index].read_count + 1; pastas[index].read_count += 1;
// get current unix time in seconds // get current unix time in seconds
let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) { let timenow: i64 = match SystemTime::now().duration_since(UNIX_EPOCH) {

View file

@ -7,8 +7,6 @@ use crate::util::misc::{self, remove_expired};
use crate::AppState; use crate::AppState;
use actix_web::{get, web, HttpResponse}; use actix_web::{get, web, HttpResponse};
use askama::Template; use askama::Template;
use qrcode_generator::QrCodeEcc;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Template)] #[derive(Template)]
#[template(path = "qr.html", escape = "none")] #[template(path = "qr.html", escape = "none")]

View file

@ -21,9 +21,9 @@ pub async fn remove(data: web::Data<AppState>, id: web::Path<String>) -> HttpRes
let mut pastas = data.pastas.lock().unwrap(); let mut pastas = data.pastas.lock().unwrap();
let id = if ARGS.hash_ids { let id = if ARGS.hash_ids {
hashid_to_u64(&*id).unwrap_or(0) hashid_to_u64(&id).unwrap_or(0)
} else { } else {
to_u64(&*id.into_inner()).unwrap_or(0) to_u64(&id.into_inner()).unwrap_or(0)
}; };
for (i, pasta) in pastas.iter().enumerate() { for (i, pasta) in pastas.iter().enumerate() {

View file

@ -1,4 +1,4 @@
use actix_web::{web, App, HttpResponse, HttpServer, Responder}; use actix_web::{web, HttpResponse, Responder};
use mime_guess::from_path; use mime_guess::from_path;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;

View file

@ -118,7 +118,7 @@ impl Pasta {
}; };
// it's less than 1 second????? // it's less than 1 second?????
return String::from("just now"); String::from("just now")
} }
pub fn last_read_days_ago(&self) -> u16 { pub fn last_read_days_ago(&self) -> u16 {
@ -132,7 +132,7 @@ impl Pasta {
} as i64; } as i64;
// get seconds since last read and convert it to days // get seconds since last read and convert it to days
return ((timenow - self.last_read) / 86400) as u16; ((timenow - self.last_read) / 86400) as u16
} }
pub fn content_syntax_highlighted(&self) -> String { pub fn content_syntax_highlighted(&self) -> String {
@ -144,7 +144,7 @@ impl Pasta {
} }
pub fn content_escaped(&self) -> String { pub fn content_escaped(&self) -> String {
self.content.replace("`", "\\`").replace("$", "\\$") self.content.replace('`', "\\`").replace('$', "\\$")
} }
} }

View file

@ -24,7 +24,7 @@ pub fn to_animal_names(mut number: u64) -> String {
number -= digit * ANIMAL_NAMES.len().pow(power) as u64; number -= digit * ANIMAL_NAMES.len().pow(power) as u64;
if power > 0 { if power > 0 {
power -= 1; power -= 1;
} else if power <= 0 || number == 0 { } else if power == 0 || number == 0 {
break; break;
} }
} }
@ -35,12 +35,12 @@ pub fn to_animal_names(mut number: u64) -> String {
pub fn to_u64(animal_names: &str) -> Result<u64, &str> { pub fn to_u64(animal_names: &str) -> Result<u64, &str> {
let mut result: u64 = 0; let mut result: u64 = 0;
let animals: Vec<&str> = animal_names.split("-").collect(); let animals: Vec<&str> = animal_names.split('-').collect();
let mut pow = animals.len(); let mut pow = animals.len();
for i in 0..animals.len() { for animal in animals {
pow -= 1; pow -= 1;
let animal_index = ANIMAL_NAMES.iter().position(|&r| r == animals[i]); let animal_index = ANIMAL_NAMES.iter().position(|&r| r == animal);
match animal_index { match animal_index {
None => return Err("Failed to convert animal name to u64!"), None => return Err("Failed to convert animal name to u64!"),
Some(_) => { Some(_) => {

View file

@ -4,7 +4,7 @@ use std::io::{BufReader, BufWriter};
use crate::Pasta; use crate::Pasta;
static DATABASE_PATH: &'static str = "pasta_data/database.json"; static DATABASE_PATH: &str = "pasta_data/database.json";
pub fn save_to_file(pasta_data: &Vec<Pasta>) { pub fn save_to_file(pasta_data: &Vec<Pasta>) {
let mut file = File::create(DATABASE_PATH); let mut file = File::create(DATABASE_PATH);

View file

@ -13,6 +13,6 @@ pub fn to_u64(hash_id: &str) -> Result<u64, &str> {
let ids = HARSH let ids = HARSH
.decode(hash_id) .decode(hash_id)
.map_err(|_e| "Failed to decode hash ID")?; .map_err(|_e| "Failed to decode hash ID")?;
let id = ids.get(0).ok_or("No ID found in hash ID")?; let id = ids.first().ok_or("No ID found in hash ID")?;
Ok(*id) Ok(*id)
} }

View file

@ -11,7 +11,7 @@ pub fn html_highlight(text: &str, extension: &str) -> String {
let syntax = ps let syntax = ps
.find_syntax_by_extension(extension) .find_syntax_by_extension(extension)
.or(Option::from(ps.find_syntax_plain_text())) .or_else(|| Option::from(ps.find_syntax_plain_text()))
.unwrap(); .unwrap();
let mut h = HighlightLines::new(syntax, &ts.themes["InspiredGitHub"]); let mut h = HighlightLines::new(syntax, &ts.themes["InspiredGitHub"]);
@ -33,5 +33,5 @@ pub fn html_highlight(text: &str, extension: &str) -> String {
highlighted_content2 = highlighted_content2 =
highlighted_content2.replace("style=\"color:#183691;\"", "style=\"color:blue;\""); highlighted_content2.replace("style=\"color:#183691;\"", "style=\"color:blue;\"");
return highlighted_content2; highlighted_content2
} }