move record list conversion to models module

main
Hannaeko 2022-03-04 19:43:19 +01:00
parent 96f66e1fd7
commit 77cc634257
6 changed files with 67 additions and 30 deletions

View File

@ -130,6 +130,20 @@ impl From<DnsApiError> for ErrorResponse {
}
}
impl From<models::RecordListParseError> for ErrorResponse {
fn from(e: models::RecordListParseError) -> Self {
models::ErrorResponse::new(
Status::BadRequest,
"Record list contains records that could not be parsed into DNS records".into()
).with_details(
json!({
"zone_name": e.zone.to_utf8(),
"records": e.bad_records
})
)
}
}
impl<S> From<ErrorResponse> for Outcome<S, ErrorResponse> {
fn from(e: ErrorResponse) -> Self {

View File

@ -15,5 +15,5 @@ pub use errors::{UserError, ErrorResponse, make_500};
pub use name::{AbsoluteName, SerdeName};
pub use user::{LocalUser, UserInfo, Role, UserZone, User, CreateUserRequest};
pub use rdata::RData;
pub use record::Record;
pub use record::{Record, RecordList, ParseRecordList, RecordListParseError};
pub use zone::{Zone, AddZoneMemberRequest, CreateZoneRequest};

View File

@ -69,4 +69,10 @@ impl Deref for AbsoluteName {
fn deref(&self) -> &Self::Target {
&self.0.0
}
}
impl AbsoluteName {
pub fn into_inner(self) -> Name {
self.0.0
}
}

View File

@ -247,7 +247,7 @@ impl TryFrom<RData> for dns::RData {
// TODO: Error out for DNSSEC? Prefer downstream checks?
RData::DNSSEC(_) => todo!(),
// TODO: Disallow unknown? (could be used to bypass unsopported types?) Prefer downstream checks?
RData::Unknown { code, data } => todo!(),
RData::Unknown { code: _code, data: _data } => todo!(),
})
}
}

View File

@ -40,4 +40,41 @@ impl TryFrom<Record> for dns::Record {
trust_dns_record.set_dns_class(record.dns_class.into());
Ok(trust_dns_record)
}
}
pub type RecordList = Vec<Record>;
pub struct RecordListParseError {
pub bad_records: Vec<Record>,
pub zone: dns::Name,
}
pub trait ParseRecordList {
fn try_into_dns_type(self, zone: dns::Name) -> Result<Vec<dns::Record>, RecordListParseError>;
}
impl ParseRecordList for RecordList {
fn try_into_dns_type(self, zone: dns::Name) -> Result<Vec<dns::Record>, RecordListParseError> {
// TODO: What about relative names (also in cnames and stuff)
let mut bad_records = Vec::new();
let mut records: Vec<dns::Record> = Vec::new();
for record in self.into_iter() {
let this_record = record.clone();
if let Ok(record) = record.try_into() {
records.push(record);
} else {
bad_records.push(this_record.clone());
}
}
if !bad_records.is_empty() {
return Err(RecordListParseError {
zone,
bad_records,
});
}
return Ok(records)
}
}

View File

@ -1,14 +1,13 @@
use std::convert::TryInto;
use serde_json::json;
use rocket::Response;
use rocket::http::Status;
use rocket_contrib::json::Json;
use crate::DbConn;
use crate::models;
use crate::dns;
use crate::models;
use crate::dns::{RecordApi, ZoneApi};
use crate::models::{ParseRecordList};
#[get("/zones/<zone>/records")]
@ -58,33 +57,14 @@ pub async fn create_zone_records(
}
}).await?;
// TODO: What about relative names (also in cnames and stuff)
let mut bad_records = Vec::new();
let mut records: Vec<dns::Record> = Vec::new();
for record in new_records.into_inner().into_iter() {
let this_record = record.clone();
if let Ok(record) = record.try_into() {
records.push(record);
} else {
bad_records.push(this_record.clone());
}
}
if !bad_records.is_empty() {
return models::ErrorResponse::new(
Status::BadRequest,
"Record list contains records that could not been parsed into DNS records".into()
).with_details(
json!({
"zone_name": zone.to_utf8(),
"records": bad_records
})
).err();
}
let mut dns_api = dns::DnsApiClient::new(client);
dns_api.add_records(zone.clone(), dns::DNSClass::IN, records).await?;
dns_api.add_records(
zone.clone(),
models::DNSClass::IN.into(),
new_records.into_inner().try_into_dns_type(zone.into_inner())?
).await?;
return Ok(Json(()));
}