From 479bcaa0fdcff7b28934aa282def955afe086652 Mon Sep 17 00:00:00 2001 From: Dan Felder <30899941+felder101@users.noreply.github.com> Date: Fri, 26 Jul 2024 09:16:19 -0400 Subject: [PATCH] Production Release (#609) Includes sprint 34 and 34 issues Link Checker #369 Adding Drone Content to all Trainings #599 Adding FASCSA Order Check to all Trainings #598 Accessibility Bug: Buttons without Accessible Names on all Trainings Print Training Functionality #591 Admin Panel - Display Completed Quizzes/Certificates for Users #317 Research solutions for implementing audit fields #451 Update GSPC Image #601 Log Tracking Editing of User Records #443 --- .github/workflows/frontend-tests.yaml | 3 + .../291331bea272_user_audit_fields.py | 31 +++ data/seedsdata.yaml | 1 - training-front-end/linkinator-config.json | 17 ++ training-front-end/package-lock.json | 182 +++++++++++++++++- training-front-end/package.json | 7 +- training-front-end/public/images/gspc.svg | 1 + .../src/components/AdminEditReporting.vue | 118 +++++++++++- .../AdminViewUserCertificateTable.vue | 128 ++++++++++++ .../src/components/CertificateTable.vue | 2 +- .../__tests__/AdminEditReporting.spec.js | 15 +- .../AdminViewUserCertificateTable.spec.js | 131 +++++++++++++ .../content/training_fleet_pc/lesson03.mdx | 51 +++++ .../content/training_purchase/lesson05.mdx | 52 +++++ .../content/training_purchase_pc/lesson03.mdx | 52 +++++ .../src/content/training_travel/lesson03.mdx | 52 +++++ .../content/training_travel_pc/lesson03.mdx | 52 +++++ .../pages/training_fleet_pc/printable.astro | 6 +- .../pages/training_purchase/printable.astro | 5 +- .../training_purchase_pc/printable.astro | 5 +- .../src/pages/training_travel/printable.astro | 5 +- .../pages/training_travel_pc/printable.astro | 5 +- training/api/api_v1/certificates.py | 23 ++- training/api/api_v1/users.py | 7 +- training/api/deps.py | 4 +- training/models/user.py | 7 +- training/repositories/certificate.py | 2 +- training/repositories/user.py | 11 +- training/schemas/user.py | 22 +++ training/tests/conftest.py | 2 +- training/tests/test_api_certificates.py | 42 +++- training/tests/test_api_loginless_flow.py | 6 +- training/tests/test_certificate_repository.py | 4 +- training/tests/test_user_repository.py | 20 +- training/tests/testdata.yaml | 3 + 35 files changed, 1022 insertions(+), 52 deletions(-) create mode 100644 alembic/versions/291331bea272_user_audit_fields.py create mode 100644 training-front-end/linkinator-config.json create mode 100644 training-front-end/public/images/gspc.svg create mode 100644 training-front-end/src/components/AdminViewUserCertificateTable.vue create mode 100644 training-front-end/src/components/__tests__/AdminViewUserCertificateTable.spec.js diff --git a/.github/workflows/frontend-tests.yaml b/.github/workflows/frontend-tests.yaml index 7a087443..ab2523fb 100644 --- a/.github/workflows/frontend-tests.yaml +++ b/.github/workflows/frontend-tests.yaml @@ -34,3 +34,6 @@ jobs: - name: Run pa11y run: npm run pa11y-ci:gh + + - name: Run broken link checker + run: npm run link-checker:pipeline diff --git a/alembic/versions/291331bea272_user_audit_fields.py b/alembic/versions/291331bea272_user_audit_fields.py new file mode 100644 index 00000000..ebeb99b7 --- /dev/null +++ b/alembic/versions/291331bea272_user_audit_fields.py @@ -0,0 +1,31 @@ +"""user-audit-fields + +Revision ID: 291331bea272 +Revises: a5fbdcd0e719 +Create Date: 2024-07-19 09:06:27.754024 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '291331bea272' +down_revision = 'a5fbdcd0e719' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column('users', sa.Column('created_on', sa.DateTime, nullable=False, server_default=sa.func.current_timestamp())) + op.add_column('users', sa.Column('created_by', sa.String(), nullable=False, server_default='Migrated')) + op.alter_column('users', 'created_by', server_default=None) + op.add_column('users', sa.Column('modified_on', sa.DateTime, nullable=True)) + op.add_column('users', sa.Column('modified_by', sa.String(), nullable=True)) + + +def downgrade() -> None: + op.drop_column('users', 'created_on') + op.drop_column('users', 'created_by') + op.drop_column('users', 'modified_on') + op.drop_column('users', 'modified_by') diff --git a/data/seedsdata.yaml b/data/seedsdata.yaml index 08c5236f..dc93f6ca 100644 --- a/data/seedsdata.yaml +++ b/data/seedsdata.yaml @@ -966,7 +966,6 @@ AOPSs: email: stcdirector@sierratribal.org agency: Native American Tribal Governments bureau: Sierra Tribal Consortium, INC. - bureau: null reporting_agencies: - report_agency: Native American Tribal Governments report_bureau: Sierra Tribal Consortium, INC. diff --git a/training-front-end/linkinator-config.json b/training-front-end/linkinator-config.json new file mode 100644 index 00000000..009c9c22 --- /dev/null +++ b/training-front-end/linkinator-config.json @@ -0,0 +1,17 @@ +{ + "recurse": true, + "headers": { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0", + "Referer": "http://localhost:4321/" + }, + "skip": [ + "https://www.fpds.gov/", + "https://www.congress.gov/bill/101st-congress/house-bill/94", + "/printable/printable/$", + "http://www.energystar.gov/", + "http://www.biopreferred.gov/BioPreferred/", + "https://www.gsaadvantage.gov/advantage/ws/main/start_page\\?store=ADVANTAGE", + "https://www.congress.gov/bill/118th-congress/house-bill/2670" + ], + "verbosity": "debug" +} \ No newline at end of file diff --git a/training-front-end/package-lock.json b/training-front-end/package-lock.json index b2ed8cb5..249d62a1 100644 --- a/training-front-end/package-lock.json +++ b/training-front-end/package-lock.json @@ -39,6 +39,7 @@ "eslint-plugin-vue": "^9.11.0", "eslint-plugin-vuejs-accessibility": "^2.1.0", "jsdom": "^21.1.1", + "linkinator": "^6.0.5", "pa11y-ci": "^3.0.1", "start-server-and-test": "^2.0.3", "vitest": "^1.5.3" @@ -9069,8 +9070,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "peer": true + "dev": true }, "node_modules/escape-string-regexp": { "version": "1.0.5", @@ -10793,6 +10793,72 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.6.0.tgz", + "integrity": "sha512-bpOZVQV5gthH/jVCSuYuokRo2bTKOcuBiVWpjmTn6C5Agl5zclGfTljuGsQZxwwDBkli+YhZhP4TdlqTnhOezQ==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -14318,6 +14384,61 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/linkinator": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/linkinator/-/linkinator-6.0.5.tgz", + "integrity": "sha512-LRMHgO/29gk2WQzdj4cFcFHGKPhYPGBWVZOayATP6j3159ubonGJizObNRvgA5qDnrkqsRwJT7p4Tq97pC9GeA==", + "dev": true, + "dependencies": { + "chalk": "^5.0.0", + "escape-html": "^1.0.3", + "gaxios": "^6.0.0", + "glob": "^10.3.10", + "htmlparser2": "^9.0.0", + "marked": "^12.0.1", + "meow": "^13.0.0", + "mime": "^4.0.0", + "server-destroy": "^1.0.1", + "srcset": "^5.0.0" + }, + "bin": { + "linkinator": "build/src/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/linkinator/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/linkinator/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -14905,6 +15026,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", @@ -15671,6 +15804,18 @@ "timers-ext": "^0.1.7" } }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -16788,6 +16933,21 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.3.tgz", + "integrity": "sha512-KgUb15Oorc0NEKPbvfa0wRU+PItIEZmiv+pyAO2i0oTIVTJhlzMclU7w4RXWQrSOVH5ax/p/CkIO7KI4OyFJTQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -23679,6 +23839,12 @@ "node": ">= 0.8.0" } }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "dev": true + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -24326,6 +24492,18 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, + "node_modules/srcset": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz", + "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", diff --git a/training-front-end/package.json b/training-front-end/package.json index a8b15681..f1482371 100644 --- a/training-front-end/package.json +++ b/training-front-end/package.json @@ -15,7 +15,9 @@ "pa11y-ci": "npm run pa11y-ci:desktop && npm run pa11y-ci:mobile", "pa11y-ci:desktop": "pa11y-ci --config ./.pa11yci-desktop --sitemap http://localhost:8080/sitemap-0.xml --sitemap-find \"^https://training.smartpay.gsa.gov/\" --sitemap-replace \"http://localhost:8080/\"", "pa11y-ci:mobile": "pa11y-ci --config ./.pa11yci-mobile --sitemap http://localhost:8080/sitemap-0.xml --sitemap-find \"^https://training.smartpay.gsa.gov\" --sitemap-replace \"http://localhost:8080/\"", - "pa11y-ci:gh": "npx start-server-and-test serve http://localhost:8080 pa11y-ci" + "pa11y-ci:gh": "npx start-server-and-test serve http://localhost:8080 pa11y-ci", + "link-checker": "npx linkinator http://localhost:4321/ --config linkinator-config.json", + "link-checker:pipeline": "npx start-server-and-test serve http://localhost:8080 'npx linkinator http://localhost:8080 --config linkinator-config.json'" }, "dependencies": { "@astrojs/mdx": "^3.0.1", @@ -51,7 +53,8 @@ "jsdom": "^21.1.1", "pa11y-ci": "^3.0.1", "start-server-and-test": "^2.0.3", - "vitest": "^1.5.3" + "vitest": "^1.5.3", + "linkinator": "^6.0.5" }, "overrides": { "glob-parent": "^5.1.2" diff --git a/training-front-end/public/images/gspc.svg b/training-front-end/public/images/gspc.svg new file mode 100644 index 00000000..a13b2a4c --- /dev/null +++ b/training-front-end/public/images/gspc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/training-front-end/src/components/AdminEditReporting.vue b/training-front-end/src/components/AdminEditReporting.vue index 003b2c15..07a51f79 100644 --- a/training-front-end/src/components/AdminEditReporting.vue +++ b/training-front-end/src/components/AdminEditReporting.vue @@ -6,6 +6,7 @@ import USWDSComboBox from "./USWDSComboBox.vue"; import {agencyList, bureauList, selectedAgencyId, setSelectedAgencyId} from '../stores/agencies' import {useStore} from '@nanostores/vue' import AdminEditUserDetails from "./AdminEditUserDetails.vue"; +import AdminViewUserCertificateTable from "./AdminViewUserCertificateTable.vue" const props = defineProps({ user: { @@ -59,6 +60,41 @@ async function updateUser(successMessage) { function cancelUpdate() { editing.value = false; } + +function formatDate(dateStr) { + // Check if the string is null, undefined, or empty + if (!dateStr || dateStr.trim() === '') { + return 'N/A'; + } + + const date = new Date(dateStr); + + // Check if the date is valid + if (isNaN(date.getTime())) { + return 'N/A'; + } + + //doing it this way to reduce dependancies + const monthNames = [ + 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December' + ]; + + const month = monthNames[date.getMonth()]; + const day = date.getDate(); + const year = date.getFullYear(); + + return `${month} ${day}, ${year}`; +} + + function formatString(str) { + // Check if the string is null, undefined, or empty + if (!str || str.trim() === '') { + return 'N/A'; + } + + return str; +} \ No newline at end of file diff --git a/training-front-end/src/components/AdminViewUserCertificateTable.vue b/training-front-end/src/components/AdminViewUserCertificateTable.vue new file mode 100644 index 00000000..30a44444 --- /dev/null +++ b/training-front-end/src/components/AdminViewUserCertificateTable.vue @@ -0,0 +1,128 @@ + + + diff --git a/training-front-end/src/components/CertificateTable.vue b/training-front-end/src/components/CertificateTable.vue index fe994029..a9d8b49c 100644 --- a/training-front-end/src/components/CertificateTable.vue +++ b/training-front-end/src/components/CertificateTable.vue @@ -15,7 +15,7 @@ 'Purchase Training for Card/Account Holders and Approving Officials': 'smartpay-red-purchase-plain.svg', 'Purchase Training For Program Coordinators': 'smartpay-red-purchase-plain.svg', 'Fleet Training For Program Coordinators': 'smartpay-green-fleet-plain.svg', - 'GSA SmartPay Program Certification (GSPC)': 'smartpay-green-fleet-plain.svg' + 'GSA SmartPay Program Certification (GSPC)': 'gspc.svg' } const certificates = ref([]) diff --git a/training-front-end/src/components/__tests__/AdminEditReporting.spec.js b/training-front-end/src/components/__tests__/AdminEditReporting.spec.js index 0679c26a..71062212 100644 --- a/training-front-end/src/components/__tests__/AdminEditReporting.spec.js +++ b/training-front-end/src/components/__tests__/AdminEditReporting.spec.js @@ -94,8 +94,8 @@ describe('AdminAgencySelect', async () => { }) it("adds/removes agency when user marks check boxes", async () => { - const props = {user: users[0]} - const wrapper = mount(AdminEditReporting, {props}) + const props = { user: users[0] } + const wrapper = mount(AdminEditReporting, { props }) const agencySelect = wrapper.find('select') await agencySelect.setValue(20) @@ -103,17 +103,18 @@ describe('AdminAgencySelect', async () => { const checkbox = wrapper.find('input[type="checkbox"]') await checkbox.setChecked() - let table_rows = wrapper.findAll('tr') + let table_rows = wrapper.findAll('#user-reporting-access-table tr') expect(table_rows.length).toBe(4) expect(table_rows[3].text()).toContain("Enfield Tennis Academy") await checkbox.setChecked(false) - table_rows = wrapper.findAll('tr') + table_rows = wrapper.findAll('#user-reporting-access-table tr') expect(table_rows.length).toBe(3) }) + it("adds agency without bureau when user marks check boxes", async () => { - const props = {user: users[0]} - const wrapper = mount(AdminEditReporting, {props}) + const props = { user: users[0] } + const wrapper = mount(AdminEditReporting, { props }) const agencySelect = wrapper.find('select') await agencySelect.setValue(10) @@ -121,7 +122,7 @@ describe('AdminAgencySelect', async () => { const checkbox = wrapper.find('input[type="checkbox"]') await checkbox.setChecked() - let table_rows = wrapper.findAll('tr') + let table_rows = wrapper.findAll('#user-reporting-access-table tr') expect(table_rows.length).toBe(4) expect(table_rows[3].text()).toContain("Ennet House") }) diff --git a/training-front-end/src/components/__tests__/AdminViewUserCertificateTable.spec.js b/training-front-end/src/components/__tests__/AdminViewUserCertificateTable.spec.js new file mode 100644 index 00000000..067554e8 --- /dev/null +++ b/training-front-end/src/components/__tests__/AdminViewUserCertificateTable.spec.js @@ -0,0 +1,131 @@ +import { describe, it, expect, afterEach, vi} from 'vitest' +import { mount, flushPromises } from '@vue/test-utils' +import AdminViewUserCertificateTable from '../AdminViewUserCertificateTable.vue' + +const API_RESPONSE = [ + { + "id": 2, + "user_id": 1, + "user_name": "Becky Sharp", + "cert_title": "Travel Training for Card/Account Holders and Approving Officials", + "completion_date": "2023-04-17T15:02:02.814004", + "certificate_type": 1 + }, + { + "id": 68, + "user_id": 1, + "user_name": "Becky Sharp", + "cert_title": "Travel Training for Agency/Organization Program Coordinators", + "completion_date": "2023-04-25T18:03:45.134752", + "certificate_type": 1 + }, + { + "id": 99, + "user_id": 1, + "user_name": "Becky Sharp", + "cert_title": "GSPC", + "completion_date": "2023-07-25T18:03:45.134752", + "certificate_type": 2 + } +] + +const user = { + "id": 0, + } + +describe('CertificateTable', async () => { + afterEach(() => { + vi.restoreAllMocks() + }) + + it('shows training names in table', async () => { + vi.spyOn(global, 'fetch').mockImplementation(() => { + return Promise.resolve({ok: true, status:200, json: () => Promise.resolve(API_RESPONSE) }) + }) + const wrapper = await mount(AdminViewUserCertificateTable, { + props: { user } + }) + await flushPromises() + const rows = wrapper.findAll('tr') + expect(rows.length).toBe(API_RESPONSE.length + 1) + + const rowOne = rows[1].findAll('td') + API_RESPONSE[0].cert_title + expect(rowOne[0].text()).toBe(API_RESPONSE[0].cert_title) + + const rowTwo = rows[2].findAll('td') + expect(rowTwo[0].text()).toBe(API_RESPONSE[1].cert_title) + + const rowThree = rows[3].findAll('td') + expect(rowThree[0].text()).toBe(API_RESPONSE[2].cert_title) + }) + + it('displays formatted dates', async () => { + vi.spyOn(global, 'fetch').mockImplementation(() => { + return Promise.resolve({ok: true, status:200, json: () => Promise.resolve(API_RESPONSE) }) + }) + const wrapper = await mount(AdminViewUserCertificateTable, { + props: { user } + }) + await flushPromises() + const rows = wrapper.findAll('tr') + + const rowOne = rows[1].findAll('td') + expect(rowOne[1].text()).toBe('April 17, 2023') + + const rowTwo = rows[2].findAll('td') + expect(rowTwo[1].text()).toBe('April 25, 2023') + }) + + it('displays formatted times', async () => { + vi.spyOn(global, 'fetch').mockImplementation(() => { + return Promise.resolve({ok: true, status:200, json: () => Promise.resolve(API_RESPONSE) }) + }) + const wrapper = await mount(AdminViewUserCertificateTable, { + props: { user } + }) + await flushPromises() + const rows = wrapper.findAll('tr') + + const rowOne = rows[1].findAll('td') + expect(rowOne[2].text()).toBe('3:02:02 PM') + + const rowTwo = rows[2].findAll('td') + expect(rowTwo[2].text()).toBe('6:03:45 PM') + }) + + it('has links to certificate with cert type and id', async () => { + vi.spyOn(global, 'fetch').mockImplementation(() => { + return Promise.resolve({ok: true, status:200, json: () => Promise.resolve(API_RESPONSE) }) + }) + const wrapper = await mount(AdminViewUserCertificateTable, { + props: { user } + }) + await flushPromises() + const rows = wrapper.findAll('tr') + + const anchorOne = rows[1].find('form') + expect(anchorOne.attributes('action')).toBe("http://localhost:8000/api/v1/certificate/1/2") + + const anchorTwo = rows[2].find('form') + expect(anchorTwo.attributes('action')).toBe("http://localhost:8000/api/v1/certificate/1/68") + + const anchorThree = rows[3].find('form') + expect(anchorThree.attributes('action')).toBe("http://localhost:8000/api/v1/certificate/2/99") + }) + + it('show correct message when the user has not taken a quiz', async () => { + vi.spyOn(global, 'fetch').mockImplementation(() => { + return Promise.resolve({ok: true, status:200, json: () => Promise.resolve([]) }) + }) + const wrapper = await mount(AdminViewUserCertificateTable, { + props: { user } + }) + await flushPromises() + + const table = wrapper.find('table') + expect(table.exists()).toBe(false) + + expect(wrapper.text()).toContain('User has not earned any certificates yet.') + }) +}) \ No newline at end of file diff --git a/training-front-end/src/content/training_fleet_pc/lesson03.mdx b/training-front-end/src/content/training_fleet_pc/lesson03.mdx index 78757cc6..1f235f12 100644 --- a/training-front-end/src/content/training_fleet_pc/lesson03.mdx +++ b/training-front-end/src/content/training_fleet_pc/lesson03.mdx @@ -85,3 +85,54 @@ Strategic payment solutions offered under the [GSA SmartPay 3 Master Contract](h ## What is Section 889 and how does it apply to purchases? Section 889 of the John S. McCain National Defense Authorization Act (NDAA) for Fiscal Year 2019 ([P.L. 115-232 [PDF, 789 pages]](https://www.congress.gov/115/plaws/publ232/PLAW-115publ232.pdf)) and the [Federal Acquisition Regulation (FAR) Case 2018-017](https://www.federalregister.gov/documents/2019/08/13/2019-17201/federal-acquisition-regulation-prohibition-on-contracting-for-certain-telecommunications-and-video) prohibit the purchase of covered telecommunications equipment and services from merchants who sell products containing spyware. These devices could pose a threat to U.S. security by spying on or disrupting communications within the U.S. Therefore, purchase card/account holders should follow their agency’s policy regarding Section 889 compliance. +### FASCSA Order Check +Before making any purchase, buyers should review Federal Acquisition Supply Chain Security Act (FASCSA) orders. + +The federal government issued an [interim rule](https://www.federalregister.gov/documents/2023/10/05/2023-21320/federal-acquisition-regulation-implementation-of-federal-acquisition-supply-chain-security-act) that amends the Federal Acquisition Regulation (FAR) to implement supply chain risk information sharing and FASCSA orders. This rule became effective on December 4, 2023. + +#### Accessing FASCSA Orders +[The System for Award Management (SAM)](https://sam.gov/) is an official website of the U.S. Government that helps users navigate the federal award lifecycle. + +The site stores FASCSA order data entered by the Department of Homeland Security (DHS), the Department of Defense (DoD), and the Director of National Intelligence (DNI). + +Before making any purchase, including GSA SmartPay Purchase card/account transactions, agency officials should go to [SAM.gov](https://sam.gov/) and select the “View FASCSA Orders” button to download and review a complete list of the FASCSA orders. + +Buyers should: + +- Be sure to follow their agency rules and procedures for compliance with applicable FASCSA orders to determine whether the purchase should be made. +- Keep in mind that the FASCSA order review should take place for all purchases at any dollar threshold. +- Note that until DHS, DoD, or DNI create the first FASCSA order in [SAM.gov](https://sam.gov/), the downloaded file will be empty. + +### American Security Drone Act Of 2023 +On December 22, 2023, the President signed the [National Defense Authorization Act for Fiscal Year 2024 (NDAA)](https://www.congress.gov/bill/118th-congress/house-bill/2670). + +As part of the NDAA, Sections 1821 and 1826 contain prohibitions on using the GSA SmartPay purchase card to buy any covered unmanned aircraft systems from covered foreign entities. + +**Section 1821** - THE AMERICAN SECURITY DRONE ACT OF 2023
+**Section 1822** - Defines covered foreign entities and covered unmanned aircraft systems. + + +**Section 1826** - PROHIBITION ON USE OF GOVERNMENT-ISSUED PURCHASE CARDS TO PURCHASE COVERED UNMANNED AIRCRAFT SYSTEMS FROM COVERED FOREIGN ENTITIES +- Effective immediately, Government-issued Purchase Cards may not be used to procure any covered unmanned aircraft system from a covered foreign entity. + +#### Cleared Drone Vendors +- A cleared list of drone vendors is available from the Defense Innovation Unit. +- https://www.diu.mil/blue-uas-cleared-list diff --git a/training-front-end/src/content/training_purchase/lesson05.mdx b/training-front-end/src/content/training_purchase/lesson05.mdx index 576fad89..a0dbe26b 100644 --- a/training-front-end/src/content/training_purchase/lesson05.mdx +++ b/training-front-end/src/content/training_purchase/lesson05.mdx @@ -86,6 +86,58 @@ POS is the point where a transaction is finalized or the moment where a customer Section 889 of the John S. McCain National Defense Authorization Act (NDAA) for Fiscal Year 2019 ([P.L. 115-232 [PDF, 789 pages]](https://www.congress.gov/115/plaws/publ232/PLAW-115publ232.pdf)) and the[ Federal Acquisition Regulation (FAR) Case 2018-017](https://www.federalregister.gov/documents/2019/08/13/2019-17201/federal-acquisition-regulation-prohibition-on-contracting-for-certain-telecommunications-and-video) prohibit the purchase of covered telecommunications equipment and services from vendors who sell products containing spyware. These devices could pose a threat to U.S. security by spying on or disrupting communications within the U.S. Therefore, purchase card/account holders should follow their agency’s policy regarding Section 889 compliance. +### FASCSA Order Check +Before making any purchase, buyers should review Federal Acquisition Supply Chain Security Act (FASCSA) orders. + +The federal government issued an [interim rule](https://www.federalregister.gov/documents/2023/10/05/2023-21320/federal-acquisition-regulation-implementation-of-federal-acquisition-supply-chain-security-act) that amends the Federal Acquisition Regulation (FAR) to implement supply chain risk information sharing and FASCSA orders. This rule became effective on December 4, 2023. + +#### Accessing FASCSA Orders +[The System for Award Management (SAM)](https://sam.gov/) is an official website of the U.S. Government that helps users navigate the federal award lifecycle. + +The site stores FASCSA order data entered by the Department of Homeland Security (DHS), the Department of Defense (DoD), and the Director of National Intelligence (DNI). + +Before making any purchase, including GSA SmartPay Purchase card/account transactions, agency officials should go to [SAM.gov](https://sam.gov/) and select the “View FASCSA Orders” button to download and review a complete list of the FASCSA orders. + +Buyers should: + +- Be sure to follow their agency rules and procedures for compliance with applicable FASCSA orders to determine whether the purchase should be made. +- Keep in mind that the FASCSA order review should take place for all purchases at any dollar threshold. +- Note that until DHS, DoD, or DNI create the first FASCSA order in [SAM.gov](https://sam.gov/), the downloaded file will be empty. + +### American Security Drone Act Of 2023 +On December 22, 2023, the President signed the [National Defense Authorization Act for Fiscal Year 2024 (NDAA)](https://www.congress.gov/bill/118th-congress/house-bill/2670). + +As part of the NDAA, Sections 1821 and 1826 contain prohibitions on using the GSA SmartPay purchase card to buy any covered unmanned aircraft systems from covered foreign entities. + +**Section 1821** - THE AMERICAN SECURITY DRONE ACT OF 2023
+**Section 1822** - Defines covered foreign entities and covered unmanned aircraft systems. + + +**Section 1826** - PROHIBITION ON USE OF GOVERNMENT-ISSUED PURCHASE CARDS TO PURCHASE COVERED UNMANNED AIRCRAFT SYSTEMS FROM COVERED FOREIGN ENTITIES +- Effective immediately, Government-issued Purchase Cards may not be used to procure any covered unmanned aircraft system from a covered foreign entity. + +#### Cleared Drone Vendors +- A cleared list of drone vendors is available from the Defense Innovation Unit. +- https://www.diu.mil/blue-uas-cleared-list + ## What are convenience checks? Some agencies allow for the use of convenience checks. diff --git a/training-front-end/src/content/training_purchase_pc/lesson03.mdx b/training-front-end/src/content/training_purchase_pc/lesson03.mdx index dcba97a9..447a1f0e 100644 --- a/training-front-end/src/content/training_purchase_pc/lesson03.mdx +++ b/training-front-end/src/content/training_purchase_pc/lesson03.mdx @@ -78,6 +78,58 @@ Strategic payment solutions offered under the [GSA SmartPay 3 Master Contract](h ## What is Section 889 and how does it apply to purchases? Section 889 of the John S. McCain National Defense Authorization Act (NDAA) for Fiscal Year 2019 ([P.L. 115-232 [PDF, 789 pages]](https://www.congress.gov/115/plaws/publ232/PLAW-115publ232.pdf)) and the [Federal Acquisition Regulation (FAR) Case 2018-017](https://www.federalregister.gov/documents/2019/08/13/2019-17201/federal-acquisition-regulation-prohibition-on-contracting-for-certain-telecommunications-and-video) prohibit the purchase of covered telecommunications equipment and services from merchants who sell products containing spyware. These devices could pose a threat to U.S. security by spying on or disrupting communications within the U.S. Therefore, purchase card/account holders should follow their agency’s policy regarding Section 889 compliance. +### FASCSA Order Check +Before making any purchase, buyers should review Federal Acquisition Supply Chain Security Act (FASCSA) orders. + +The federal government issued an [interim rule](https://www.federalregister.gov/documents/2023/10/05/2023-21320/federal-acquisition-regulation-implementation-of-federal-acquisition-supply-chain-security-act) that amends the Federal Acquisition Regulation (FAR) to implement supply chain risk information sharing and FASCSA orders. This rule became effective on December 4, 2023. + +#### Accessing FASCSA Orders +[The System for Award Management (SAM)](https://sam.gov/) is an official website of the U.S. Government that helps users navigate the federal award lifecycle. + +The site stores FASCSA order data entered by the Department of Homeland Security (DHS), the Department of Defense (DoD), and the Director of National Intelligence (DNI). + +Before making any purchase, including GSA SmartPay Purchase card/account transactions, agency officials should go to [SAM.gov](https://sam.gov/) and select the “View FASCSA Orders” button to download and review a complete list of the FASCSA orders. + +Buyers should: + +- Be sure to follow their agency rules and procedures for compliance with applicable FASCSA orders to determine whether the purchase should be made. +- Keep in mind that the FASCSA order review should take place for all purchases at any dollar threshold. +- Note that until DHS, DoD, or DNI create the first FASCSA order in [SAM.gov](https://sam.gov/), the downloaded file will be empty. + +### American Security Drone Act Of 2023 +On December 22, 2023, the President signed the [National Defense Authorization Act for Fiscal Year 2024 (NDAA)](https://www.congress.gov/bill/118th-congress/house-bill/2670). + +As part of the NDAA, Sections 1821 and 1826 contain prohibitions on using the GSA SmartPay purchase card to buy any covered unmanned aircraft systems from covered foreign entities. + +**Section 1821** - THE AMERICAN SECURITY DRONE ACT OF 2023
+**Section 1822** - Defines covered foreign entities and covered unmanned aircraft systems. + + +**Section 1826** - PROHIBITION ON USE OF GOVERNMENT-ISSUED PURCHASE CARDS TO PURCHASE COVERED UNMANNED AIRCRAFT SYSTEMS FROM COVERED FOREIGN ENTITIES +- Effective immediately, Government-issued Purchase Cards may not be used to procure any covered unmanned aircraft system from a covered foreign entity. + +#### Cleared Drone Vendors +- A cleared list of drone vendors is available from the Defense Innovation Unit. +- https://www.diu.mil/blue-uas-cleared-list + ## What are convenience checks? Some agencies allow for the use of convenience checks. diff --git a/training-front-end/src/content/training_travel/lesson03.mdx b/training-front-end/src/content/training_travel/lesson03.mdx index 3939b7be..c5fa759d 100644 --- a/training-front-end/src/content/training_travel/lesson03.mdx +++ b/training-front-end/src/content/training_travel/lesson03.mdx @@ -46,3 +46,55 @@ The GSA SmartPay Travel card/account may be used for authorized official travel ## What is Section 889 and how does it apply to purchases? Section 889 of the John S. McCain National Defense Authorization Act (NDAA) for Fiscal Year 2019 ([P.L. 115-232 [PDF, 789 pages]](https://www.congress.gov/115/plaws/publ232/PLAW-115publ232.pdf)) and the [Federal Acquisition Regulation (FAR) Case 2018-017](https://www.federalregister.gov/documents/2019/08/13/2019-17201/federal-acquisition-regulation-prohibition-on-contracting-for-certain-telecommunications-and-video) prohibit the purchase of covered telecommunications equipment and services from merchants who sell products containing spyware. These devices could pose a threat to U.S. security by spying on or disrupting communications within the U.S. Therefore, GSA SmartPay card/account holders should follow their agency’s policy regarding Section 889 compliance. + +### FASCSA Order Check +Before making any purchase, buyers should review Federal Acquisition Supply Chain Security Act (FASCSA) orders. + +The federal government issued an [interim rule](https://www.federalregister.gov/documents/2023/10/05/2023-21320/federal-acquisition-regulation-implementation-of-federal-acquisition-supply-chain-security-act) that amends the Federal Acquisition Regulation (FAR) to implement supply chain risk information sharing and FASCSA orders. This rule became effective on December 4, 2023. + +#### Accessing FASCSA Orders +[The System for Award Management (SAM)](https://sam.gov/) is an official website of the U.S. Government that helps users navigate the federal award lifecycle. + +The site stores FASCSA order data entered by the Department of Homeland Security (DHS), the Department of Defense (DoD), and the Director of National Intelligence (DNI). + +Before making any purchase, including GSA SmartPay Purchase card/account transactions, agency officials should go to [SAM.gov](https://sam.gov/) and select the “View FASCSA Orders” button to download and review a complete list of the FASCSA orders. + +Buyers should: + +- Be sure to follow their agency rules and procedures for compliance with applicable FASCSA orders to determine whether the purchase should be made. +- Keep in mind that the FASCSA order review should take place for all purchases at any dollar threshold. +- Note that until DHS, DoD, or DNI create the first FASCSA order in [SAM.gov](https://sam.gov/), the downloaded file will be empty. + +### American Security Drone Act Of 2023 +On December 22, 2023, the President signed the [National Defense Authorization Act for Fiscal Year 2024 (NDAA)](https://www.congress.gov/bill/118th-congress/house-bill/2670). + +As part of the NDAA, Sections 1821 and 1826 contain prohibitions on using the GSA SmartPay purchase card to buy any covered unmanned aircraft systems from covered foreign entities. + +**Section 1821** - THE AMERICAN SECURITY DRONE ACT OF 2023
+**Section 1822** - Defines covered foreign entities and covered unmanned aircraft systems. + + +**Section 1826** - PROHIBITION ON USE OF GOVERNMENT-ISSUED PURCHASE CARDS TO PURCHASE COVERED UNMANNED AIRCRAFT SYSTEMS FROM COVERED FOREIGN ENTITIES +- Effective immediately, Government-issued Purchase Cards may not be used to procure any covered unmanned aircraft system from a covered foreign entity. + +#### Cleared Drone Vendors +- A cleared list of drone vendors is available from the Defense Innovation Unit. +- https://www.diu.mil/blue-uas-cleared-list \ No newline at end of file diff --git a/training-front-end/src/content/training_travel_pc/lesson03.mdx b/training-front-end/src/content/training_travel_pc/lesson03.mdx index 9d09956f..513f63c7 100644 --- a/training-front-end/src/content/training_travel_pc/lesson03.mdx +++ b/training-front-end/src/content/training_travel_pc/lesson03.mdx @@ -107,3 +107,55 @@ The GSA SmartPay Travel card/account may be used for authorized official travel ## What is Section 889 and how does it apply to purchases? Section 889 of the John S. McCain National Defense Authorization Act (NDAA) for Fiscal Year 2019 ([P.L. 115-232 [PDF, 789 pages]](https://www.congress.gov/115/plaws/publ232/PLAW-115publ232.pdf)) and the [Federal Acquisition Regulation (FAR) Case 2018-017](https://www.federalregister.gov/documents/2019/08/13/2019-17201/federal-acquisition-regulation-prohibition-on-contracting-for-certain-telecommunications-and-video) prohibit the purchase of covered telecommunications equipment and services from merchants who sell products containing spyware. These devices could pose a threat to U.S. security by spying on or disrupting communications within the U.S. Therefore, GSA SmartPay card/account holders should follow their agency’s policy regarding Section 889 compliance. + +### FASCSA Order Check +Before making any purchase, buyers should review Federal Acquisition Supply Chain Security Act (FASCSA) orders. + +The federal government issued an [interim rule](https://www.federalregister.gov/documents/2023/10/05/2023-21320/federal-acquisition-regulation-implementation-of-federal-acquisition-supply-chain-security-act) that amends the Federal Acquisition Regulation (FAR) to implement supply chain risk information sharing and FASCSA orders. This rule became effective on December 4, 2023. + +#### Accessing FASCSA Orders +[The System for Award Management (SAM)](https://sam.gov/) is an official website of the U.S. Government that helps users navigate the federal award lifecycle. + +The site stores FASCSA order data entered by the Department of Homeland Security (DHS), the Department of Defense (DoD), and the Director of National Intelligence (DNI). + +Before making any purchase, including GSA SmartPay Purchase card/account transactions, agency officials should go to [SAM.gov](https://sam.gov/) and select the “View FASCSA Orders” button to download and review a complete list of the FASCSA orders. + +Buyers should: + +- Be sure to follow their agency rules and procedures for compliance with applicable FASCSA orders to determine whether the purchase should be made. +- Keep in mind that the FASCSA order review should take place for all purchases at any dollar threshold. +- Note that until DHS, DoD, or DNI create the first FASCSA order in [SAM.gov](https://sam.gov/), the downloaded file will be empty. + +### American Security Drone Act Of 2023 +On December 22, 2023, the President signed the [National Defense Authorization Act for Fiscal Year 2024 (NDAA)](https://www.congress.gov/bill/118th-congress/house-bill/2670). + +As part of the NDAA, Sections 1821 and 1826 contain prohibitions on using the GSA SmartPay purchase card to buy any covered unmanned aircraft systems from covered foreign entities. + +**Section 1821** - THE AMERICAN SECURITY DRONE ACT OF 2023
+**Section 1822** - Defines covered foreign entities and covered unmanned aircraft systems. + + +**Section 1826** - PROHIBITION ON USE OF GOVERNMENT-ISSUED PURCHASE CARDS TO PURCHASE COVERED UNMANNED AIRCRAFT SYSTEMS FROM COVERED FOREIGN ENTITIES +- Effective immediately, Government-issued Purchase Cards may not be used to procure any covered unmanned aircraft system from a covered foreign entity. + +#### Cleared Drone Vendors +- A cleared list of drone vendors is available from the Defense Innovation Unit. +- https://www.diu.mil/blue-uas-cleared-list diff --git a/training-front-end/src/pages/training_fleet_pc/printable.astro b/training-front-end/src/pages/training_fleet_pc/printable.astro index ab0ea534..d0b26b5e 100644 --- a/training-front-end/src/pages/training_fleet_pc/printable.astro +++ b/training-front-end/src/pages/training_fleet_pc/printable.astro @@ -21,7 +21,11 @@ const entries = await Promise.all(content_components)
-