[Draft] Implement Reviewer Notice Link using Login Redirect #40
15 changed files with 50 additions and 57 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
|
@ -1351,7 +1351,6 @@ dependencies = [
|
|||
"http",
|
||||
"ldap3",
|
||||
"lettre",
|
||||
"listenfd",
|
||||
"log",
|
||||
"mime_guess",
|
||||
"multipart_helper",
|
||||
|
|
@ -1504,17 +1503,6 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "listenfd"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14e4fcc00ff6731d94b70e16e71f43bda62883461f31230742e3bc6dddf12988"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"uuid",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "local-channel"
|
||||
version = "0.1.3"
|
||||
|
|
@ -2668,12 +2656,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- missing lines around lists and headings triggering lints in changelog
|
||||
- new clippy lints
|
||||
- create storage dir when missing
|
||||
|
||||
### Change
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- startup errors are more descriptive
|
||||
- the confirmation link now works after confirmation so that submissions can be deleted early by the submitter
|
||||
- this changes the on-disk format slightly as the token now has a different scope and was moved accordingly
|
||||
- reviewe notice link is now indirect via the login page
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ RUN useradd -u $UID -g dev -m dev
|
|||
|
||||
RUN echo -e "\ndev ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
|
||||
RUN rm -rd /etc/pacman.d/gnupg
|
||||
RUN pacman-key --init
|
||||
RUN pacman-key --populate
|
||||
RUN pacman -Sy archlinux-keyring --noconfirm
|
||||
|
||||
RUN pacman -Syu --noconfirm
|
||||
|
||||
COPY . /src_dir
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ lettre = { workspace = true, default-features = false, features = ["sendmail-tra
|
|||
# use rustls a native tls library rather than openssl,
|
||||
# as depending on c dependencies can get annoying even when vendoring
|
||||
ldap3 = { workspace = true, default-features = false, features = ["tls-rustls"] }
|
||||
listenfd = { workspace = true }
|
||||
log = { workspace = true }
|
||||
mime_guess = { workspace = true }
|
||||
multipart_helper = { workspace = true }
|
||||
|
|
|
|||
BIN
packages/jobboerse/THIRDPARTY.toml
(Stored with Git LFS)
BIN
packages/jobboerse/THIRDPARTY.toml
(Stored with Git LFS)
Binary file not shown.
|
|
@ -1,11 +1,12 @@
|
|||
use crate::job_offers::error::EmailError;
|
||||
use crate::route::RETURN_TO;
|
||||
use crate::server_config::EmailConfig;
|
||||
use crate::template;
|
||||
use handlebars::Handlebars;
|
||||
use lettre::message::header::{Header, HeaderName, HeaderValue, UserAgent};
|
||||
use lettre::message::{Mailbox, SinglePart};
|
||||
use lettre::{Address, AsyncTransport};
|
||||
use log::warn;
|
||||
use log::{warn, debug};
|
||||
use serde_json::json;
|
||||
use url::Url;
|
||||
|
||||
|
|
@ -68,13 +69,20 @@ pub(crate) async fn send_confirmation_email(
|
|||
pub(crate) async fn send_reviewer_notice(
|
||||
hb: &Handlebars<'_>,
|
||||
email_config: &EmailConfig,
|
||||
url: Url,
|
||||
highlight_url: Url,
|
||||
mut login_url: Url,
|
||||
) {
|
||||
// successfully send a confirmation e-mail now send a notice to our-self
|
||||
|
||||
login_url
|
||||
.query_pairs_mut()
|
||||
.append_pair(RETURN_TO, highlight_url.as_str());
|
||||
|
||||
debug!("Url:\n{login_url}");
|
||||
|
||||
let body = match hb.render(
|
||||
template::EMAIL_REVIEWER_NOTICE,
|
||||
&json!({ "highlight_link": url }),
|
||||
&json!({ "highlight_link": login_url }),
|
||||
) {
|
||||
Ok(body) => body,
|
||||
Err(err) => {
|
||||
|
|
@ -83,6 +91,8 @@ pub(crate) async fn send_reviewer_notice(
|
|||
}
|
||||
};
|
||||
|
||||
debug!("Sending:\n{body}");
|
||||
|
||||
let message = lettre::Message::builder()
|
||||
.from(email_config.from.to_owned())
|
||||
.to(email_config.from.to_owned())
|
||||
|
|
|
|||
|
|
@ -74,10 +74,6 @@ pub(crate) enum SeverInitializationError {
|
|||
TemplateError(#[from] handlebars::TemplateError),
|
||||
#[error("the jobboerse server encountered a fatal io error during startup, could not bind socket: {0}")]
|
||||
Bind(std::io::Error),
|
||||
#[error("the jobboerse server encountered a fatal io error during startup, could not listen on socket: {0}")]
|
||||
TakeListen(std::io::Error),
|
||||
#[error("the jobboerse server encountered a fatal io error during startup, could not take listen socket: {0}")]
|
||||
Listen(std::io::Error),
|
||||
#[error("the jobboerse server encountered a fatal io error during startup, could not start the server: {0}")]
|
||||
Run(std::io::Error),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -654,6 +654,10 @@ impl JobOffers {
|
|||
let storage = &config.config.data_storage_path;
|
||||
info!("Loading Job Offers from {}", storage.display());
|
||||
|
||||
tokio::fs::create_dir_all(storage)
|
||||
.await
|
||||
.map_err(|err| JobofferLoadError::IO(err, storage.clone()))?;
|
||||
|
||||
let mut dir = tokio::fs::read_dir(storage)
|
||||
.await
|
||||
.map_err(|err| JobofferLoadError::IO(err, storage.clone()))?;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use actix_web::middleware::{ErrorHandlers, NormalizePath, TrailingSlash};
|
|||
use actix_web::{get, web, App, HttpServer};
|
||||
use error::SeverInitializationError;
|
||||
use handlebars::Handlebars;
|
||||
use listenfd::ListenFd;
|
||||
use log::{error, LevelFilter, SetLoggerError};
|
||||
// internal imports
|
||||
use job_offers::lease::SubmissionLimiter;
|
||||
|
|
@ -65,8 +64,6 @@ async fn main() -> Result<(), error::SeverInitializationError> {
|
|||
async fn run() -> Result<(), error::SeverInitializationError> {
|
||||
let server_config = ServerConfig::load().await?;
|
||||
|
||||
let mut listen_fd = ListenFd::from_env();
|
||||
|
||||
let mut hb = Handlebars::new();
|
||||
let bundle =
|
||||
bundle_licenses_lib::format::Format::Toml.deserialize_from_reader(route::LICENSE_BUNDLE)?;
|
||||
|
|
@ -151,19 +148,12 @@ async fn run() -> Result<(), error::SeverInitializationError> {
|
|||
app
|
||||
});
|
||||
|
||||
if let Some(l) = listen_fd
|
||||
.take_tcp_listener(0)
|
||||
.map_err(SeverInitializationError::TakeListen)?
|
||||
{
|
||||
server.listen(l).map_err(SeverInitializationError::Listen)?
|
||||
} else {
|
||||
let ipv6 = SocketAddr::from((Ipv6Addr::UNSPECIFIED, port));
|
||||
let ipv4 = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port));
|
||||
let ipv6 = SocketAddr::from((Ipv6Addr::UNSPECIFIED, port));
|
||||
let ipv4 = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port));
|
||||
|
||||
server
|
||||
.bind([ipv6, ipv4].as_slice())
|
||||
.map_err(SeverInitializationError::Bind)?
|
||||
}
|
||||
server
|
||||
.bind([ipv6, ipv4].as_slice())
|
||||
.map_err(SeverInitializationError::Bind)?
|
||||
.run()
|
||||
.await
|
||||
.map_err(SeverInitializationError::Run)?;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub(crate) mod form_constants;
|
|||
mod job_offer;
|
||||
mod license;
|
||||
|
||||
pub(crate) use auth::{LOGIN_ROUTE, LOGOUT_ROUTE};
|
||||
pub(crate) use auth::{LOGIN_ROUTE, LOGOUT_ROUTE, RETURN_TO};
|
||||
pub(crate) use job_offer::{
|
||||
confirmation::JOBOFFER_CONFIRM_ROUTE,
|
||||
create::JOBOFFER_CREATION_ROUTE,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ pub(crate) fn configure(config: &mut ServiceConfig) {
|
|||
}
|
||||
|
||||
pub(crate) const LOGIN_ROUTE: &str = "login";
|
||||
pub(crate) const RETURN_TO: &str = "return_to";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub(crate) struct LoginQuery {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ use multipart_helper::MultipartFieldError;
|
|||
use serde_json::json;
|
||||
use url::Url;
|
||||
|
||||
use super::auth::RETURN_TO;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Some error occurred while attempting to display an error page")]
|
||||
pub struct ErrorHandlerResponseError;
|
||||
|
|
@ -226,7 +228,7 @@ fn login_url_with_return(req: &HttpRequest, return_to: &str) -> Result<Url, UrlG
|
|||
|
||||
login_url
|
||||
.query_pairs_mut()
|
||||
.append_pair("return_to", return_to);
|
||||
.append_pair(RETURN_TO, return_to);
|
||||
|
||||
Ok(login_url)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use crate::job_offers::{
|
|||
use crate::route::form_constants::{self, UploadLimits};
|
||||
use crate::route::job_offer::confirmation::JOBOFFER_CONFIRM_ROUTE;
|
||||
use crate::route::job_offer::error::{FormProcessingError, SubmissionResponseError};
|
||||
use crate::route::HTML_CONTENT;
|
||||
use crate::route::{HTML_CONTENT, LOGIN_ROUTE};
|
||||
use crate::server_config::ServerConfig;
|
||||
use crate::util::{parse_date, parse_datetime, process_links, process_new_attachments};
|
||||
use crate::{email, template};
|
||||
|
|
@ -248,9 +248,12 @@ pub(crate) async fn create_job_offer<'data, 'config>(
|
|||
|
||||
if let Some(email_config) = &config.config.email {
|
||||
if !is_pre_approved {
|
||||
match created_offer.highlight_link(req) {
|
||||
Ok(highlight_url) => {
|
||||
email::send_reviewer_notice(hb, email_config, highlight_url).await;
|
||||
match created_offer
|
||||
.highlight_link(req)
|
||||
.and_then(|highlight| Ok((highlight, req.url_for_static(LOGIN_ROUTE)?)))
|
||||
{
|
||||
Ok((highlight_url, login_url)) => {
|
||||
email::send_reviewer_notice(hb, &email_config, highlight_url, login_url).await;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to generate highlight link: {}", err)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
Automatischer Hinweis: Eine neue Stellenausschreibung wurde zur Jobbörse eingereicht!
|
||||
|
||||
{{highlight_link}}
|
||||
{{{highlight_link}}}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,10 @@ RUN_DIR="${DIR}/../packages/jobboerse"
|
|||
|
||||
pushd "${RUN_DIR}"
|
||||
|
||||
systemfd \
|
||||
--no-pid \
|
||||
-s http::8080 \
|
||||
-- cargo watch \
|
||||
-i ./packages/jobboerse/config/dev-config.toml \
|
||||
-x "run --package jobboerse --bin jobboerse --release --features=dev_mode -- --config=\"${CFG}\" --mode=development"
|
||||
export RUST_LOG=debug
|
||||
|
||||
cargo watch \
|
||||
-i ./packages/jobboerse/config/dev-config.toml \
|
||||
-x "run --package jobboerse --bin jobboerse --release --features=dev_mode -- --config=\"${CFG}\" --mode=development"
|
||||
|
||||
popd
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue