Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

Employee level materials #225

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE users DROP COLUMN materials;
12 changes: 12 additions & 0 deletions cio/migrations/2022-07-12-150519_add_materials_to_employees/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ALTER TABLE users ADD COLUMN materials VARCHAR NOT NULL DEFAULT '';

UPDATE users
SET materials = applicant.materials
FROM (
SELECT
email,
materials
FROM
applicants
) AS applicant
WHERE users.recovery_email = applicant.email;
40 changes: 35 additions & 5 deletions cio/src/configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ pub struct UserConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub public_ssh_keys: Vec<String>,

#[serde(default, skip_serializing_if = "String::is_empty")]
pub materials: String,

#[serde(default, rename = "type", skip_serializing_if = "String::is_empty")]
pub typev: String,

Expand Down Expand Up @@ -813,14 +816,20 @@ impl UserConfig {
self.work_address_formatted = self.work_address_formatted.replace('\n', "\\n");
}

// Looks up an applicant record based on the users recovery_email. There is a historical
// implicit assumption here that employees use the email that they applied with as their
// recovery_email
async fn applicant_record(&self, db: &Database) -> Result<Applicant> {
Ok(applicants::dsl::applicants
.filter(applicants::dsl::email.eq(self.recovery_email.to_string()))
.first_async::<Applicant>(db.pool())
.await?)
}

pub async fn populate_start_date(&mut self, db: &Database) {
// Only populate the start date, if we could not update it from Gusto.
if self.start_date == crate::utils::default_date() {
if let Ok(a) = applicants::dsl::applicants
.filter(applicants::dsl::email.eq(self.recovery_email.to_string()))
.first_async::<Applicant>(db.pool())
.await
{
if let Ok(a) = self.applicant_record(db).await {
// Get their start date.
if a.start_date.is_some() {
self.start_date = a.start_date.unwrap();
Expand All @@ -829,6 +838,25 @@ impl UserConfig {
}
}

// If the user does not yet have a materials url, attempt to look it up from our applicant
// data based on the recovery email. This is performed when a user joins the
// organization and their record is first populated. If these do not match, then materials
// urls will need to be manually assigned
pub async fn populate_materials(&mut self, db: &Database) {
if self.materials.is_empty() {
if let Ok(applicant) = self.applicant_record(db).await {
self.materials = applicant.materials;
} else {
// TODO: When user structs are fixed so they always carry ids, this should be
// updated to log the user id instead
log::info!(
"Unable to find matching applicant when attempting to assign materials to employee starting on {}",
self.start_date
);
}
}
}

pub fn populate_type(&mut self) {
// TODO: make this an enum.
self.typev = "full-time".to_string();
Expand Down Expand Up @@ -894,6 +922,8 @@ impl UserConfig {

self.populate_start_date(db).await;

self.populate_materials(db).await;

// Create the link to the manager.
if !self.manager.is_empty() {
self.link_to_manager = vec![self.manager.to_string()];
Expand Down
29 changes: 8 additions & 21 deletions cio/src/interviews.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,36 +336,23 @@ pub async fn compile_packets(db: &Database, company: &Company) -> Result<()> {
.create_folder(&drive_id, "", "interview_packets")
.await?;

// Iterate over each user we have in gsuite and download their materials
// locally.
// Iterate over each user we have in gsuite and download their materials locally.
// TODO: This function currently creates local copies of every employees materials prior to
// compiling interview packets. While this is efficient in terms of only requesting each
// materials document once, it is wasteful in that it downloads materials it does not need.
let employees = Users::get_from_db(db, company.id).await?;
for employee in employees {
if employee.is_system_account() {
continue;
}

// Get their application materials.
let mut materials_url = "".to_string();
if let Ok(a) = applicants::dsl::applicants
.filter(applicants::dsl::email.eq(employee.recovery_email.to_string()))
.first_async::<Applicant>(db.pool())
.await
{
materials_url = a.materials;
}

if materials_url.is_empty() {
if employee.username == "ben.leonard" {
// Add Ben's materials.
materials_url = "https://drive.google.com/open?id=1bOHalcpSyXwaxr4E-_2LeT06HGXQCW0n".to_string();
} else {
info!("could not find materials for email {}", employee.recovery_email);
continue;
}
if employee.materials.is_empty() {
info!("could not find materials for employee {}", employee.id);
continue;
}

// Let's download the contents of their materials locally.
if let Err(err) = download_materials_as_pdf(&drive_client, &materials_url, &employee.username).await {
if let Err(err) = download_materials_as_pdf(&drive_client, &employee.materials, &employee.username).await {
log::warn!(
"Failed to download materials for employee {} when constructing interview packets. err: {:?}",
employee.id,
Expand Down
1 change: 1 addition & 0 deletions cio/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,7 @@ table! {
start_date -> Date,
birthday -> Date,
public_ssh_keys -> Array<Text>,
materials -> Varchar,
typev -> Varchar,
google_anniversary_event_id -> Varchar,
email -> Varchar,
Expand Down