Skip to content

Commit

Permalink
Update education options and add to schema (#1069)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhysyngsun authored Jun 12, 2024
1 parent 73127cf commit 59df868
Show file tree
Hide file tree
Showing 20 changed files with 1,216 additions and 74 deletions.
244 changes: 238 additions & 6 deletions frontends/api/src/generated/v0/api.ts

Large diffs are not rendered by default.

574 changes: 574 additions & 0 deletions frontends/api/src/generated/v1/api.ts

Large diffs are not rendered by default.

13 changes: 5 additions & 8 deletions frontends/mit-open/src/pages/OnboardingPage/CertificateStep.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import React from "react"

import { Grid, Container, ChoiceBox } from "ol-components"
import { CertificateDesiredEnum } from "api/v0"
import {
CertificateDesiredEnum,
CertificateDesiredEnumDescriptions,
} from "api/v0"

import { StepProps } from "./types"

import Prompt from "./Prompt"

const LABELS = {
[CertificateDesiredEnum.No]: "No",
[CertificateDesiredEnum.Yes]: "Yes",
[CertificateDesiredEnum.NotSureYet]: "Not sure yet",
}

function CertificateStep({ profile, onUpdate }: StepProps) {
const [certificateDesired, setCertificateDesired] = React.useState<
CertificateDesiredEnum | ""
Expand Down Expand Up @@ -49,7 +46,7 @@ function CertificateStep({ profile, onUpdate }: StepProps) {
<Grid item xs={4} key={index}>
<ChoiceBox
type="radio"
label={LABELS[value]}
label={CertificateDesiredEnumDescriptions[value]}
value={value}
onChange={handleToggle}
checked={checked}
Expand Down
13 changes: 2 additions & 11 deletions frontends/mit-open/src/pages/OnboardingPage/EducationLevelStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,10 @@ import {
Container,
FormControl,
} from "ol-components"
import { CurrentEducationEnum } from "api/v0"
import { CurrentEducationEnum, CurrentEducationEnumDescriptions } from "api/v0"

import { StepProps } from "./types"

const LABELS = {
[CurrentEducationEnum.Ged]: "GED",
[CurrentEducationEnum.Primary]: "Primary Education",
[CurrentEducationEnum.NoFormal]: "No Formal Education",
[CurrentEducationEnum.SecondaryOrHighSchool]:
"Secondary Education or High School",
[CurrentEducationEnum.VocationalQualification]: "Vocational Qualification",
}

function EducationLevelStep({ profile, onUpdate }: StepProps) {
const [educationLevel, setEducationLevel] = React.useState<
CurrentEducationEnum | ""
Expand Down Expand Up @@ -56,7 +47,7 @@ function EducationLevelStep({ profile, onUpdate }: StepProps) {
{Object.values(CurrentEducationEnum).map((value, index) => {
return (
<MenuItem value={value} key={index}>
{LABELS[value]}
{CurrentEducationEnumDescriptions[value]}
</MenuItem>
)
})}
Expand Down
10 changes: 2 additions & 8 deletions frontends/mit-open/src/pages/OnboardingPage/GoalsStep.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import React from "react"
import { Grid, Container, ChoiceBox } from "ol-components"
import { GoalsEnum } from "api/v0"
import { GoalsEnum, GoalsEnumDescriptions } from "api/v0"

import Prompt from "./Prompt"
import type { StepProps } from "./types"

const GoalsLabels: Record<string, string> = {
[GoalsEnum.CareerGrowth]: "Career Growth",
[GoalsEnum.SupplementalLearning]: "Supplemental Learning",
[GoalsEnum.JustToLearn]: "Just To Learn",
}

const GoalsDescriptions: Record<string, string> = {
[GoalsEnum.CareerGrowth]:
"Looking for career growth through new skills & certification",
Expand Down Expand Up @@ -56,7 +50,7 @@ function GoalsStep({ profile, onUpdate }: StepProps) {
return (
<Grid item xs={4} key={index}>
<ChoiceBox
label={GoalsLabels[value]}
label={GoalsEnumDescriptions[value]}
description={GoalsDescriptions[value]}
value={value}
type="checkbox"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import React from "react"
import { Grid, Container, ChoiceBox } from "ol-components"
import { LearningFormatEnum } from "api/v0"
import { LearningFormatEnum, LearningFormatEnumDescriptions } from "api/v0"

import Prompt from "./Prompt"
import { StepProps } from "./types"

const LABELS: Record<LearningFormatEnum, string> = {
[LearningFormatEnum.Online]: "Online",
[LearningFormatEnum.InPerson]: "In-Person",
[LearningFormatEnum.Hybrid]: "Hybrid",
}

function LearningFormatStep({ onUpdate, profile }: StepProps) {
const [learningFormat, setLearningFormat] = React.useState<
LearningFormatEnum | ""
Expand Down Expand Up @@ -47,7 +41,7 @@ function LearningFormatStep({ onUpdate, profile }: StepProps) {
<Grid item xs={4} key={index}>
<ChoiceBox
type="radio"
label={LABELS[value]}
label={LearningFormatEnumDescriptions[value]}
value={value}
onChange={handleToggle}
checked={checked}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const STEPS_DATA: Partial<Profile>[] = [
time_commitment: TimeCommitmentEnum._0To5Hours,
},
{
current_education: CurrentEducationEnum.SecondaryOrHighSchool,
current_education: CurrentEducationEnum.SecondaryHighSchool,
},
{
learning_format: LearningFormatEnum.Hybrid,
Expand Down
12 changes: 2 additions & 10 deletions frontends/mit-open/src/pages/OnboardingPage/TimeCommitmentStep.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import React from "react"
import { Grid, Container, ChoiceBox } from "ol-components"
import { TimeCommitmentEnum } from "api/v0"
import { TimeCommitmentEnum, TimeCommitmentEnumDescriptions } from "api/v0"

import Prompt from "./Prompt"
import { StepProps } from "./types"

const LABELS: Record<TimeCommitmentEnum, string> = {
[TimeCommitmentEnum._0To5Hours]: "< 5 hours/week",
[TimeCommitmentEnum._5To10Hours]: "5-10 hours/week",
[TimeCommitmentEnum._10To20Hours]: "10-20 hours/week",
[TimeCommitmentEnum._20To30Hours]: "20-30 hours/week",
[TimeCommitmentEnum._30PlusHours]: "30+ hours/week",
}

function TimeCommitmentStep({ onUpdate, profile }: StepProps) {
const [timeCommitment, setTimeCommitment] = React.useState<
TimeCommitmentEnum | ""
Expand Down Expand Up @@ -48,7 +40,7 @@ function TimeCommitmentStep({ onUpdate, profile }: StepProps) {
return (
<Grid item xs={4} key={index}>
<ChoiceBox
label={LABELS[value]}
label={TimeCommitmentEnumDescriptions[value]}
value={value}
onChange={handleToggle}
checked={checked}
Expand Down
5 changes: 5 additions & 0 deletions openapi/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""OpenAPI exception"""


class EnumDescriptionError(Exception):
"""Failed to compute a description"""
72 changes: 72 additions & 0 deletions openapi/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""Extensions for OpenAPI schema"""

import re

from openapi.exceptions import EnumDescriptionError

ENUM_DESCRIPTION_RE = re.compile(r"\w*\*\s`(?P<key>.*)`\s\-\s(?P<description>.*)")


def _iter_described_enums(schema, *, name=None, is_root=True):
"""
Create an iterator over all enums with descriptions
"""
if is_root:
for item_name, item in schema.items():
yield from _iter_described_enums(item, name=item_name, is_root=False)
elif isinstance(schema, list):
for item in schema:
yield from _iter_described_enums(item, name=name, is_root=is_root)
elif isinstance(schema, dict):
if "enum" in schema and "description" in schema:
yield name, schema

yield from _iter_described_enums(
schema.get("properties", []), name=name, is_root=is_root
)
yield from _iter_described_enums(
schema.get("oneOf", []), name=name, is_root=is_root
)
yield from _iter_described_enums(
schema.get("allOf", []), name=name, is_root=is_root
)
yield from _iter_described_enums(
schema.get("anyOf", []), name=name, is_root=is_root
)


def postprocess_x_enum_descriptions(result, generator, request, public): # noqa: ARG001
"""
Take the drf-spectacular generated descriptions and
puts it into the x-enum-descriptions property.
"""

# your modifications to the schema in parameter result
schemas = result.get("components", {}).get("schemas", {})

for name, schema in _iter_described_enums(schemas):
lines = schema["description"].splitlines()
descriptions_by_value = {}
for line in lines:
match = ENUM_DESCRIPTION_RE.match(line)
if match is None:
continue

key = match["key"]
description = match["description"]

# sometimes there are descriptions for empty values
# that aren't present in `"enums"`
if key in schema["enum"]:
descriptions_by_value[key] = description

if len(descriptions_by_value.values()) != len(schema["enum"]):
msg = f"Unable to find descriptions for all enum values: {name}"
raise EnumDescriptionError(msg)

if descriptions_by_value:
schema["x-enum-descriptions"] = [
descriptions_by_value[value] for value in schema["enum"]
]

return result
4 changes: 4 additions & 0 deletions openapi/settings_spectacular.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
"COMPONENT_SPLIT_REQUEST": True,
"AUTHENTICATION_WHITELIST": [],
"SCHEMA_PATH_PREFIX": "/api/v[0-9]",
"POSTPROCESSING_HOOKS": [
"drf_spectacular.hooks.postprocess_schema_enums",
"openapi.hooks.postprocess_x_enum_descriptions",
],
}
Loading

0 comments on commit 59df868

Please sign in to comment.