-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #557 from GSA/feature/21-verify-gspc-course-requie…
…rments Feature/21 verify gspc course requierments
- Loading branch information
Showing
25 changed files
with
378 additions
and
61 deletions.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
alembic/versions/a5fbdcd0e719_add_gspc_completions_table.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
"""add gspc_completions table | ||
Revision ID: a5fbdcd0e719 | ||
Revises: 51b251b1ec2a | ||
Create Date: 2024-05-08 10:43:09.569708 | ||
""" | ||
from alembic import op | ||
import sqlalchemy as sa | ||
from sqlalchemy.dialects import postgresql | ||
|
||
|
||
# revision identifiers, used by Alembic. | ||
revision = 'a5fbdcd0e719' | ||
down_revision = '51b251b1ec2a' | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade() -> None: | ||
op.create_table( | ||
'gspc_completions', | ||
sa.Column('id', sa.Integer(), nullable=False), | ||
sa.Column('user_id', sa.Integer(), nullable=False), | ||
sa.Column('passed', sa.Boolean(), nullable=False), | ||
sa.Column('certification_expiration_date', sa.Date, nullable=False), | ||
sa.Column('submit_ts', sa.DateTime(), server_default=sa.text('now()'), nullable=False), | ||
sa.Column('responses', postgresql.JSONB(astext_type=sa.Text()), nullable=False), | ||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), | ||
sa.PrimaryKeyConstraint('id') | ||
) | ||
|
||
|
||
def downgrade() -> None: | ||
op.drop_table('gspc_completions') |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import USWDSAlert from './USWDSAlert.vue' | ||
import Loginless from './LoginlessFlow.vue'; | ||
import GspcQuestions from './GspcQuestions.vue'; | ||
import FileDownLoad from "./icons/FileDownload.vue" | ||
onErrorCaptured((err) => { | ||
setError(err) | ||
|
@@ -17,6 +18,11 @@ | |
required: false, | ||
default: false | ||
}, | ||
'certId': { | ||
type: Number, | ||
required: false, | ||
default: null | ||
}, | ||
'certFailed': { | ||
type: Boolean, | ||
required: false, | ||
|
@@ -32,6 +38,7 @@ | |
const user = useStore(profile) | ||
const base_url = import.meta.env.PUBLIC_API_BASE_URL | ||
const certPassed = ref(props.certPassed) | ||
const certId = ref(props.certId) | ||
const certFailed = ref(props.certFailed) | ||
const quizStarted = ref(false) | ||
const quizSubmitted = ref(false) | ||
|
@@ -65,10 +72,6 @@ | |
error.value = event | ||
} | ||
function downloadCert(){ | ||
//console.log('todo') | ||
} | ||
function startQuiz() { | ||
quizStarted.value = true | ||
} | ||
|
@@ -85,7 +88,7 @@ | |
'Content-Type': 'application/json', | ||
'Authorization': `Bearer ${user.value.jwt}` | ||
}, | ||
body: JSON.stringify( {'responses': user_answers, 'expiration_date': expirationDate}) | ||
body: JSON.stringify({'responses':{'responses': user_answers}, 'expiration_date': expirationDate}) | ||
}) | ||
} catch(e) { | ||
const err = new Error("There was a problem connecting with the server") | ||
|
@@ -104,6 +107,7 @@ | |
var result = await res.json() | ||
if(result.passed){ | ||
certPassed.value = true | ||
certId.value = result.cert_id | ||
} else{ | ||
certFailed.value = true | ||
} | ||
|
@@ -137,7 +141,7 @@ | |
page-id="gspc_registration" | ||
title="gspc_registration" | ||
:header="header" | ||
link-destination-text="the GSA SmartPay Program Certification (GSPCS)" | ||
link-destination-text="the GSA SmartPay Program Certification (GSPC)" | ||
:parameters="redirectExpirationDateString" | ||
@start-loading="startLoading" | ||
@error="setError" | ||
|
@@ -154,24 +158,35 @@ | |
<div v-if="certPassed"> | ||
<h2>Congratulations You Earned Your GSA SmartPay Program Certificate (GSPC)</h2> | ||
<p>You have met the requirements to earn a GSA SmartPay Program Certificate (GSPC). Your certificate has been emailed to you. Or, you may download your certificate below.</p> | ||
<button | ||
class="usa-button" | ||
@click="downloadCert" | ||
<form | ||
:action="`${base_url}/api/v1/certificate/gspc/${certId}`" | ||
method="post" | ||
> | ||
Download your certificate | ||
</button> | ||
<br><br> | ||
<a href="/">Return to the GSA SmartPay Training Home Page</a> | ||
<input | ||
type="hidden" | ||
name="jwtToken" | ||
:value="user.jwt" | ||
> | ||
<button | ||
class="usa-button" | ||
type="submit" | ||
> | ||
<FileDownLoad /> Download your certificate | ||
</button> | ||
<br><br> | ||
<a :href="base_url">Return to the GSA SmartPay Training Home Page</a> | ||
</form> | ||
</div> | ||
<div v-else-if="certFailed"> | ||
<h2>You Don't Meet the Requirements for GSA SmartPay Program Certification (GSPC)</h2> | ||
<p>Once you have met the coursework and experience requirement of six months of continuous, hands-on experience working with the GSA SmartPay program please return to the link in your email to reapply.</p> | ||
<p>If you have any questions ,please reference <a href="">Smart Bulletin No. 022</a> or contact the GSPC Program Manager at <a href="mailto:[email protected]">[email protected]</a>.</p> | ||
<a href="/">Return to the GSA SmartPay Training Home Page</a> | ||
<p>If you have any questions, please reference <a href="https://smartpay.gsa.gov/policies-and-audits/smart-bulletins/022">Smart Bulletin No. 022</a> or contact the GSPC Program Manager at <a href="mailto:[email protected]">[email protected]</a>.</p> | ||
<a :href="base_url">Return to the GSA SmartPay Training Home Page</a> | ||
</div> | ||
<div v-else> | ||
<GspcQuestions | ||
:questions="questions" | ||
class="desktop:grid-col-8" | ||
@submit-gspc-registration="submitGspcRegistration" | ||
@start-quiz="startQuiz" | ||
/> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ | |
<p> | ||
If you did not submit this request, you may be receiving this message in error. | ||
Please disregard this email. If you have any questions or need further assistance, | ||
email us at [email protected]. | ||
email us at <a href="mailto:$mailto">$mailto</a>. | ||
</p> | ||
<p>Thank you.</p> | ||
''') | ||
|
@@ -52,6 +52,8 @@ | |
# Todo move email function from quiz.py and turn this into a service so that it can be mocked | ||
def send_email(to_email: EmailStr, name: str, link: str, training_title: str) -> None: | ||
# Todo clean this up | ||
mailto = "[email protected]" | ||
|
||
if training_title and "certificate" in training_title.lower(): | ||
subject = "GSA SmartPay® training certificate(s)" | ||
email_subject = "Access your GSA SmartPay training certificate(s)" | ||
|
@@ -61,11 +63,12 @@ def send_email(to_email: EmailStr, name: str, link: str, training_title: str) -> | |
elif training_title and "gspc_registration" in training_title.lower(): | ||
subject = "GSA SmartPay® GSPC Registration form" | ||
email_subject = "Access to GSA SmartPay GSPC Registration" | ||
mailto = "[email protected]" | ||
else: | ||
subject = f"GSA SmartPay® {training_title} quiz" | ||
email_subject = f"Access GSA SmartPay {training_title} quiz" | ||
|
||
body = EMAIL_TEMPLATE.substitute({"name": name, "link": link, "subject": subject}) | ||
body = EMAIL_TEMPLATE.substitute({"name": name, "link": link, "subject": subject, "mailto": mailto}) | ||
message = EmailMessage() | ||
message.set_content(body, subtype="html") | ||
message["Subject"] = email_subject | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from typing import Any | ||
from datetime import datetime | ||
from training.models import Base | ||
from sqlalchemy.orm import Mapped, mapped_column | ||
from sqlalchemy import Column, Date, ForeignKey, func | ||
|
||
|
||
class GspcCompletion(Base): | ||
__tablename__ = "gspc_completions" | ||
|
||
id: Mapped[int] = mapped_column(primary_key=True) | ||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id")) | ||
passed: Mapped[bool] = mapped_column() | ||
certification_expiration_date = Column(Date(), nullable=False) | ||
submit_ts: Mapped[datetime] = mapped_column(server_default=func.now()) | ||
responses: Mapped[dict[str, Any]] = mapped_column() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from sqlalchemy.orm import Session | ||
from training import models, schemas | ||
from .base import BaseRepository | ||
|
||
|
||
class GspcCompletionRepository(BaseRepository[models.GspcCompletion]): | ||
|
||
def __init__(self, session: Session): | ||
super().__init__(session, models.GspcCompletion) | ||
|
||
def create(self, gspc_completion: schemas.GspcCompletion) -> models.GspcCompletion: | ||
return self.save(models.GspcCompletion( | ||
user_id=gspc_completion.user_id, | ||
passed=gspc_completion.passed, | ||
certification_expiration_date=gspc_completion.certification_expiration_date, | ||
responses=gspc_completion.responses | ||
)) |
Oops, something went wrong.