1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
//! Semester Edit services.

use crate::api::rcos::semesters::get_by_id::{semester::SemesterSemestersByPk, Semester};
use crate::api::rcos::semesters::mutations::edit::EditSemester;
use crate::error::TelescopeError;
use crate::templates::page::Page;
use crate::templates::Template;
use actix_web::http::header::LOCATION;
use actix_web::web::Form;
use actix_web::{web::Path, HttpRequest, HttpResponse};
use chrono::NaiveDate;

/// Make the form template for the semester edits.
fn make_edit_form(id: String, title: String, start: NaiveDate, end: NaiveDate) -> Template {
    let mut form = Template::new("admin/semesters/forms/edit");

    form.fields = json!({
        "id": id,
        "title": {"value": title},
        "start": {"value": start},
        "end": {"value": end}
    });

    return form;
}

/// The form submitted for semester edits.
#[derive(Serialize, Deserialize, Debug)]
pub struct SemesterEdits {
    title: String,
    start: NaiveDate,
    end: NaiveDate,
}

/// Service to display the semester edit form.
#[get("/semesters/edit/{semester_id}")]
pub async fn edit(
    req: HttpRequest,
    Path(semester_id): Path<String>,
) -> Result<Page, TelescopeError> {
    // First lookup the semester.
    let semester_data = Semester::get_by_id(semester_id).await?;

    // Make sure it exists.
    if semester_data.is_none() {
        return Err(TelescopeError::resource_not_found(
            "Semester Not Found",
            "Could not find a semester by this ID.",
        ));
    }

    // It does, we can unwrap it and deconstruct it.
    let SemesterSemestersByPk {
        semester_id,
        title,
        start_date,
        end_date,
    } = semester_data.unwrap();

    // Build and return the form with it.
    make_edit_form(semester_id, title, start_date, end_date)
        .in_page(&req, "Edit Semester")
        .await
}

/// Service to receive semester edits.
#[post("/semesters/edit/{semester_id}")]
pub async fn submit_edit(
    req: HttpRequest,
    Path(semester_id): Path<String>,
    Form(SemesterEdits { title, start, end }): Form<SemesterEdits>,
) -> Result<HttpResponse, TelescopeError> {
    // Assume the semester exist. Return an error later if the GraphQL mutation fails.
    // Start by validating the changes.

    // Validate title
    if title.trim().is_empty() {
        let mut return_form_template: Template = make_edit_form(semester_id, title, start, end);
        return_form_template.fields["title"]["issue"] = json!("Title cannot be empty.");
        let page = return_form_template.in_page(&req, "Edit Semester").await?;
        return Err(TelescopeError::InvalidForm(page));
    }

    // Validate dates.
    if start >= end {
        let mut return_form_template: Template = make_edit_form(semester_id, title, start, end);
        return_form_template.fields["start"]["issue"] =
            json!("Start date must be before end date.");
        let page = return_form_template.in_page(&req, "Edit Semester").await?;
        return Err(TelescopeError::InvalidForm(page));
    }

    // Data is valid. Execute changes.
    let edited = EditSemester::execute(semester_id, title, start, end).await?;

    // Check if there was a semester for this ID.
    if edited.is_none() {
        return Err(TelescopeError::resource_not_found(
            "Semester not found.",
            "Could not find a semester by this ID.",
        ));
    }

    // Edit success! Redirect user.
    Ok(HttpResponse::Found()
        .header(LOCATION, "/admin/semesters")
        .finish())
}