///|
pub(all) struct PrivacyReport {
records : Int
local_fields : Int
email_values : Int
phone_values : Int
manual_review_required : Bool
} derive(Eq, Debug)
///|
fn contains_email(value : String) -> Bool {
value.contains("@") && value.contains(".")
}
///|
fn digit_count(value : String) -> Int {
let mut count = 0
for character in value {
if character >= '0' && character <= '9' {
count = count + 1
}
}
count
}
///|
fn contains_phone(value : String) -> Bool {
digit_count(value) >= 7
}
///|
fn field_values(field : @record.MarcField) -> Array[String] {
match field {
@record.MarcField::ControlField(value~, ..) => [value]
@record.MarcField::DataField(subfields~, ..) => {
let values : Array[String] = []
for subfield in subfields {
values.push(subfield.value)
}
values
}
}
}
///|
pub fn scan(records : Array[@record.MarcRecord]) -> PrivacyReport {
let mut local_fields = 0
let mut email_values = 0
let mut phone_values = 0
for record in records {
for field in record.fields() {
if field.tag() >= "900" && field.tag() <= "999" {
local_fields = local_fields + 1
}
for value in field_values(field) {
if contains_email(value) {
email_values = email_values + 1
}
if contains_phone(value) {
phone_values = phone_values + 1
}
}
}
}
{
records: records.length(),
local_fields,
email_values,
phone_values,
manual_review_required: local_fields > 0 ||
email_values > 0 ||
phone_values > 0,
}
}
///|
fn mask_email(value : String) -> String {
match value.find("@") {
None => value
Some(position) => "***" + value[position:].to_owned()
}
}
///|
fn redact_field(
field : @record.MarcField,
drop_9xx : Bool,
mask_email_values : Bool,
) -> @record.MarcField? {
if drop_9xx && field.tag() >= "900" && field.tag() <= "999" {
return None
}
match field {
@record.MarcField::ControlField(tag~, value~) =>
Some(
@record.MarcField::ControlField(
tag~,
value=if mask_email_values && contains_email(value) {
mask_email(value)
} else {
value
},
),
)
@record.MarcField::DataField(tag~, indicator1~, indicator2~, subfields~) => {
let updated : Array[@record.Subfield] = []
for subfield in subfields {
updated.push({
code: subfield.code,
value: if mask_email_values && contains_email(subfield.value) {
mask_email(subfield.value)
} else {
subfield.value
},
})
}
Some(
@record.MarcField::DataField(
tag~,
indicator1~,
indicator2~,
subfields=updated,
),
)
}
}
}
///|
pub fn redact(
records : Array[@record.MarcRecord],
drop_9xx? : Bool,
mask_email? : Bool,
) -> Array[@record.MarcRecord] {
let drop_9xx = match drop_9xx {
None => false
Some(value) => value
}
let mask_email_values = match mask_email {
None => false
Some(value) => value
}
let output : Array[@record.MarcRecord] = []
for record in records {
let fields : Array[@record.MarcField] = []
for field in record.fields() {
match redact_field(field, drop_9xx, mask_email_values) {
None => ()
Some(value) => fields.push(value)
}
}
output.push({ leader: record.leader(), fields })
}
output
}