diff --git a/Cargo.lock b/Cargo.lock index 93a5549..50a500c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,23 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -739,6 +756,15 @@ dependencies = [ "either", ] +[[package]] +name = "bzip2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" +dependencies = [ + "libbz2-rs-sys", +] + [[package]] name = "camino" version = "1.2.2" @@ -789,6 +815,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "cmake" version = "0.1.57" @@ -895,6 +931,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b" +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "convert_case" version = "0.6.0" @@ -1173,6 +1215,12 @@ dependencies = [ "syn", ] +[[package]] +name = "deflate64" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" + [[package]] name = "der" version = "0.6.1" @@ -1359,6 +1407,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "miniz_oxide", + "zlib-rs", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2237,6 +2295,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "interpolator" version = "0.5.0" @@ -2683,6 +2750,12 @@ dependencies = [ "tachys", ] +[[package]] +name = "libbz2-rs-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" + [[package]] name = "libc" version = "0.2.182" @@ -2725,6 +2798,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lzma-rust2" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47bb1e988e6fb779cf720ad431242d3f03167c1b3f2b1aae7f1a94b2495b36ae" +dependencies = [ + "sha2", +] + [[package]] name = "macros" version = "0.1.0" @@ -2795,6 +2877,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "1.1.1" @@ -2958,6 +3050,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "pem" version = "3.0.6" @@ -3016,6 +3118,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "potential_utf" version = "0.1.4" @@ -3031,6 +3139,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppmd-rust" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -3621,6 +3735,7 @@ dependencies = [ "chrono", "console_error_panic_hook", "csv", + "futures", "icondata", "indexmap", "jsonwebtoken 10.3.0", @@ -3640,6 +3755,7 @@ dependencies = [ "traits", "uuid", "wasm-bindgen", + "zip", ] [[package]] @@ -3931,6 +4047,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "simple_asn1" version = "0.6.4" @@ -4177,6 +4299,7 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", + "js-sys", "num-conv", "powerfmt", "serde_core", @@ -4464,6 +4587,12 @@ dependencies = [ "syn", ] +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + [[package]] name = "typenum" version = "1.19.0" @@ -5311,8 +5440,81 @@ dependencies = [ "syn", ] +[[package]] +name = "zip" +version = "8.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcab981e19633ebcf0b001ddd37dd802996098bc1864f90b7c5d970ce76c1d59" +dependencies = [ + "aes", + "bzip2", + "constant_time_eq", + "crc32fast", + "deflate64", + "flate2", + "getrandom 0.4.1", + "hmac", + "indexmap", + "lzma-rust2", + "memchr", + "pbkdf2", + "ppmd-rust", + "sha1", + "time", + "typed-path", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 2492772..9102aac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ leptos_oidc = "0.9.0" base64 = "0.22" chrono = "0.4" leptos_animate = "0.1" - macros = { path = "./macros" } traits = { path = "./traits" } icondata = { version = "0.7.0", features = ["font-awesome"] } @@ -35,6 +34,8 @@ csv = "1.4.0" leptos-use = { version = "0.18.3", features = ["use_drop_zone"] } jsonwebtoken = { version = "10.3.0", features = ["aws_lc_rs"], optional = true } reqwest = { version = "0.13.2", features = ["json"] } +zip = { version = "8.5.1", optional = true } +futures = { version = "0.3.32", optional = true } [features] default = ["ssr"] @@ -52,6 +53,8 @@ ssr = [ "dep:aws-config", "dep:serde_dynamo", "dep:jsonwebtoken", + "dep:zip", + "dep:futures", "leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr", diff --git a/src/app.rs b/src/app.rs index 8cedd5e..fd98e09 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,10 +2,11 @@ use crate::components::ToastList; use crate::components::login::ProviderLoginContext; use crate::pages::{ AdminHomePage, AdminProviderPage, AdminScholarshipPage, AdminShell, AdminUtilsPage, - ApplicantsPageFallback, AuthCallbackPage, LoanerBorrowForm, LoanerFallback, LoanerReturnForm, - LoanerShell, ProviderContactPage, ProviderPortal, + ApplicantsPageFallback, ApplicantsStudentList, AuthCallbackPage, LoanerBorrowForm, + LoanerFallback, LoanerReturnForm, LoanerShell, ProviderContactPage, ProviderPortal, + ScholarshipInfoPage, }; -use crate::pages::{FormClosedPage, student}; +use crate::pages::{ApplicantsPageShell, student}; use leptos::prelude::*; use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context}; use leptos_oidc::AuthSignal; @@ -86,14 +87,17 @@ fn ProviderRoutes() -> impl MatchNestedRoutes + Clone { view! { - + + + + - - // - // - // - // + // + + + + } .into_inner() diff --git a/src/common/expandable_info.rs b/src/common/expandable_info.rs index a209606..304c73f 100644 --- a/src/common/expandable_info.rs +++ b/src/common/expandable_info.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; /// now, the table will simply create a single massive `Map` field that contains all the stored /// information in the `HashMap`. We'd prefer to be able to get single values if possible, /// especially for interoperability with other applications, should they be created. -#[derive(Debug, Clone, Serialize, Deserialize, Reactive)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Reactive)] pub struct ExpandableInfo { /// The main key member. Required and used to get/put the information in a database. pub subject: String, diff --git a/src/common/schema_node.rs b/src/common/schema_node.rs index 2e1f943..922b3de 100644 --- a/src/common/schema_node.rs +++ b/src/common/schema_node.rs @@ -1,13 +1,35 @@ -use std::collections::HashMap; -use indexmap::IndexMap; +use indexmap::IndexMap; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Default, Debug, Clone)] pub enum SchemaType { + /// Indicates a `ValueType::String` value. + #[default] String, + /// Indicates a `ValueType::Number` value. Number, - List, - Map + /// Indicates a `ValueType::List` containing only strings or numbers. + PrimitiveList, + /// Indicates a `ValueType::List` containing only maps. + MapList, + /// Indicates a `ValueType::Map`. + Map, +} + +#[derive(Serialize, Deserialize, Default, Debug, Clone)] +pub enum SchemaContainerStyle { + #[default] + Header, + Capsule, +} + +#[derive(Serialize, Deserialize, Default, Debug, Clone)] +pub enum SchemaHeaderStyle { + #[default] + None, + MainHeader, + SubsectionHeader, + Bold, } /// # Schema Node @@ -55,12 +77,16 @@ pub enum SchemaType { /// This schema does not currently support display of a single nested member, like a single map /// within a list. This means that you will have to display any listed or mapped information as a /// list. Consider this when designing the data. -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Default, Debug, Clone)] pub struct SchemaNode { + /// The display style of the data. Refer to [`SchemaContainerStyle`] for more information. + pub container_style: SchemaContainerStyle, /// The datatype of the data found using the `data_member` key. pub data_type: SchemaType, /// The header of this display. pub header: String, + /// The style of the header's display. + pub header_style: SchemaHeaderStyle, /// When used with a SchemaType::List, this determines the datatype and children for every entry /// in the list. Some examples include a list of maps, where we use the `item_template` to define /// the SchemaType::Map, and all its children. This is then mapped across all entries in the list, @@ -69,16 +95,28 @@ pub struct SchemaNode { /// When used with a SchemaType::Map, this determines what children from the map are displayed /// and how. It is ignored with all other SchemaType variants. pub children: IndexMap, + /// The primary key for iteration over maps. Used when there is a list of maps. + pub primary_key: Option, } impl SchemaNode { - pub fn new(data_type: SchemaType) -> Self { - SchemaNode { - data_type, - header: "".to_string(), - item_template: None, - children: IndexMap::new(), - } + /// Creates a new [`SchemaBuilder`]. + pub fn builder() -> SchemaBuilder { + SchemaBuilder::default() + } +} + +#[derive(Default, Debug, Clone)] +pub struct SchemaBuilder { + container_style: SchemaContainerStyle, + header: String, + header_style: SchemaHeaderStyle, +} + +impl SchemaBuilder { + pub fn container(mut self, style: SchemaContainerStyle) -> Self { + self.container_style = style; + self } pub fn header(mut self, header: impl Into) -> Self { @@ -86,13 +124,130 @@ impl SchemaNode { self } - pub fn child(mut self, data_member: impl Into, node: SchemaNode) -> Self { - self.children.insert(data_member.into(), node); + pub fn header_style(mut self, header_style: SchemaHeaderStyle) -> Self { + self.header_style = header_style; self } + pub fn primitive_list(self) -> SchemaPrimitiveListBuilder { + SchemaPrimitiveListBuilder::new(self) + } + + pub fn map_list(self) -> SchemaMapListBuilder { + SchemaMapListBuilder::new(self) + } + + pub fn map(self) -> SchemaMapBuilder { + SchemaMapBuilder::new(self) + } + + pub fn string(self) -> SchemaPrimitiveBuilder { + SchemaPrimitiveBuilder::new(self, SchemaType::String) + } + + pub fn number(self) -> SchemaPrimitiveBuilder { + SchemaPrimitiveBuilder::new(self, SchemaType::Number) + } + + fn into_node(self) -> SchemaNode { + SchemaNode { + container_style: self.container_style, + header: self.header, + header_style: self.header_style, + ..Default::default() + } + } +} + +#[derive(Default, Debug, Clone)] +pub struct SchemaPrimitiveListBuilder { + builder: SchemaBuilder, +} + +impl SchemaPrimitiveListBuilder { + fn new(builder: SchemaBuilder) -> Self { + Self { builder } + } +} + +#[derive(Default, Debug, Clone)] +pub struct SchemaMapListBuilder { + builder: SchemaBuilder, + item_template: Option>, + primary_key: String, +} + +impl SchemaMapListBuilder { + fn new(builder: SchemaBuilder) -> Self { + Self { + builder, + ..Default::default() + } + } + pub fn item_template(mut self, node: SchemaNode) -> Self { self.item_template = Some(Box::new(node)); self } + + pub fn primary_key(mut self, primary_key: impl Into) -> Self { + self.primary_key = primary_key.into(); + self + } + + pub fn build(self) -> SchemaNode { + SchemaNode { + data_type: SchemaType::MapList, + item_template: self.item_template, + primary_key: Some(self.primary_key), + ..self.builder.into_node() + } + } +} + +#[derive(Default, Debug, Clone)] +pub struct SchemaMapBuilder { + builder: SchemaBuilder, + children: IndexMap, +} + +impl SchemaMapBuilder { + fn new(builder: SchemaBuilder) -> Self { + Self { + builder, + ..Default::default() + } + } + + pub fn child(mut self, data_member: impl Into, node: SchemaNode) -> Self { + self.children.insert(data_member.into(), node); + self + } + + pub fn build(self) -> SchemaNode { + SchemaNode { + data_type: SchemaType::Map, + children: self.children, + ..self.builder.into_node() + } + } +} + +#[derive(Default, Debug, Clone)] +pub struct SchemaPrimitiveBuilder { + builder: SchemaBuilder, + data_type: SchemaType, +} + +impl SchemaPrimitiveBuilder { + fn new(builder: SchemaBuilder, data_type: SchemaType) -> Self { + Self { data_type, builder } + } + + pub fn build(self) -> SchemaNode { + SchemaNode { + data_type: self.data_type, + ..self.builder.into_node() + } + } } diff --git a/src/common/user.rs b/src/common/user.rs index 496037a..525572c 100644 --- a/src/common/user.rs +++ b/src/common/user.rs @@ -24,4 +24,7 @@ pub struct UserClaims { pub username: String, /// The intended use for the token. pub token_use: String, + /// The list of the names of user pool groups that have this user as a member. + #[serde(rename = "cognito:groups")] + pub groups: Vec, } diff --git a/src/components/action_button.rs b/src/components/action_button.rs index 7a91b2b..0cd2aeb 100644 --- a/src/components/action_button.rs +++ b/src/components/action_button.rs @@ -8,7 +8,7 @@ pub fn ActionButton( ) -> impl IntoView { view! {