├── .github ├── .keep ├── pull_request_template.md ├── dependabot.yml └── workflows │ ├── semantic-pr.yaml │ ├── label-pr.yaml │ ├── db-test-ci.yaml │ ├── linked-issue-pr.yaml │ ├── dependent-issues.yaml │ ├── nextjs-test-ci.yaml │ ├── nextjs-lint.yaml │ ├── license-check.yaml │ ├── lambda-lint.yaml │ └── db-itest-ci.yaml ├── app ├── web │ ├── .prettierrc │ ├── cypress │ │ ├── .gitignore │ │ ├── img │ │ │ └── cypress │ │ │ │ ├── new_spec.png │ │ │ │ ├── run_spec.png │ │ │ │ ├── spec_name.png │ │ │ │ ├── open_cypress.png │ │ │ │ ├── choose_browser.png │ │ │ │ ├── create_new_spec.png │ │ │ │ └── example_spec_run.png │ │ ├── tsconfig.json │ │ └── e2e │ │ │ ├── api │ │ │ └── users.cy.ts │ │ │ ├── user │ │ │ └── appointments.cy.ts │ │ │ ├── logout.cy.ts │ │ │ ├── home.cy.ts │ │ │ ├── staff │ │ │ └── staff.cy.ts │ │ │ └── upload │ │ │ └── upload.cy.ts │ ├── db │ │ ├── .gitignore │ │ ├── tests │ │ │ └── prisma │ │ ├── migrations │ │ │ ├── migration_lock.toml │ │ │ └── 20240408001135_v0_1_0 │ │ │ │ └── migration.sql │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── itests │ │ │ └── package.json │ │ ├── license.header.txt │ │ ├── include │ │ │ └── entrypoint.sh │ │ ├── schema.prisma │ │ └── README.md │ ├── public │ │ └── build.json │ ├── src │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── opengraph-image.png │ │ │ ├── api │ │ │ │ ├── video │ │ │ │ │ ├── status │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── review │ │ │ │ │ │ └── README.md │ │ │ │ │ ├── upload │ │ │ │ │ │ └── README.md │ │ │ │ │ ├── count │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── processed │ │ │ │ │ │ └── route.ts │ │ │ │ ├── message │ │ │ │ │ └── README.md │ │ │ │ ├── README.md │ │ │ │ ├── submitFeedback │ │ │ │ │ ├── README.md │ │ │ │ │ └── route.ts │ │ │ │ ├── auth │ │ │ │ │ ├── [...nextauth] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── logout │ │ │ │ │ │ └── route.ts │ │ │ │ ├── update-info │ │ │ │ │ └── route.ts │ │ │ │ ├── clients │ │ │ │ │ └── README.md │ │ │ │ └── appointments │ │ │ │ │ └── README.md │ │ │ ├── health │ │ │ │ └── liveness │ │ │ │ │ └── route.ts │ │ │ ├── not-found.tsx │ │ │ ├── welcome │ │ │ │ └── page.tsx │ │ │ ├── registration │ │ │ │ └── page.tsx │ │ │ ├── loading.tsx │ │ │ ├── page.tsx │ │ │ ├── verify │ │ │ │ └── [username] │ │ │ │ │ └── page.tsx │ │ │ ├── user │ │ │ │ ├── change_password │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── appointments │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── [id] │ │ │ │ │ └── page.tsx │ │ │ ├── profile │ │ │ │ ├── page.tsx │ │ │ │ ├── update │ │ │ │ │ └── page.tsx │ │ │ │ └── [withUser] │ │ │ │ │ └── page.tsx │ │ │ ├── staff │ │ │ │ ├── appointments │ │ │ │ │ ├── manage │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── new │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ └── id │ │ │ │ │ │ └── [id] │ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── login │ │ │ │ └── page.tsx │ │ │ └── layout.tsx │ │ ├── assets │ │ │ ├── welcome.gif │ │ │ ├── Email_logo.png │ │ │ ├── Github_logo.png │ │ │ ├── dark_logo.png │ │ │ ├── light_logo.png │ │ │ ├── Youtube_logo.png │ │ │ ├── dark_logo_no_name.png │ │ │ ├── light_logo_no_name.png │ │ │ ├── blurring_placeholder.png │ │ │ ├── appointment_background.png │ │ │ ├── pf_avatar.svg │ │ │ └── style.ts │ │ ├── lib │ │ │ ├── userRole.ts │ │ │ ├── url.ts │ │ │ ├── appointment.ts │ │ │ ├── base64.ts │ │ │ ├── lambda.ts │ │ │ ├── ses.ts │ │ │ ├── db.ts │ │ │ └── time.ts │ │ └── components │ │ │ ├── auth │ │ │ ├── link │ │ │ │ ├── SignupLink.tsx │ │ │ │ ├── LoginLink.tsx │ │ │ │ ├── LogoutLink.tsx │ │ │ │ └── LoginLogoutLink.tsx │ │ │ └── button │ │ │ │ ├── LoginButton.tsx │ │ │ │ └── LogoutButton.tsx │ │ │ ├── layout │ │ │ ├── GIthubIconImage.tsx │ │ │ ├── Content.tsx │ │ │ ├── BackgroundImageBasic.tsx │ │ │ ├── PrivacyPalLogo.tsx │ │ │ ├── NavButton.tsx │ │ │ ├── AppointmentBackground.tsx │ │ │ ├── BackButton.tsx │ │ │ ├── NotFoundContainer.tsx │ │ │ ├── Header.tsx │ │ │ └── Footer.tsx │ │ │ ├── appointment │ │ │ ├── inbox │ │ │ │ └── InboxAvatar.tsx │ │ │ └── AppointmentManagementList.tsx │ │ │ ├── form │ │ │ ├── Hint.tsx │ │ │ ├── LinkButton.tsx │ │ │ ├── SelectedItem.tsx │ │ │ └── PalTextInput.tsx │ │ │ ├── welcome │ │ │ ├── GifImage.tsx │ │ │ └── WelcomePage.tsx │ │ │ ├── CustomAvatar.tsx │ │ │ ├── staff │ │ │ └── AttributeFilter.tsx │ │ │ └── ErrorView.tsx │ ├── __tests__ │ │ ├── test-configs │ │ │ └── extractConfigFile.test.json │ │ ├── nextConfig.test.ts │ │ ├── AboutUs.test.tsx │ │ ├── base64.lib.test.ts │ │ ├── time.lib.test.ts │ │ ├── ProfilePicture.test.tsx │ │ ├── ProfileDetail.test.tsx │ │ └── LoadingButton.test.tsx │ ├── .dockerignore │ ├── license.header.txt │ ├── license-config.json │ ├── .gitignore │ ├── env.tpl │ ├── next.config.js │ ├── jest.setup.js │ ├── cypress.config.ts │ ├── Dockerfile │ ├── tsconfig.json │ ├── types │ │ └── next-auth.d.ts │ └── jest.config.mjs ├── README.md ├── video-conversion │ ├── lambda │ │ ├── .gitignore │ │ ├── requirements_dev.txt │ │ ├── resources │ │ │ ├── username-recorded-20240223T193522.mp4 │ │ │ ├── username-recorded-20240223T193522.webm │ │ │ └── sample_event.json │ │ ├── setup.cfg │ │ ├── Dockerfile │ │ ├── install_ffmpeg.sh │ │ └── lambda_fn.py │ ├── images │ │ ├── lambda_deploy.png │ │ ├── lambda_role_page.png │ │ ├── lambda_role_config.png │ │ ├── lambda_general_config.png │ │ └── lambda_trigger_config.png │ └── license.header.txt ├── video-processing │ ├── lambda │ │ ├── .gitignore │ │ ├── requirements.txt │ │ ├── requirements_dev.txt │ │ ├── resources │ │ │ ├── username-recorded-20240223T193522-processed.mp4 │ │ │ ├── sample_event.json │ │ │ └── username-recorded-20240223T193522.mp4 │ │ ├── setup.cfg │ │ ├── Dockerfile │ │ ├── mock_client.py │ │ └── install_ffmpeg.sh │ ├── samples │ │ ├── response_no_faces.json │ │ ├── test.jpg │ │ ├── test.mp4 │ │ ├── response_one_face.json │ │ └── response_two_faces.json │ ├── deprecated │ │ ├── requirements_dev.txt │ │ ├── requirements.txt │ │ ├── setup.cfg │ │ ├── utils.py │ │ ├── Dockerfile │ │ ├── entrypoint.sh │ │ ├── .gitignore │ │ └── .dockerignore │ ├── images │ │ ├── lambda_deploy.png │ │ ├── lambda_role_page.png │ │ ├── lambda_role_config.png │ │ ├── lambda_general_config.png │ │ ├── lambda_trigger_config.png │ │ └── lambda_env_variable_config.png │ └── license.header.txt ├── smoketest │ └── compose │ │ ├── include │ │ └── servers.json │ │ ├── smoketest.sh │ │ ├── privacypal.yaml │ │ └── README.md └── templates │ └── README.md ├── helm-charts ├── .gitignore ├── ct.yaml ├── images │ └── eks_components.png ├── charts │ └── privacypal │ │ ├── templates │ │ ├── configmap.yaml │ │ ├── serviceaccount.yaml │ │ ├── service.yaml │ │ ├── secret.yaml │ │ ├── fieldexport.yaml │ │ ├── tests │ │ │ └── test-connection.yaml │ │ ├── s3.yaml │ │ ├── lambda.yaml │ │ └── ingress.yaml │ │ ├── .helmignore │ │ └── Chart.yaml ├── chart_schema.yaml ├── lintconf.yaml └── scripts │ └── eks │ └── aws_lb_controller_install.sh ├── docs ├── final │ └── README.md ├── plan │ └── Readme.md ├── design │ └── README.md ├── communication │ └── README.md └── weekly logs │ └── README.md └── .gitignore /.github/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/web/.prettierrc: -------------------------------------------------------------------------------- 1 | 2 | {} 3 | -------------------------------------------------------------------------------- /app/web/cypress/.gitignore: -------------------------------------------------------------------------------- 1 | !*.mp4 2 | -------------------------------------------------------------------------------- /helm-charts/.gitignore: -------------------------------------------------------------------------------- 1 | !images/* 2 | -------------------------------------------------------------------------------- /docs/final/README.md: -------------------------------------------------------------------------------- 1 | The home for your final documentation. 2 | -------------------------------------------------------------------------------- /docs/plan/Readme.md: -------------------------------------------------------------------------------- 1 | This is the home for your project plan. 2 | -------------------------------------------------------------------------------- /docs/design/README.md: -------------------------------------------------------------------------------- 1 | The home for your design documentation. 2 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | This is the home for the source code of your application. 2 | -------------------------------------------------------------------------------- /app/video-conversion/lambda/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | !resources/* 3 | .coverage 4 | -------------------------------------------------------------------------------- /app/video-processing/lambda/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | !resources/* 3 | .coverage 4 | -------------------------------------------------------------------------------- /app/web/db/.gitignore: -------------------------------------------------------------------------------- 1 | # local env files 2 | .env*.local 3 | .env 4 | 5 | *.log 6 | -------------------------------------------------------------------------------- /app/video-processing/samples/response_no_faces.json: -------------------------------------------------------------------------------- 1 | { 2 | "FaceDetails": [ 3 | ] 4 | } 5 | -------------------------------------------------------------------------------- /app/video-processing/lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.26.4 2 | opencv-python-headless==4.9.0.80 3 | -------------------------------------------------------------------------------- /app/web/public/build.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "productName": "privacypal" 4 | } 5 | -------------------------------------------------------------------------------- /app/web/db/tests/prisma: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Mock prisma 3 | # Print out command arguments 4 | 5 | echo "$@" 6 | -------------------------------------------------------------------------------- /docs/communication/README.md: -------------------------------------------------------------------------------- 1 | The home for your communications logs where you keep meeting minutes and design decisions. 2 | -------------------------------------------------------------------------------- /app/web/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/app/favicon.ico -------------------------------------------------------------------------------- /app/video-processing/deprecated/requirements_dev.txt: -------------------------------------------------------------------------------- 1 | flake8==7.0.0 2 | pytest==7.4.4 3 | pytest-asyncio==0.21.1 4 | pytest-env==1.1.3 5 | -------------------------------------------------------------------------------- /app/web/src/assets/welcome.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/welcome.gif -------------------------------------------------------------------------------- /app/web/src/assets/Email_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/Email_logo.png -------------------------------------------------------------------------------- /app/web/src/assets/Github_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/Github_logo.png -------------------------------------------------------------------------------- /app/web/src/assets/dark_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/dark_logo.png -------------------------------------------------------------------------------- /app/web/src/assets/light_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/light_logo.png -------------------------------------------------------------------------------- /app/web/src/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/app/opengraph-image.png -------------------------------------------------------------------------------- /app/web/src/assets/Youtube_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/Youtube_logo.png -------------------------------------------------------------------------------- /app/video-processing/samples/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/samples/test.jpg -------------------------------------------------------------------------------- /app/video-processing/samples/test.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/samples/test.mp4 -------------------------------------------------------------------------------- /helm-charts/ct.yaml: -------------------------------------------------------------------------------- 1 | chart-dirs: 2 | - charts 3 | validate-maintainers: false 4 | check-version-increment: false 5 | helm-extra-args: --timeout=600s 6 | -------------------------------------------------------------------------------- /helm-charts/images/eks_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/helm-charts/images/eks_components.png -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/new_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/new_spec.png -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/run_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/run_spec.png -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/spec_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/spec_name.png -------------------------------------------------------------------------------- /app/web/src/assets/dark_logo_no_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/dark_logo_no_name.png -------------------------------------------------------------------------------- /app/web/src/assets/light_logo_no_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/light_logo_no_name.png -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/open_cypress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/open_cypress.png -------------------------------------------------------------------------------- /app/web/src/assets/blurring_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/blurring_placeholder.png -------------------------------------------------------------------------------- /app/video-conversion/images/lambda_deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/images/lambda_deploy.png -------------------------------------------------------------------------------- /app/video-processing/images/lambda_deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/images/lambda_deploy.png -------------------------------------------------------------------------------- /app/video-processing/lambda/requirements_dev.txt: -------------------------------------------------------------------------------- 1 | flake8==7.0.0 2 | pytest==8.1.1 3 | pytest-socket==0.7.0 4 | pytest-env==1.1.3 5 | coverage==7.4.4 6 | moto==5.0.4 7 | -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/choose_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/choose_browser.png -------------------------------------------------------------------------------- /app/web/src/assets/appointment_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/src/assets/appointment_background.png -------------------------------------------------------------------------------- /app/video-conversion/images/lambda_role_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/images/lambda_role_page.png -------------------------------------------------------------------------------- /app/video-processing/images/lambda_role_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/images/lambda_role_page.png -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/create_new_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/create_new_spec.png -------------------------------------------------------------------------------- /app/web/cypress/img/cypress/example_spec_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/web/cypress/img/cypress/example_spec_run.png -------------------------------------------------------------------------------- /app/video-conversion/images/lambda_role_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/images/lambda_role_config.png -------------------------------------------------------------------------------- /app/video-processing/images/lambda_role_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/images/lambda_role_config.png -------------------------------------------------------------------------------- /app/web/db/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /app/video-conversion/images/lambda_general_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/images/lambda_general_config.png -------------------------------------------------------------------------------- /app/video-conversion/images/lambda_trigger_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/images/lambda_trigger_config.png -------------------------------------------------------------------------------- /app/video-processing/deprecated/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3==1.34.41 2 | botocore==1.34.41 3 | numpy==1.26.4 4 | opencv-python-headless==4.9.0.80 5 | quart==0.19.4 6 | uvicorn==0.25.0 7 | -------------------------------------------------------------------------------- /app/video-processing/images/lambda_general_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/images/lambda_general_config.png -------------------------------------------------------------------------------- /app/video-processing/images/lambda_trigger_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/images/lambda_trigger_config.png -------------------------------------------------------------------------------- /app/web/__tests__/test-configs/extractConfigFile.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "tests": [ 3 | { 4 | "id": 1, 5 | "name": "Test Extract Config File" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /app/video-conversion/lambda/requirements_dev.txt: -------------------------------------------------------------------------------- 1 | flake8==7.0.0 2 | pytest==8.0.2 3 | pytest-socket==0.7.0 4 | pytest-env==1.1.3 5 | coverage==7.4.3 6 | moto==5.0.2 7 | testfixtures==8.1.0 8 | -------------------------------------------------------------------------------- /app/video-processing/images/lambda_env_variable_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/images/lambda_env_variable_config.png -------------------------------------------------------------------------------- /app/video-conversion/lambda/resources/username-recorded-20240223T193522.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/lambda/resources/username-recorded-20240223T193522.mp4 -------------------------------------------------------------------------------- /app/video-conversion/lambda/resources/username-recorded-20240223T193522.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-conversion/lambda/resources/username-recorded-20240223T193522.webm -------------------------------------------------------------------------------- /app/web/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "target": "es5", 5 | "lib": ["dom", "es2020"], 6 | "types": ["cypress", "node"] 7 | }, 8 | "include": ["./**/*.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /app/video-processing/samples/response_one_face.json: -------------------------------------------------------------------------------- 1 | { 2 | "FaceDetails": [ 3 | { 4 | "BoundingBox": { 5 | "Width": 0.2, 6 | "Height": 0.4, 7 | "Left": 0.7, 8 | "Top": 0.5 9 | } 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /app/video-processing/lambda/resources/username-recorded-20240223T193522-processed.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/COSC-499-W2023/year-long-project-team-1/HEAD/app/video-processing/lambda/resources/username-recorded-20240223T193522-processed.mp4 -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "privacypal.fullname" . -}}-db-config 6 | labels: 7 | {{- include "privacypal.labels" . | nindent 4 }} 8 | data: {} 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Welcome to PrivacyPal! 👋 2 | 3 | Fixes: # 4 | 5 | ## Description of the change: 6 | *This change allows an environment variable to be configured so that...* 7 | 8 | ## Motivation for the change: 9 | *This change is helpful because users may want to...* 10 | -------------------------------------------------------------------------------- /app/web/db/.dockerignore: -------------------------------------------------------------------------------- 1 | # Container files 2 | Dockerfile 3 | .dockerignore 4 | 5 | # Docs 6 | README.md 7 | 8 | # Git 9 | .git 10 | .gitignore 11 | 12 | # Env 13 | .env 14 | .env.local 15 | 16 | # Makefile 17 | Makefile 18 | 19 | *.log 20 | 21 | # Sample 22 | sample 23 | 24 | # Tests 25 | itests 26 | tests 27 | -------------------------------------------------------------------------------- /app/smoketest/compose/include/servers.json: -------------------------------------------------------------------------------- 1 | { 2 | "Servers": { 3 | "1": { 4 | "Name": "privacypal", 5 | "Group": "Servers", 6 | "Host": "db", 7 | "Port": 5432, 8 | "MaintenanceDB": "postgres", 9 | "Username": "privacypal", 10 | "SSLMode": "prefer" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/weekly logs/README.md: -------------------------------------------------------------------------------- 1 | The home for personal and team weekly logs. 2 | 3 | Please follow the required structure for the logs. For personal logs, each team member can have one markdown file that incorporates added content with the appropriate dates each week. For team logs, each week should correspond to a separate file (markdown or PDF). 4 | -------------------------------------------------------------------------------- /app/video-conversion/lambda/setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = D203 3 | max-line-length = 200 4 | exclude = 5 | __pycache__ 6 | 7 | [tool:pytest] 8 | env = 9 | TEST_EVENT_PATH=resources/sample_event.json 10 | TEST_FILE_NAME=username-recorded-20240223T193522 11 | TMP_DIRECTORY=resources 12 | addopts = --verbose --disable-socket 13 | -------------------------------------------------------------------------------- /app/video-processing/lambda/setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = D203 3 | max-line-length = 200 4 | exclude = 5 | __pycache__ 6 | 7 | [tool:pytest] 8 | env = 9 | TMP_DIRECTORY=resources 10 | OUTPUT_BUCKET=output-video-bucket 11 | TEST_EVENT_PATH=resources/sample_event.json 12 | AWS_DEFAULT_REGION=ca-central-1 13 | addopts = --verbose --disable-socket 14 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "privacypal.serviceAccountName" . }} 6 | labels: 7 | {{- include "privacypal.labels" . | nindent 4 }} 8 | annotations: 9 | {{- toYaml .Values.serviceAccount.annotations | nindent 4 }} 10 | {{- end -}} 11 | -------------------------------------------------------------------------------- /app/video-processing/samples/response_two_faces.json: -------------------------------------------------------------------------------- 1 | { 2 | "FaceDetails": [ 3 | { 4 | "BoundingBox": { 5 | "Width": 0.2, 6 | "Height": 0.4, 7 | "Left": 0.1, 8 | "Top": 0.1 9 | } 10 | }, 11 | { 12 | "BoundingBox": { 13 | "Width": 0.2, 14 | "Height": 0.4, 15 | "Left": 0.5, 16 | "Top": 0.5 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /app/video-conversion/lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/python:3.12 AS deps 2 | 3 | WORKDIR /build 4 | 5 | COPY install_ffmpeg.sh . 6 | 7 | RUN sh install_ffmpeg.sh 8 | 9 | FROM public.ecr.aws/lambda/python:3.12 10 | 11 | COPY --from=deps /build/ffmpeg /usr/bin/ffmpeg 12 | 13 | COPY lambda_fn.py . 14 | 15 | # Overwrite the command by providing a different command directly in the template. 16 | CMD ["lambda_fn.lambda_handler"] 17 | -------------------------------------------------------------------------------- /app/web/db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/node:18-alpine 2 | 3 | USER root 4 | 5 | # Reference: https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine 6 | RUN apk add --no-cache libc6-compat 7 | 8 | RUN adduser --system --ingroup root --uid 1002 prisma 9 | 10 | RUN npm install -g prisma@5.12.1 11 | 12 | WORKDIR /app 13 | 14 | COPY . . 15 | 16 | USER 1002 17 | 18 | ENTRYPOINT ["sh", "include/entrypoint.sh"] 19 | -------------------------------------------------------------------------------- /app/web/db/itests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "db-init-itests", 3 | "version": "0.1.0", 4 | "private": true, 5 | "description": "Integration tests for database initializer", 6 | "scripts": { 7 | "test": "DEBUG=testcontainers* jest" 8 | }, 9 | "devDependencies": { 10 | "@testcontainers/postgresql": "^10.7.1", 11 | "jest": "^29.7.0", 12 | "lodash": "^4.17.21", 13 | "pg": "^8.11.3", 14 | "testcontainers": "^10.7.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/templates/README.md: -------------------------------------------------------------------------------- 1 | 1. Choose user pool you want to add this template. 2 | 2. Under **Messaging** tab, scroll to **Message templates**, choose **Invitation message** and click **Edit** button. 3 | 3. Under **Email**, past the html template in **Email message**, add **Email subject**. 4 | 4. Leave the rest as default settings and click **Save changes**. 5 | 6 | ![image](https://github.com/COSC-499-W2023/year-long-project-team-1/assets/58235340/160fa5ea-0e68-4a28-aecb-5624fc7cf962) 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/app/web" 5 | target-branch: "develop" 6 | schedule: 7 | interval: "daily" 8 | labels: 9 | - "dependencies" 10 | - "chore" 11 | - package-ecosystem: "pip" 12 | directory: "/app/video-processing/lambda" 13 | target-branch: "develop" 14 | schedule: 15 | interval: "daily" 16 | labels: 17 | - "dependencies" 18 | - "chore" 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # we need this guy 2 | !**/resources/*.mp4 3 | 4 | # don't commit test and temp video/image files 5 | *.mp4 6 | *.mkv 7 | *.avi 8 | *.webm 9 | *.mov 10 | *.png 11 | *.jpg 12 | 13 | # don't commit my .vscode settings folder 14 | .vscode 15 | 16 | # don't commit my __pycache__ folders 17 | **/__pycache__/ 18 | 19 | # don't commit system files 20 | .DS_Store 21 | 22 | # makefile for windows 23 | **/Makefile-win 24 | 25 | # keep our readme images 26 | !**/images/*.png 27 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /.github/workflows/semantic-pr.yaml: -------------------------------------------------------------------------------- 1 | name: Semantic Pull Request Check 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - edited 9 | - synchronize 10 | 11 | jobs: 12 | check: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | pull-requests: write 16 | statuses: write 17 | steps: 18 | - uses: amannn/action-semantic-pull-request@v5.3.0 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /.github/workflows/label-pr.yaml: -------------------------------------------------------------------------------- 1 | name: Semantic labels Check 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - labeled 8 | - unlabeled 9 | - synchronize 10 | 11 | jobs: 12 | check-and-comment: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: yashhy/pr-label-check-and-comment-action@v1.0.1 16 | with: 17 | required_labels: 'chore,ci,docs,feat,build,fix,test,dependencies' 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | -------------------------------------------------------------------------------- /app/web/.dockerignore: -------------------------------------------------------------------------------- 1 | # Build files 2 | Dockerfile 3 | .dockerignore 4 | 5 | # Node modules 6 | node_modules 7 | 8 | # Logs 9 | npm-debug.log 10 | 11 | # Documentation 12 | README.md 13 | 14 | # Build outputs 15 | .next 16 | 17 | # git 18 | .git 19 | .gitignore 20 | 21 | # Tests 22 | __tests__ 23 | jest.* 24 | 25 | # Database 26 | db/ 27 | !db/schema.prisma 28 | 29 | # Local conf 30 | # FIXME: Uncomment when auth managers are updated 31 | # conf/ 32 | 33 | # Development .env 34 | .env 35 | .env.local 36 | -------------------------------------------------------------------------------- /app/web/src/app/api/video/status/README.md: -------------------------------------------------------------------------------- 1 | # Video Status API 2 | 3 | ## Expects 4 | 5 | - `filename`: used value returned by `/api/video/upload` 6 | 7 | ## Request 8 | 9 | ```json 10 | GET api/video/status?filename= 11 | ``` 12 | 13 | ## Returns 14 | 15 | Encoding: 16 | 17 | - `application/json` 18 | 19 | Complete status: 20 | 21 | ```json 22 | { 23 | "message": "done" 24 | } 25 | ``` 26 | 27 | Still in process status: 28 | 29 | ```json 30 | { 31 | "message": "processing" 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /app/web/src/app/api/message/README.md: -------------------------------------------------------------------------------- 1 | # Appointments API 2 | 3 | - Post message linked to an appointment to pg with time 4 | 5 | ## Endpoint 6 | 7 | ```json 8 | POST /api/message 9 | ``` 10 | 11 | ## Request body 12 | 13 | ```json 14 | { 15 | "apptId": 1, 16 | "message": "another new video 2" 17 | } 18 | ``` 19 | 20 | ## Response 21 | 22 | ```json 23 | { 24 | "message": { 25 | "data": { 26 | "status": 200, 27 | "title": "OK" 28 | } 29 | } 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /app/video-processing/lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/python:3.12 AS deps 2 | 3 | WORKDIR /build 4 | 5 | COPY install_ffmpeg.sh . 6 | 7 | RUN sh install_ffmpeg.sh 8 | 9 | FROM public.ecr.aws/lambda/python:3.12 10 | 11 | COPY --from=deps /build/ffmpeg /usr/bin/ffmpeg 12 | 13 | COPY requirements.txt . 14 | 15 | RUN pip install -r requirements.txt 16 | 17 | COPY video_processor.py lambda_fn.py . 18 | 19 | # Overwrite the command by providing a different command directly in the template. 20 | CMD ["lambda_fn.lambda_handler"] 21 | -------------------------------------------------------------------------------- /app/web/src/app/api/README.md: -------------------------------------------------------------------------------- 1 | # API routes 2 | 3 | How to make an API route: 4 | 5 | Create a folder with the name of the url slug you want to use: 6 | 7 | i.e. `localhost:3000/api/my-route` => `/src/app/api/my-route` 8 | 9 | Then inside this folder, create a file called `route.ts` that exports a default `async` function. 10 | 11 | ```ts 12 | import { NextApiRequest, NextApiResponse } from "next"; 13 | 14 | export default async function handler( 15 | req: NextApiRequest, 16 | res: NextApiResponse, 17 | ) { 18 | res.status(200).json({ message: "Hello World!" }); 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{- $svcName := include "privacypal.fullname" . -}} 2 | --- 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | name: {{ $svcName }} 7 | labels: 8 | {{- include "privacypal.labels" . | nindent 4 }} 9 | annotations: 10 | {{- toYaml .Values.web.service.annotations | indent 4 }} 11 | spec: 12 | type: {{ .Values.web.service.type }} 13 | ports: 14 | - port: {{ .Values.web.service.port }} 15 | targetPort: http 16 | protocol: TCP 17 | name: http 18 | selector: 19 | {{- include "privacypal.selectorLabels" . | nindent 4 }} 20 | -------------------------------------------------------------------------------- /app/web/db/license.header.txt: -------------------------------------------------------------------------------- 1 | Copyright [2023] [Privacypal Authors] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /app/web/license.header.txt: -------------------------------------------------------------------------------- 1 | Copyright [2023] [Privacypal Authors] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | 3 | name: privacypal 4 | 5 | description: A Helm chart for PrivacyPal 6 | 7 | type: application 8 | 9 | version: 0.1.0-dev 10 | 11 | appVersion: "0.1.0-dev" 12 | 13 | kubeVersion: ">= 1.27.0-0" 14 | 15 | keywords: 16 | - privacypal 17 | - video-processing 18 | - security 19 | 20 | home: https://github.com/COSC-499-W2023/year-long-project-team-1 21 | 22 | # icon: 23 | 24 | sources: 25 | - https://github.com/COSC-499-W2023/year-long-project-team-1 26 | 27 | maintainers: 28 | - name: Privacypal Team 29 | url: https://github.com/orgs/COSC-499-W2023/teams/team-1 30 | -------------------------------------------------------------------------------- /app/video-conversion/license.header.txt: -------------------------------------------------------------------------------- 1 | Copyright [2023] [Privacypal Authors] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /app/video-processing/license.header.txt: -------------------------------------------------------------------------------- 1 | Copyright [2023] [Privacypal Authors] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /app/smoketest/compose/smoketest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | COMPOSE_TOOL=${COMPOSE_TOOL:-docker-compose} 6 | 7 | FILES=( 8 | privacypal.yaml 9 | db.yaml 10 | ) 11 | 12 | CMDS=() 13 | 14 | for file in "${FILES[@]}"; do 15 | CMDS+=( -f "${file}" ) 16 | done 17 | 18 | cleanup() { 19 | local DOWN_FLAGS=('--remove-orphans') 20 | if [ "${KEEP_VOLUMES}" != "true" ]; then 21 | DOWN_FLAGS+=('--volumes') 22 | fi 23 | ${COMPOSE_TOOL} \ 24 | "${CMDS[@]}" \ 25 | down "${DOWN_FLAGS[@]}" 26 | } 27 | 28 | trap cleanup EXIT 29 | 30 | cleanup 31 | 32 | ${COMPOSE_TOOL} \ 33 | "${CMDS[@]}" \ 34 | up 35 | -------------------------------------------------------------------------------- /app/web/license-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "license.header.txt", 3 | "licenseFormats": { 4 | "ts|tsx": { 5 | "prepend": "/*", 6 | "append": " */", 7 | "eachLine": { 8 | "prepend": " * " 9 | } 10 | } 11 | }, 12 | "ignore": [ 13 | "__tests__/**/*.snap", 14 | ".next", 15 | ".swc", 16 | "conf", 17 | "coverage", 18 | "**/*.md", 19 | "db", 20 | "**/.dockerignore", 21 | "**/.gitignore", 22 | "**/Dockerfile", 23 | "**/Makefile", 24 | "**/.env*", 25 | "**/*.(sh|bash)", 26 | "**/*.log", 27 | "env.tpl", 28 | ".prettierrc", 29 | "**/*.svg" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /app/video-processing/deprecated/setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = D203 3 | max-line-length = 200 4 | exclude = 5 | __pycache__ 6 | 7 | [tool:pytest] 8 | testpaths = . 9 | env = 10 | PRIVACYPAL_INPUT_VIDEO_DIR={PWD}/samples 11 | PRIVACYPAL_OUTPUT_VIDEO_DIR={PWD}/samples 12 | AWS_ACCESS_KEY_ID=some-key-id 13 | AWS_SECRET_ACCESS_KEY=some-access-key 14 | AWS_SESSION_TOKEN=some-session-token 15 | AWS_DEFAULT_REGION=ca-central-1 16 | ENVIRONMENT=testing 17 | log_cli = true 18 | log_cli_level = INFO 19 | log_cli_format = "%%(asctime)s [%%(levelname)8s] %%(message)s (%%(filename)s:%%(lineno)s)" 20 | log_cli_date_format = "%%Y-%%m-%%d %%H:%%M:%%S 21 | -------------------------------------------------------------------------------- /app/web/src/app/api/video/review/README.md: -------------------------------------------------------------------------------- 1 | # Video Review API 2 | 3 | Review a processed video. If accepted, the video is uploaded to S3 shared bucket. After request, all source and processed videos are deleted. 4 | 5 | ## Endpoint 6 | 7 | ```json 8 | POST /api/video/review 9 | ``` 10 | 11 | Request body (JSON): 12 | 13 | - `apptId`: Appointment ID. 14 | - `filename`: Name of file to review. 15 | - `action`: Action to perform. Can be one of `accept`, `reject` or `noop`. 16 | 17 | For example: 18 | 19 | ```json 20 | { 21 | "apptId": "1", 22 | "filename": "test1.mp4", 23 | "action": "accept" 24 | } 25 | ``` 26 | 27 | ## Response 28 | 29 | Status `200`: Action is completed. Empty body. 30 | -------------------------------------------------------------------------------- /app/web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env* 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | # SWC 38 | .swc/ 39 | 40 | # Logs 41 | *.log 42 | 43 | # preserve front end images 44 | !*.png 45 | !*.jpg 46 | 47 | cypress/screenshots 48 | cypress.env.json 49 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | {{ $fullName := include "privacypal.fullname" . -}} 2 | {{- if empty .Values.database.credentialSecretName -}} 3 | --- 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: {{ $fullName }}-postgres-secret 8 | labels: 9 | {{- include "privacypal.labels" . | nindent 4 }} 10 | type: Opaque 11 | data: 12 | DB_PASSWORD: {{ include "privacypal.databasePassword" . }} 13 | {{- end }} 14 | --- 15 | apiVersion: v1 16 | kind: Secret 17 | metadata: 18 | name: {{ $fullName }}-nextauth-secret 19 | labels: 20 | {{- include "privacypal.labels" . | nindent 4 }} 21 | type: Opaque 22 | data: 23 | SECRET: {{ include "privacypal.nextauthSecret" . }} 24 | -------------------------------------------------------------------------------- /helm-charts/chart_schema.yaml: -------------------------------------------------------------------------------- 1 | name: str() 2 | home: str(required=False) 3 | version: str() 4 | appVersion: any(str(), num(), required=False) 5 | description: str(required=False) 6 | keywords: list(str(), required=False) 7 | sources: list(str(), required=False) 8 | maintainers: list(include('maintainer'), required=False) 9 | icon: str(required=False) 10 | apiVersion: str(required=False) 11 | engine: str(required=False) 12 | condition: str(required=False) 13 | tags: str(required=False) 14 | deprecated: bool(required=False) 15 | kubeVersion: str(required=False) 16 | annotations: map(str(), str(), required=False) 17 | --- 18 | maintainer: 19 | name: str(required=False) 20 | email: str(required=False) 21 | url: str(required=False) 22 | -------------------------------------------------------------------------------- /.github/workflows/db-test-ci.yaml: -------------------------------------------------------------------------------- 1 | name: Database Initializer Unit Tests 2 | 3 | concurrency: 4 | group: ${{ github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - "develop" 11 | - "master" 12 | - "main" 13 | pull_request: 14 | paths: 15 | - "app/web/db/**" 16 | types: 17 | - opened 18 | - reopened 19 | - synchronize 20 | workflow_dispatch: 21 | 22 | jobs: 23 | itest: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Check out the repository 27 | uses: actions/checkout@v4 28 | with: 29 | token: ${{ github.token }} 30 | - name: Run tests 31 | working-directory: app/web/db 32 | run: make test 33 | -------------------------------------------------------------------------------- /app/web/env.tpl: -------------------------------------------------------------------------------- 1 | AWS_ACCESS_KEY_ID= 2 | AWS_SECRET_ACCESS_KEY= 3 | AWS_SESSION_TOKEN= 4 | COGNITO_CLIENT= 5 | COGNITO_CLIENT_SECRET= 6 | COGNITO_POOL_ID= 7 | AWS_REGION="ca-central-1" 8 | PRIVACYPAL_AUTH_MANAGER=cognito 9 | PRIVACYPAL_AUTH_SECRET="0Fa2BOJrd3958qaZUa7pf1jEREoo6tU5rsx430bUp/k=" 10 | PRIVACYPAL_POSTGRES_USERNAME=privacypal 11 | PRIVACYPAL_POSTGRES_PASSWORD=password 12 | PRIVACYPAL_POSTGRES_HOST=localhost 13 | PRIVACYPAL_POSTGRES_PORT=5432 14 | PRIVACYPAL_POSTGRES_DATABASE=privacypal 15 | PRIVACYPAL_PROCESSOR_LAMBDA=processVideoContainer 16 | PRIVACYPAL_CONVERSION_LAMBDA=mediaConvert 17 | PRIVACYPAL_OUTPUT_BUCKET=privacypal-output 18 | PRIVACYPAL_TMP_BUCKET=privacypal-input 19 | NEXTAUTH_URL="http://localhost:3000" 20 | NOREPLY_EMAIL= 21 | -------------------------------------------------------------------------------- /app/video-processing/lambda/mock_client.py: -------------------------------------------------------------------------------- 1 | # Copyright [2023] [Privacypal Authors] 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | class MockClient: 16 | def detect_faces(Image: any): 17 | return None 18 | -------------------------------------------------------------------------------- /app/web/src/lib/userRole.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export enum UserRole { 17 | PROFESSIONAL = "professional", 18 | CLIENT = "client", 19 | } 20 | -------------------------------------------------------------------------------- /app/web/src/app/health/liveness/route.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | export async function GET() { 17 | return new Response(null, { status: 200 }); 18 | } 19 | -------------------------------------------------------------------------------- /app/video-processing/deprecated/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright [2023] [Privacypal Authors] 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | 17 | 18 | def get_env(key: str, default: str): 19 | return os.environ.get(key, default=default) 20 | -------------------------------------------------------------------------------- /.github/workflows/linked-issue-pr.yaml: -------------------------------------------------------------------------------- 1 | name: Linked Issue Verification 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - edited 9 | - synchronize 10 | 11 | jobs: 12 | verify: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | pull-requests: write 16 | issues: read 17 | if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]' 18 | steps: 19 | - uses: Codeinwp/verify-linked-issue-action@6da9af91d78847c7ea264083a64eab3271b4369f 20 | id: verify_issue_reference 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | - name: Report no referenced issue 24 | if: steps.verify_issue_reference.outputs.has_linked_issues != 'true' 25 | run: exit 1; 26 | -------------------------------------------------------------------------------- /app/web/src/lib/url.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export const redirUrlFromReq = (req: Request, url: string) => { 18 | const baseUrl = new URL(req.url).origin; 19 | return new URL(url, baseUrl).toString(); 20 | }; 21 | -------------------------------------------------------------------------------- /app/web/src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import NotFoundContainer from "@components/layout/NotFoundContainer"; 18 | 19 | export default async function NotFound() { 20 | return ; 21 | } 22 | -------------------------------------------------------------------------------- /app/web/src/components/auth/link/SignupLink.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | 18 | import Link from "next/link"; 19 | 20 | export const SignupLink = () => { 21 | return Sign up; 22 | }; 23 | -------------------------------------------------------------------------------- /.github/workflows/dependent-issues.yaml: -------------------------------------------------------------------------------- 1 | name: Dependent Issues 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - reopened 9 | pull_request: 10 | types: 11 | - opened 12 | - edited 13 | - reopened 14 | - synchronize # Add status check for PRs. 15 | 16 | # Schedule a daily check. 17 | # Used in referencing cross-repository issues or pull requests 18 | schedule: 19 | - cron: '0 0 * * *' 20 | 21 | jobs: 22 | check: 23 | runs-on: ubuntu-latest 24 | permissions: 25 | pull-requests: write 26 | issues: read 27 | statuses: write 28 | steps: 29 | - uses: z0al/dependent-issues@v1 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | with: 33 | check_issues: off # Do not check issues 34 | keywords: depends on, blocked by, based on 35 | -------------------------------------------------------------------------------- /app/web/next.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright [2023] [Privacypal Authors] 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | /** @type {import('next').NextConfig} */ 17 | 18 | const nextConfig = { 19 | // https://nextjs.org/docs/pages/api-reference/next-config-js/output#automatically-copying-traced-files 20 | output: "standalone", 21 | }; 22 | 23 | module.exports = nextConfig; 24 | -------------------------------------------------------------------------------- /app/web/db/include/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright [2023] [Privacypal Authors] 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | set -e 19 | 20 | export DATABASE_URL=postgresql://$PRIVACYPAL_POSTGRES_USERNAME:$PRIVACYPAL_POSTGRES_PASSWORD@$PRIVACYPAL_POSTGRES_HOST:$PRIVACYPAL_POSTGRES_PORT/$PRIVACYPAL_POSTGRES_DATABASE 21 | 22 | prisma migrate deploy 23 | -------------------------------------------------------------------------------- /app/web/src/app/welcome/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import Content from "@components/layout/Content"; 17 | import { WelcomePage } from "@components/welcome/WelcomePage"; 18 | 19 | export default function Page() { 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /app/web/src/components/auth/link/LoginLink.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | 18 | interface LoginLinkProps { 19 | authManager: string; 20 | text?: string; 21 | } 22 | 23 | export const LoginLink = ({ authManager, text }: LoginLinkProps) => { 24 | return {text ?? "Sign in"}; 25 | }; 26 | -------------------------------------------------------------------------------- /app/web/src/lib/appointment.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { User } from "next-auth"; 18 | import { CognitoUser } from "./cognito"; 19 | 20 | export interface ViewableAppointment { 21 | id: number; 22 | clientUser: CognitoUser; 23 | professionalUser: User; 24 | time: Date; 25 | video_count: number; 26 | } 27 | -------------------------------------------------------------------------------- /app/web/src/lib/base64.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { Buffer } from "buffer"; 17 | 18 | export const utf8ToBase64 = (s: string) => { 19 | return Buffer.from(s, "binary").toString("base64"); 20 | }; 21 | 22 | export const base64ToUtf8 = (s: string) => { 23 | return Buffer.from(s, "base64").toString("binary"); 24 | }; 25 | -------------------------------------------------------------------------------- /app/web/db/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | model Appointment { 14 | id Int @id @default(autoincrement()) 15 | time DateTime @default(now()) 16 | proUsrName String 17 | clientUsrName String 18 | Video Video[] 19 | Message Message[] 20 | } 21 | 22 | model Video { 23 | appt Appointment @relation(fields: [apptId], references: [id]) 24 | apptId Int 25 | awsRef String @id 26 | time DateTime 27 | } 28 | 29 | model Message { 30 | id Int @id @default(autoincrement()) 31 | appt Appointment @relation(fields: [apptId], references: [id]) 32 | apptId Int 33 | sender String 34 | message String 35 | time DateTime 36 | } 37 | -------------------------------------------------------------------------------- /app/web/src/app/registration/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import Content from "@components/layout/Content"; 17 | import { RegistrationForm } from "@components/registration/RegistrationForm"; 18 | 19 | export default function Page() { 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /app/web/src/components/layout/GIthubIconImage.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | import { GithubIcon } from "@patternfly/react-icons"; 18 | import Github from "next-auth/providers/github"; 19 | 20 | export const GithubIconImage: React.FunctionComponent = () => { 21 | return ; 22 | }; 23 | -------------------------------------------------------------------------------- /app/web/src/app/loading.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import Content from "@components/layout/Content"; 18 | import { Spinner } from "@patternfly/react-core"; 19 | 20 | export default function Loading() { 21 | return ( 22 | 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /app/web/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import Content from "@components/layout/Content"; 17 | import { WelcomePage } from "@components/welcome/WelcomePage"; 18 | 19 | export const dynamic = "force-dynamic"; 20 | 21 | export default async function HomePage() { 22 | return ( 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /app/web/__tests__/nextConfig.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import nextConfig from "../next.config"; 18 | 19 | describe("Next Config", () => { 20 | it("should have a valid config", () => { 21 | expect(nextConfig).toBeDefined(); 22 | }); 23 | 24 | it("should be in standalone mode", () => { 25 | expect(nextConfig.output).toEqual("standalone"); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /app/web/jest.setup.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright [2023] [Privacypal Authors] 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | process.env.NODE_ENV = "test"; 18 | process.env.PRIVACYPAL_AUTH_SECRET = 19 | "SoNlMT8Tbo2yzTYezGxgVTHtKHDdbDVWXaIvCsxz5kc="; 20 | process.env.PRIVACYPAL_AUTH_MANAGER = "cognito"; 21 | 22 | const mGetRandomValues = jest.fn().mockReturnValueOnce(new Uint32Array(10)); 23 | Object.defineProperty(window, "crypto", { 24 | value: { getRandomValues: mGetRandomValues }, 25 | }); 26 | -------------------------------------------------------------------------------- /app/video-processing/deprecated/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/python:3.9-slim-bullseye AS base 2 | 3 | USER root 4 | 5 | ENV PYTHONDONTWRITEBYTECODE 1 6 | ENV PYTHONUNBUFFERED 1 7 | 8 | RUN apt-get update 9 | 10 | FROM base AS builder 11 | 12 | WORKDIR /build 13 | 14 | RUN apt-get install -y --no-install-recommends build-essential gcc ffmpeg libsm6 libxext6 15 | 16 | COPY requirements.txt . 17 | 18 | RUN pip wheel --no-cache-dir --no-deps --wheel-dir /build/wheels -r requirements.txt 19 | 20 | FROM base AS runner 21 | 22 | RUN apt-get install -y --no-install-recommends ffmpeg 23 | 24 | ENV CONFIG_DIR=/opt/privacypal 25 | 26 | RUN mkdir -p $CONFIG_DIR && chmod -R g=u $CONFIG_DIR 27 | 28 | RUN adduser --system --ingroup root uvicorn 29 | 30 | WORKDIR /app 31 | 32 | COPY --from=builder /build/wheels /wheels 33 | 34 | RUN pip install --no-cache /wheels/* 35 | 36 | COPY --chown=uvicorn . . 37 | 38 | USER uvicorn 39 | 40 | EXPOSE 3000 41 | 42 | ENV PORT 3000 43 | ENV HOST "0.0.0.0" 44 | 45 | ENTRYPOINT ["sh", "entrypoint.sh"] 46 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/fieldexport.yaml: -------------------------------------------------------------------------------- 1 | {{ $fullName := include "privacypal.fullname" . -}} 2 | --- 3 | apiVersion: services.k8s.aws/v1alpha1 4 | kind: FieldExport 5 | metadata: 6 | name: {{ $fullName }}-db-host 7 | labels: 8 | {{- include "privacypal.labels" . | nindent 4 }} 9 | spec: 10 | to: 11 | name: {{ $fullName }}-db-config 12 | kind: configmap 13 | key: db-host 14 | from: 15 | path: ".status.endpoint.address" 16 | resource: 17 | group: rds.services.k8s.aws 18 | kind: DBInstance 19 | name: {{ $fullName }}-db 20 | --- 21 | apiVersion: services.k8s.aws/v1alpha1 22 | kind: FieldExport 23 | metadata: 24 | name: {{ $fullName }}-db-port 25 | labels: 26 | {{- include "privacypal.labels" . | nindent 4 }} 27 | spec: 28 | to: 29 | name: {{ $fullName }}-db-config 30 | kind: configmap 31 | key: db-port 32 | from: 33 | path: ".status.endpoint.port" 34 | resource: 35 | group: rds.services.k8s.aws 36 | kind: DBInstance 37 | name: {{ $fullName }}-db 38 | -------------------------------------------------------------------------------- /app/web/src/components/auth/link/LogoutLink.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | 18 | import { signOut } from "next-auth/react"; 19 | 20 | interface LogoutLinkProps { 21 | text?: string; 22 | } 23 | 24 | export const LogoutLink = ({ text }: LogoutLinkProps) => { 25 | return ( 26 | signOut({ callbackUrl: "/" })}> 27 | {text ?? "Sign out"} 28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /.github/workflows/nextjs-test-ci.yaml: -------------------------------------------------------------------------------- 1 | name: NextJS Unit Tests 2 | 3 | concurrency: 4 | group: ${{ github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - "develop" 11 | - "master" 12 | - "main" 13 | pull_request: 14 | paths: 15 | - "app/web/**" 16 | - "!app/web/db/**" 17 | types: 18 | - opened 19 | - reopened 20 | - synchronize 21 | 22 | jobs: 23 | unit-test: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Check out the repository 27 | uses: actions/checkout@v4 28 | with: 29 | token: ${{ github.token }} 30 | - name: Set up Node 31 | uses: actions/setup-node@v4 32 | with: 33 | node-version: '18' 34 | cache: 'npm' 35 | cache-dependency-path: app/web/package-lock.json 36 | - name: Install dependencies 37 | uses: bahmutov/npm-install@v1 38 | with: 39 | working-directory: app/web 40 | - name: Run tests 41 | working-directory: app/web 42 | run: npm run test 43 | -------------------------------------------------------------------------------- /app/web/src/app/api/submitFeedback/README.md: -------------------------------------------------------------------------------- 1 | In order to send user's feedback for sending and recieving emails, AWS SES (Simple Email Service) is used. An email is required to be verified on AWS SES Console in order to start sending/receiving feedbacks. 2 | 3 | ### Follow this guide to create AWS account if you haven't had one 4 | 5 | https://docs.aws.amazon.com/accounts/latest/reference/welcome-first-time-user.html#getting-started-prerequisites 6 | 7 | 8 | ### Verify destination email in AWS SES 9 | 10 | - Log into [AWS SES Console](https://ca-central-1.console.aws.amazon.com/ses/home?region=ca-central-1#/account). 11 | 12 | - Chose **Identities** and **Create identity**. 13 | 14 | - Create new domain/email that will be used to receive feedback. 15 | 16 | - A link for verification will be sent to the newly added email. After confirm email ownership, the email can be authorized to send/receive feedback. 17 | 18 | ### Configure environment variables: 19 | - Set the `NOREPLY_EMAIL` environment variable for the web server container to the newly created verified email address. 20 | -------------------------------------------------------------------------------- /app/web/src/components/auth/link/LoginLogoutLink.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { auth, authManager } from "src/auth"; 17 | import { LogoutLink } from "./LogoutLink"; 18 | import { LoginLink } from "./LoginLink"; 19 | 20 | export const LoginLogoutLink = async () => { 21 | const session = await auth(); 22 | 23 | if (session?.user) { 24 | return ; 25 | } 26 | return ; 27 | }; 28 | -------------------------------------------------------------------------------- /app/video-conversion/lambda/install_ffmpeg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright [2023] [Privacypal Authors] 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | TEMP_DIR=$(mktemp -d) 19 | OUTPUT_DIR=${OUTPUT_DIR:-$PWD} 20 | 21 | VERSION=6.0.1 22 | PACKAGE_NAME=ffmpeg-${VERSION}-amd64-static 23 | SOURCE_URL=https://www.johnvansickle.com/ffmpeg/old-releases/${PACKAGE_NAME}.tar.xz 24 | 25 | 26 | cd $TEMP_DIR 27 | 28 | wget $SOURCE_URL 29 | tar xvf ${PACKAGE_NAME}.tar.xz 30 | mv ${PACKAGE_NAME}/ffmpeg $OUTPUT_DIR 31 | 32 | cd - 33 | -------------------------------------------------------------------------------- /app/video-processing/lambda/install_ffmpeg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright [2023] [Privacypal Authors] 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | TEMP_DIR=$(mktemp -d) 19 | OUTPUT_DIR=${OUTPUT_DIR:-$PWD} 20 | 21 | VERSION=6.0.1 22 | PACKAGE_NAME=ffmpeg-${VERSION}-amd64-static 23 | SOURCE_URL=https://www.johnvansickle.com/ffmpeg/old-releases/${PACKAGE_NAME}.tar.xz 24 | 25 | 26 | cd $TEMP_DIR 27 | 28 | wget $SOURCE_URL 29 | tar xvf ${PACKAGE_NAME}.tar.xz 30 | mv ${PACKAGE_NAME}/ffmpeg $OUTPUT_DIR 31 | 32 | cd - 33 | -------------------------------------------------------------------------------- /app/web/src/components/auth/button/LoginButton.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | 18 | import LoadingButton from "@components/form/LoadingButton"; 19 | 20 | interface LoginButtonProps { 21 | text?: string; 22 | } 23 | 24 | export const LoginButton = ({ text }: LoginButtonProps) => { 25 | return ( 26 | 27 | {text || `Sign in`} 28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /.github/workflows/nextjs-lint.yaml: -------------------------------------------------------------------------------- 1 | name: NextJS Format Check 2 | 3 | concurrency: 4 | group: ${{ github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - "develop" 11 | - "master" 12 | - "main" 13 | pull_request: 14 | paths: 15 | - "app/web/**" 16 | - "!app/web/db/**" 17 | types: 18 | - opened 19 | - reopened 20 | - synchronize 21 | 22 | jobs: 23 | prettier-check: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Check out the repository 27 | uses: actions/checkout@v4 28 | with: 29 | token: ${{ github.token }} 30 | - name: Set up Node 31 | uses: actions/setup-node@v4 32 | with: 33 | node-version: '18' 34 | cache: 'npm' 35 | cache-dependency-path: app/web/package-lock.json 36 | - name: Install dependencies 37 | uses: bahmutov/npm-install@v1 38 | with: 39 | working-directory: app/web 40 | - name: Run prettier check 41 | working-directory: app/web 42 | run: npm run prettier:check 43 | -------------------------------------------------------------------------------- /app/web/src/app/verify/[username]/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import Content from "@components/layout/Content"; 17 | import { VerificationForm } from "@components/registration/VerificationForm"; 18 | 19 | export default async function VerificationPage({ 20 | params, 21 | }: { 22 | params: { username: string }; 23 | }) { 24 | return ( 25 | 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /app/web/cypress/e2e/api/users.cy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | describe("/api/users: Fetch users", () => { 18 | it("Should return a list of users", () => { 19 | cy.request("/api/users").then((response) => { 20 | expect(response.status).to.eq(200); 21 | expect(response.body).to.have.property("result"); 22 | expect(Array.isArray(response.body.result.data)).to.be.true; 23 | expect(response.body.result.data.length).to.be.at.least(0); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "privacypal.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "privacypal.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test 9 | spec: 10 | containers: 11 | - name: health-check 12 | image: registry.access.redhat.com/ubi8/ubi:latest 13 | command: 14 | - /bin/bash 15 | - '-ec' 16 | - > 17 | dnf install --disableplugin=subscription-manager -yq jq; 18 | curl -sSf --retry 20 --retry-connrefused http://{{ include "privacypal.fullname" . }}:{{ .Values.web.service.port }}/health | tee /tmp/out.json; 19 | jq -e '(.data.app_version | test("{{ .Chart.AppVersion | squote }}"))' /tmp/out.json; 20 | jq -e '.data.video_conversion_available == true' /tmp/out.json; 21 | jq -e '.data.video_processor_available == true' /tmp/out.json; 22 | jq -e '.data.database_available == true' /tmp/out.json; 23 | jq -e '.data.video_storage_available == true' /tmp/out.json 24 | restartPolicy: Never 25 | -------------------------------------------------------------------------------- /app/web/cypress.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { defineConfig } from "cypress"; 18 | 19 | const APP_PORT = process.env.APP_PORT || 8081; 20 | 21 | export default defineConfig({ 22 | projectId: "tyhfus", 23 | e2e: { 24 | specPattern: "cypress/{tests,e2e}/**/*.cy.{js,jsx,ts,tsx}", 25 | baseUrl: `http://localhost:${APP_PORT}/`, 26 | supportFile: "cypress/support/commands.ts", 27 | setupNodeEvents(on, config) { 28 | // implement node event listeners here 29 | }, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /app/web/src/components/appointment/inbox/InboxAvatar.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { CSS } from "@lib/utils"; 17 | import { Avatar } from "@patternfly/react-core"; 18 | 19 | interface AvatarProps { 20 | avatarUrl: string; 21 | alt?: string; 22 | style?: CSS; 23 | } 24 | 25 | export const InboxAvatar = ({ avatarUrl, style }: AvatarProps) => { 26 | const avatarStyle: CSS = { 27 | borderRadius: "100%", 28 | ...style, 29 | }; 30 | return ; 31 | }; 32 | -------------------------------------------------------------------------------- /app/web/__tests__/AboutUs.test.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import AboutUs from "@components/welcome/AboutUs"; 17 | import "@testing-library/jest-dom"; 18 | import { render, screen } from "@testing-library/react"; 19 | 20 | describe("AboutUs Component", () => { 21 | it("renders about us text", () => { 22 | render(); 23 | const aboutUsText = screen.getByText((content) => { 24 | return content.startsWith("Welcome to PrivacyPal"); 25 | }); 26 | expect(aboutUsText).toBeInTheDocument(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /app/web/src/assets/pf_avatar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/web/cypress/e2e/user/appointments.cy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | describe("User appointments functionality", () => { 17 | it("should redirect to /login if not logged in", () => { 18 | cy.visit("/user/appointments"); 19 | cy.wait(250); 20 | cy.url().should("include", "/login"); 21 | }); 22 | 23 | it("should allow visit user appointment page if logged in", () => { 24 | cy.loginAsClient(); 25 | cy.wait(250); 26 | cy.visit("/user/appointments"); 27 | cy.url().should("include", "/user/appointments"); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /app/web/db/migrations/20240408001135_v0_1_0/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "Appointment" ( 3 | "id" SERIAL NOT NULL, 4 | "time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | "proUsrName" TEXT NOT NULL, 6 | "clientUsrName" TEXT NOT NULL, 7 | 8 | CONSTRAINT "Appointment_pkey" PRIMARY KEY ("id") 9 | ); 10 | 11 | -- CreateTable 12 | CREATE TABLE "Video" ( 13 | "apptId" INTEGER NOT NULL, 14 | "awsRef" TEXT NOT NULL, 15 | "time" TIMESTAMP(3) NOT NULL, 16 | 17 | CONSTRAINT "Video_pkey" PRIMARY KEY ("awsRef") 18 | ); 19 | 20 | -- CreateTable 21 | CREATE TABLE "Message" ( 22 | "id" SERIAL NOT NULL, 23 | "apptId" INTEGER NOT NULL, 24 | "sender" TEXT NOT NULL, 25 | "message" TEXT NOT NULL, 26 | "time" TIMESTAMP(3) NOT NULL, 27 | 28 | CONSTRAINT "Message_pkey" PRIMARY KEY ("id") 29 | ); 30 | 31 | -- AddForeignKey 32 | ALTER TABLE "Video" ADD CONSTRAINT "Video_apptId_fkey" FOREIGN KEY ("apptId") REFERENCES "Appointment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 33 | 34 | -- AddForeignKey 35 | ALTER TABLE "Message" ADD CONSTRAINT "Message_apptId_fkey" FOREIGN KEY ("apptId") REFERENCES "Appointment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 36 | -------------------------------------------------------------------------------- /app/web/src/app/user/change_password/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { getLoggedInUser } from "@app/actions"; 17 | import ChangePasswordForm from "@components/user/ChangePasswordForm"; 18 | import { Metadata } from "next"; 19 | import { redirect } from "next/navigation"; 20 | 21 | export const metadata: Metadata = { 22 | title: "Change Password", 23 | }; 24 | 25 | export default async function UserDashboardPage() { 26 | const user = await getLoggedInUser(); 27 | 28 | if (!user) { 29 | redirect("/login"); 30 | } 31 | 32 | return ; 33 | } 34 | -------------------------------------------------------------------------------- /app/web/src/components/auth/button/LogoutButton.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | "use client"; 18 | 19 | import LoadingButton from "@components/form/LoadingButton"; 20 | import { signOut } from "next-auth/react"; 21 | 22 | interface LogoutButtonProps { 23 | text?: string; 24 | } 25 | 26 | export const LogoutButton = ({ text }: LogoutButtonProps) => { 27 | return ( 28 | signOut({ callbackUrl: "/api/auth/logout" })} 30 | className="auth-button" 31 | > 32 | {text ?? `Sign out`} 33 | 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /app/video-processing/deprecated/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright [2023] [Privacypal Authors] 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | set -e 18 | 19 | export PRIVACYPAL_INPUT_VIDEO_DIR=${PRIVACYPAL_INPUT_VIDEO_DIR:-/opt/privacypal/input_videos} 20 | export PRIVACYPAL_OUTPUT_VIDEO_DIR=${PRIVACYPAL_OUTPUT_VIDEO_DIR:-/opt/privacypal/output_videos} 21 | 22 | if [ ! -d "$PRIVACYPAL_INPUT_VIDEO_DIR" ] || [ ! -d "$PRIVACYPAL_OUTPUT_VIDEO_DIR" ]; then 23 | echo "[SEVERE][$(date)]: $PRIVACYPAL_INPUT_VIDEO_DIR and $PRIVACYPAL_OUTPUT_VIDEO_DIR must exist." 24 | exit 1 25 | fi 26 | 27 | exec python3 -m uvicorn --host $HOST --port $PORT server:app --lifespan on 28 | -------------------------------------------------------------------------------- /helm-charts/lintconf.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | braces: 3 | min-spaces-inside: 0 4 | max-spaces-inside: 0 5 | min-spaces-inside-empty: -1 6 | max-spaces-inside-empty: -1 7 | brackets: 8 | min-spaces-inside: 0 9 | max-spaces-inside: 0 10 | min-spaces-inside-empty: -1 11 | max-spaces-inside-empty: -1 12 | colons: 13 | max-spaces-before: 0 14 | max-spaces-after: 1 15 | commas: 16 | max-spaces-before: 0 17 | min-spaces-after: 1 18 | max-spaces-after: 1 19 | comments: 20 | require-starting-space: true 21 | min-spaces-from-content: 2 22 | document-end: disable 23 | document-start: disable # No --- to start a file 24 | empty-lines: 25 | max: 2 26 | max-start: 0 27 | max-end: 0 28 | hyphens: 29 | max-spaces-after: 1 30 | indentation: 31 | spaces: consistent 32 | indent-sequences: whatever # - list indentation will handle both indentation and without 33 | check-multi-line-strings: false 34 | key-duplicates: enable 35 | line-length: disable # Lines can be any length 36 | new-line-at-end-of-file: disable 37 | new-lines: 38 | type: unix 39 | trailing-spaces: enable 40 | truthy: 41 | level: warning 42 | -------------------------------------------------------------------------------- /app/web/src/app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import NextAuth from "next-auth"; 17 | import { NextRequest } from "next/server"; 18 | import { cognitoConfig } from "src/auth"; 19 | 20 | export const dynamic = "force-dynamic"; 21 | export const revalidate = 0; 22 | 23 | // `res` is supposedly of type RouteHandlerContext but no module we have exports 24 | // a type like that so i'm just leaving it like this 25 | const handler = async (req: NextRequest, res: any) => { 26 | return NextAuth(req, res, cognitoConfig(req)); 27 | }; 28 | 29 | export { handler as GET, handler as POST }; 30 | -------------------------------------------------------------------------------- /app/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/node:18-alpine AS base 2 | 3 | USER root 4 | 5 | # Reference: https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine 6 | RUN apk add --no-cache libc6-compat 7 | 8 | # Disable Next.js telemetry during build and runtime. 9 | # Reference: https://nextjs.org/telemetry 10 | ENV NEXT_TELEMETRY_DISABLED 1 11 | 12 | FROM base AS builder 13 | 14 | WORKDIR /app 15 | 16 | COPY package.json package-lock.json ./ 17 | RUN npm ci 18 | 19 | COPY . . 20 | RUN npm run prisma:generate 21 | RUN npm run build 22 | 23 | FROM base AS runner 24 | 25 | USER root 26 | 27 | RUN adduser --system --ingroup root --uid 1001 nextjs 28 | 29 | WORKDIR /app 30 | 31 | # Set the correct permission for prerender cache 32 | RUN mkdir .next && chown nextjs .next 33 | 34 | # Automatically leverage output traces to reduce image size 35 | # https://nextjs.org/docs/advanced-features/output-file-tracing 36 | COPY --from=builder --chown=nextjs /app/.next/standalone ./ 37 | COPY --from=builder --chown=nextjs /app/.next/static ./.next/static 38 | 39 | USER 1001 40 | 41 | EXPOSE 8080 42 | 43 | ENV NODE_ENV production 44 | ENV PORT 8080 45 | ENV HOSTNAME "0.0.0.0" 46 | 47 | CMD ["node", "server.js"] 48 | -------------------------------------------------------------------------------- /app/web/__tests__/base64.lib.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { base64ToUtf8, utf8ToBase64 } from "@lib/base64"; 18 | 19 | describe("base64ToUtf8", () => { 20 | it("should convert base64 to utf8", () => { 21 | const base64 = "SGVsbG8gV29ybGQ="; 22 | const utf8 = "Hello World"; 23 | expect(base64ToUtf8(base64)).toBe(utf8); 24 | }); 25 | }); 26 | 27 | describe("utf8ToBase64", () => { 28 | it("should convert utf8 to base64", () => { 29 | const base64 = "SGVsbG8gV29ybGQ="; 30 | const utf8 = "Hello World"; 31 | expect(utf8ToBase64(utf8)).toBe(base64); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /app/web/__tests__/time.lib.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { timeStampUTC } from "@lib/time"; 18 | 19 | describe("timeStampUTC", () => { 20 | it("should return a string in the form T", () => { 21 | const result = timeStampUTC(); 22 | const regex = /^\d{8}T\d{6}$/; 23 | expect(regex.test(result)).toBe(true); 24 | }); 25 | 26 | it("should return the current time in UTC", () => { 27 | const control = new Date("2023-10-26T00:00:00.000Z"); 28 | const result = timeStampUTC(control); 29 | const controlUTC = "20231026T000000"; 30 | expect(result).toBe(controlUTC); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /app/web/src/app/user/layout.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getLoggedInUser } from "@app/actions"; 18 | import { Metadata } from "next"; 19 | 20 | export async function generateMetadata(): Promise { 21 | const user = await getLoggedInUser(); 22 | 23 | return { 24 | title: { 25 | template: `%s | ${user?.username} | PrivacyPal`, 26 | default: `User Area | ${user?.username}`, 27 | }, 28 | }; 29 | } 30 | 31 | interface UserLayoutProps { 32 | children?: React.ReactNode; 33 | } 34 | 35 | export default async function UserLayout({ children }: UserLayoutProps) { 36 | return <>{children}; 37 | } 38 | -------------------------------------------------------------------------------- /app/web/src/app/profile/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import Content from "@components/layout/Content"; 17 | import { ProfileDetails } from "@components/profile/ProfileDetails"; 18 | import { auth } from "src/auth"; 19 | import { Metadata } from "next"; 20 | 21 | export const metadata: Metadata = { 22 | title: "Profile Detail", 23 | }; 24 | 25 | export default async function UserDashboardPage() { 26 | const session = await auth(); 27 | 28 | if (!session) { 29 | return Not logged in; 30 | } 31 | 32 | return ( 33 | 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /app/web/src/lib/lambda.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { 18 | LambdaClient, 19 | GetFunctionCommand, 20 | GetFunctionCommandOutput, 21 | } from "@aws-sdk/client-lambda"; 22 | 23 | const client = new LambdaClient(); 24 | 25 | export async function testLambdaAvailability(fnName: string): Promise { 26 | const command = new GetFunctionCommand({ 27 | FunctionName: fnName, 28 | }); 29 | try { 30 | const response: GetFunctionCommandOutput = await client.send(command); 31 | return response.Configuration?.FunctionName === fnName; 32 | } catch (err) { 33 | console.warn(err); 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/web/src/app/api/video/upload/README.md: -------------------------------------------------------------------------------- 1 | # Video Upload API 2 | 3 | Reachable at: `/api/video/upload/` 4 | 5 | ## Allowed Methods 6 | 7 | - `POST` 8 | 9 | ## Expects 10 | 11 | - `file`: The video file to upload as a `multipart/form-data` file. 12 | - `blurFaces`: a string indicating if the user wants to blur their face or not ("true" or "false") 13 | - `regions`: a json string of the form: 14 | ```json 15 | [ 16 | { 17 | "origin": [ 0, 0 ], 18 | "width": 40, 19 | "height": 50 20 | }, 21 | { 22 | "origin": [ 10, 10 ], 23 | "width": 50, 24 | "height": 100 25 | } 26 | ] 27 | ``` 28 | Where `origin[0]`, `origin[1]` is the x, y coordinates of the top left corner of the region. 29 | - `apptId`: Appointment ID. 30 | - `Cookie`: Include cookie in request header. Get cookie from browser storage after logging in using UI. Example: `privacypal=` 31 | 32 | ## Returns 33 | 34 | Encoding: 35 | 36 | - `application/json` 37 | 38 | Upload success: 39 | 40 | ```json 41 | { 42 | "data": { 43 | "success": true, 44 | "filePath": "testuser1-ngan-test-20240222T075030.mp4" 45 | } 46 | } 47 | ``` 48 | 49 | Upload failure: 50 | 51 | ```json 52 | { 53 | "data": { 54 | "success": false 55 | } 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /app/web/src/app/profile/update/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import Content from "@components/layout/Content"; 17 | import UserUpdateForm from "@components/user/UserUpdateForm"; 18 | import { Metadata } from "next"; 19 | import { auth } from "src/auth"; 20 | 21 | export const metadata: Metadata = { 22 | title: "Update Your Account", 23 | }; 24 | 25 | export default async function UserDashboardPage() { 26 | const session = await auth(); 27 | 28 | if (!session) { 29 | return Not logged in; 30 | } 31 | 32 | return ( 33 | 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /app/web/src/components/form/Hint.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { CSS } from "@lib/utils"; 17 | import { Text } from "@patternfly/react-core"; 18 | 19 | interface HintProps { 20 | message: string; 21 | italic?: boolean; 22 | style?: CSS; 23 | } 24 | 25 | export const Hint = ({ message, italic = false, style }: HintProps) => { 26 | return ( 27 | 36 | {message} 37 | 38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /app/web/src/components/form/LinkButton.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { Button } from "@patternfly/react-core"; 18 | import Link from "next/link"; 19 | 20 | interface LinkButtonProps { 21 | href: string; 22 | label: string; 23 | loading?: boolean; 24 | } 25 | 26 | export const LinkButton = ({ 27 | href, 28 | label, 29 | loading = false, 30 | }: LinkButtonProps) => { 31 | return ( 32 | 42 | ); 43 | }; 44 | 45 | export default LinkButton; 46 | -------------------------------------------------------------------------------- /app/video-processing/lambda/resources/sample_event.json: -------------------------------------------------------------------------------- 1 | { 2 | "Records": [ 3 | { 4 | "eventVersion": "2.0", 5 | "eventSource": "aws:s3", 6 | "awsRegion": "ca-central-1", 7 | "eventTime": "2024-01-01T00:00:00.000Z", 8 | "eventName": "ObjectCreated:Put", 9 | "userIdentity": { 10 | "principalId": "EXAMPLE" 11 | }, 12 | "requestParameters": { 13 | "sourceIPAddress": "127.0.0.1" 14 | }, 15 | "responseElements": { 16 | "x-amz-request-id": "EXAMPLE123456789", 17 | "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH" 18 | }, 19 | "s3": { 20 | "s3SchemaVersion": "1.0", 21 | "configurationId": "testConfigRule", 22 | "bucket": { 23 | "name": "input-video-bucket", 24 | "ownerIdentity": { 25 | "principalId": "EXAMPLE" 26 | }, 27 | "arn": "arn:aws:s3:::input-video-bucket" 28 | }, 29 | "object": { 30 | "key": "username-recorded-20240223T193522%2Emp4", 31 | "size": 1024, 32 | "eTag": "0123456789abcdef0123456789abcdef", 33 | "sequencer": "0A1B2C3D4E5F678901" 34 | } 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /app/video-conversion/lambda/resources/sample_event.json: -------------------------------------------------------------------------------- 1 | { 2 | "Records": [ 3 | { 4 | "eventVersion": "2.0", 5 | "eventSource": "aws:s3", 6 | "awsRegion": "ca-central-1", 7 | "eventTime": "2024-01-01T00:00:00.000Z", 8 | "eventName": "ObjectCreated:Put", 9 | "userIdentity": { 10 | "principalId": "EXAMPLE" 11 | }, 12 | "requestParameters": { 13 | "sourceIPAddress": "127.0.0.1" 14 | }, 15 | "responseElements": { 16 | "x-amz-request-id": "EXAMPLE123456789", 17 | "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH" 18 | }, 19 | "s3": { 20 | "s3SchemaVersion": "1.0", 21 | "configurationId": "testConfigRule", 22 | "bucket": { 23 | "name": "input-video-bucket", 24 | "ownerIdentity": { 25 | "principalId": "EXAMPLE" 26 | }, 27 | "arn": "arn:aws:s3:::input-video-bucket" 28 | }, 29 | "object": { 30 | "key": "username-recorded-20240223T193522%2Ewebm", 31 | "size": 1024, 32 | "eTag": "0123456789abcdef0123456789abcdef", 33 | "sequencer": "0A1B2C3D4E5F678901" 34 | } 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /app/web/src/app/staff/appointments/manage/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getLoggedInUser } from "@app/actions"; 18 | import { redirect } from "next/navigation"; 19 | import AppointmentManagementList from "@components/appointment/AppointmentManagementList"; 20 | import { UserRole } from "@lib/userRole"; 21 | import Content from "@components/layout/Content"; 22 | 23 | export default async function ViewAppointmentDetailsForm() { 24 | const user = await getLoggedInUser(); 25 | if (!user || user.role !== UserRole.PROFESSIONAL) redirect("/login"); 26 | 27 | return ( 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /app/web/src/components/layout/Content.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { CSS } from "@lib/utils"; 17 | 18 | const contentStyles: CSS = { 19 | width: "100%", 20 | padding: "1rem 3.5vw", 21 | display: "flex", 22 | flexDirection: "column", 23 | justifyContent: "flex-start", 24 | alignItems: "center", 25 | gap: "0.5rem", 26 | position: "relative", 27 | }; 28 | 29 | interface ContentProps { 30 | style?: CSS; 31 | children?: React.ReactNode; 32 | } 33 | 34 | export default async function Content({ style, children }: ContentProps) { 35 | return ( 36 |
37 | {children} 38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /app/web/src/components/welcome/GifImage.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import React from "react"; 17 | import { CSS } from "@lib/utils"; 18 | import gifimage from "@assets/welcome.gif"; 19 | import Image from "next/image"; 20 | 21 | const gifContainerStyle: CSS = { 22 | position: "relative", 23 | minWidth: "30rem", 24 | }; 25 | 26 | const GifImage: React.FC = () => { 27 | return ( 28 |
29 | Background 36 |
37 | ); 38 | }; 39 | 40 | export default GifImage; 41 | -------------------------------------------------------------------------------- /app/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "rootDir": ".", 5 | "target": "es5", 6 | "lib": ["dom", "es2020"], 7 | "allowJs": true, 8 | "skipLibCheck": true, 9 | "strict": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noImplicitAny": true, 17 | "jsx": "preserve", 18 | "incremental": true, 19 | "types": ["jest"], 20 | "plugins": [ 21 | { 22 | "name": "next" 23 | } 24 | ], 25 | "paths": { 26 | "@app/*": ["./src/app/*"], 27 | "@components/*": ["./src/components/*"], 28 | "@lib/*": ["./src/lib/*"], 29 | "@assets/*": ["./src/assets/*"], 30 | "@patternfly/assets/*": [ 31 | "node_modules/@patternfly/react-core/dist/styles/assets/*" 32 | ], 33 | "@conf/*": ["./conf/*"], 34 | "@public/*": ["./public/*"] 35 | } 36 | }, 37 | "include": ["next-env.d.ts", "types/**/*.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 38 | "exclude": ["node_modules", "cypress.config.ts", "cypress"], 39 | "ts-node": { 40 | "compilerOptions": { 41 | "module": "esnext", 42 | "moduleResolution": "node" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/video-processing/lambda/resources/username-recorded-20240223T193522.mp4: -------------------------------------------------------------------------------- 1 | { 2 | "Records": [ 3 | { 4 | "eventVersion": "2.0", 5 | "eventSource": "aws:s3", 6 | "awsRegion": "ca-central-1", 7 | "eventTime": "2024-01-01T00:00:00.000Z", 8 | "eventName": "ObjectCreated:Put", 9 | "userIdentity": { 10 | "principalId": "EXAMPLE" 11 | }, 12 | "requestParameters": { 13 | "sourceIPAddress": "127.0.0.1" 14 | }, 15 | "responseElements": { 16 | "x-amz-request-id": "EXAMPLE123456789", 17 | "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH" 18 | }, 19 | "s3": { 20 | "s3SchemaVersion": "1.0", 21 | "configurationId": "testConfigRule", 22 | "bucket": { 23 | "name": "input-video-bucket", 24 | "ownerIdentity": { 25 | "principalId": "EXAMPLE" 26 | }, 27 | "arn": "arn:aws:s3:::input-video-bucket" 28 | }, 29 | "object": { 30 | "key": "username-recorded-20240223T193522%2Emp4", 31 | "size": 1024, 32 | "eTag": "0123456789abcdef0123456789abcdef", 33 | "sequencer": "0A1B2C3D4E5F678901" 34 | } 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /app/web/src/components/layout/BackgroundImageBasic.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import React from "react"; 17 | import Image from "next/image"; 18 | import background from "@assets/background.svg"; 19 | import { CSS } from "@lib/utils"; 20 | 21 | const containerStyle: CSS = { 22 | width: "100%", 23 | height: "100%", 24 | overflow: "hidden", 25 | position: "fixed", 26 | top: 0, 27 | left: 0, 28 | zIndex: -1, 29 | }; 30 | 31 | export const BackgroundImageBasic: React.FunctionComponent = () => { 32 | return ( 33 |
34 | Background 40 |
41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /app/web/cypress/e2e/logout.cy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | describe("Logout page", () => { 17 | beforeEach(() => {}); 18 | 19 | it("should redirect a logged out user to login", () => { 20 | cy.visit("/logout"); 21 | cy.wait(250); 22 | cy.url().should("include", "/login"); 23 | }); 24 | 25 | it("should clear a user session", () => { 26 | cy.visit("/login"); 27 | cy.get("input[name=email]").type("johnny@example.com"); 28 | cy.get("input[name=password]").type("password"); 29 | cy.get("button[type=submit]").click(); 30 | cy.wait(250); 31 | cy.url().should("match", /\/$/); 32 | cy.visit("/logout"); 33 | cy.wait(250); 34 | cy.visit("/user/dashboard"); 35 | cy.wait(500); 36 | cy.url().should("include", "/login"); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /app/web/src/app/staff/appointments/new/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getLoggedInUser } from "@app/actions"; 18 | import Content from "@components/layout/Content"; 19 | import { NewAppointmentForm } from "@components/staff/NewAppointmentForm"; 20 | import { UserRole } from "@lib/userRole"; 21 | import { Metadata } from "next"; 22 | import { redirect } from "next/navigation"; 23 | 24 | export const metadata: Metadata = { 25 | title: "New Appointment", 26 | }; 27 | 28 | export default async function NewAppointmentPage() { 29 | const user = await getLoggedInUser(); 30 | 31 | if (!user || user.role != UserRole.PROFESSIONAL) { 32 | redirect("/login"); 33 | } 34 | 35 | return ( 36 | 37 | 38 | 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /app/web/src/app/user/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import LinkButton from "@components/form/LinkButton"; 18 | import Content from "@components/layout/Content"; 19 | import { CSS } from "@lib/utils"; 20 | import React from "react"; 21 | 22 | const buttonsStyles: CSS = { 23 | display: "flex", 24 | flexDirection: "column", 25 | gap: "0.5rem", 26 | justifyContent: "flex-start", 27 | alignItems: "center", 28 | padding: "1rem", 29 | }; 30 | 31 | export default async function UserPage() { 32 | return ( 33 | 34 |
35 | 36 | 37 |
38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /app/web/src/app/api/auth/logout/route.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { NextRequest, NextResponse } from "next/server"; 18 | import { authManager } from "src/auth"; 19 | 20 | const clientId = process.env.COGNITO_CLIENT || ""; 21 | const region = process.env.AWS_REGION || ""; 22 | 23 | export const dynamic = "force-dynamic"; 24 | export const revalidate = 0; 25 | 26 | export async function GET(req: NextRequest) { 27 | let redirectURL: string; 28 | if (authManager == "basic") { 29 | redirectURL = process.env.NEXTAUTH_URL || "http://localhost:3000"; 30 | } else { 31 | redirectURL = `https://privacypal.auth.${region}.amazoncognito.com/logout?client_id=${clientId}&response_type=code&logout_uri=${process.env.NEXTAUTH_URL}`; 32 | } 33 | return NextResponse.redirect(redirectURL); 34 | } 35 | -------------------------------------------------------------------------------- /app/web/types/next-auth.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { StringAttributeConstraintsType } from "@aws-sdk/client-cognito-identity-provider"; 17 | import NextAuth from "next-auth"; 18 | import { JWT } from "next-auth/jwt"; 19 | 20 | declare module "next-auth/jwt" { 21 | interface JWT { 22 | isNewUser: boolean; 23 | changePassChallenge?: { 24 | name: string; 25 | session: string; 26 | userIdForSRP: string; 27 | }; 28 | user?: CognitoProfile; 29 | } 30 | } 31 | declare module "next-auth" { 32 | interface Session { 33 | accessToken: string; 34 | user: User; 35 | } 36 | interface User { 37 | id: string | number; 38 | username: string; 39 | role?: Role; 40 | firstName: string; 41 | lastName: string; 42 | email: string; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/web/jest.config.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright [2023] [Privacypal Authors] 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | import nextJest from "next/jest.js"; 17 | 18 | const createJestConfig = nextJest({ 19 | // Provide the path to your Next.js app to load next.config.js and .env files in your test environment 20 | dir: "./", 21 | }); 22 | 23 | // Add any custom config to be passed to Jest 24 | /** @type {import('jest').Config} */ 25 | const config = { 26 | // Add more setup options before each test is run 27 | // setupFilesAfterEnv: ['/jest.setup.js'], 28 | setupFiles: ["/jest.setup.js"], 29 | preset: "ts-jest", 30 | testEnvironment: "jest-environment-jsdom", 31 | testPathIgnorePatterns: ["/node_modules/", "/db"], 32 | }; 33 | 34 | // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async 35 | export default createJestConfig(config); 36 | -------------------------------------------------------------------------------- /app/web/src/app/profile/[withUser]/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { OtherUserProfileDetails } from "@components/profile/OtherUserProfileDetails"; 18 | import React from "react"; 19 | import { auth } from "src/auth"; 20 | import { Metadata } from "next"; 21 | import Content from "@components/layout/Content"; 22 | 23 | export const metadata: Metadata = { 24 | title: "Other User Profile Detail", 25 | }; 26 | 27 | export default async function OtherUserProfilePage({ 28 | params, 29 | }: { 30 | params: { withUser: string }; 31 | }) { 32 | const session = await auth(); 33 | if (!session) { 34 | return Not logged in; 35 | } 36 | return ( 37 | 38 | 39 | 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /app/web/src/app/staff/appointments/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getAppointmentMetadata, getLoggedInUser } from "@app/actions"; 18 | import { Metadata } from "next"; 19 | import { AppointmentInbox } from "@components/appointment/inbox/AppointmentInbox"; 20 | import Content from "@components/layout/Content"; 21 | 22 | export const metadata: Metadata = { 23 | title: "Appointments", 24 | }; 25 | 26 | export default async function StaffAppointmentPage() { 27 | const loggedInUser = await getLoggedInUser(); 28 | 29 | if (!loggedInUser) { 30 | return User not logged in.; 31 | } 32 | 33 | const appointmentsMetadata = await getAppointmentMetadata(loggedInUser); 34 | 35 | return ( 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /app/web/cypress/e2e/home.cy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | describe("Home page", () => { 17 | beforeEach(() => { 18 | cy.visit("/"); 19 | }); 20 | 21 | it("should display the home page", () => { 22 | cy.get("h1").contains("PRIVACYPAL"); 23 | }); 24 | 25 | it("should contain a sign in button", () => { 26 | const signInButton = cy.get("a[href='#signin']"); 27 | signInButton.should("exist"); 28 | signInButton.should("contain", "Sign in"); 29 | }); 30 | 31 | it("should contain a sign up button", () => { 32 | const signUpButton = cy.get("a[href='/signup']"); 33 | signUpButton.should("exist"); 34 | signUpButton.should("contain", "Sign up"); 35 | }); 36 | 37 | it("should contain a link to GitHub", () => { 38 | cy.get("a[href^='https://github.com']").should("exist"); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /app/web/src/app/login/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { PalLoginForm } from "@components/auth/LoginForm"; 17 | import Content from "@components/layout/Content"; 18 | import { getUserHubSlug } from "@lib/utils"; 19 | import { Metadata } from "next"; 20 | import { redirect } from "next/navigation"; 21 | import React, { Suspense } from "react"; 22 | import { auth } from "src/auth"; 23 | 24 | export const dynamic = "force-dynamic"; 25 | 26 | export const metadata: Metadata = { 27 | title: "Login", 28 | }; 29 | 30 | export default async function LoginPage() { 31 | const session = await auth(); 32 | if (session) { 33 | redirect(getUserHubSlug(session.user)); 34 | } 35 | 36 | return ( 37 | 38 | 39 | 40 | 41 | 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /app/web/src/app/api/submitFeedback/route.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { JSONResponse } from "@lib/response"; 17 | import { NextRequest, NextResponse } from "next/server"; 18 | import { sendFeedbackEmail } from "@lib/ses"; 19 | 20 | export const POST = async (req: NextRequest) => { 21 | const { email, feedback } = await req.json(); 22 | const noreplyEmail = process.env.NOREPLY_EMAIL; 23 | 24 | if (!noreplyEmail) { 25 | return Response.json({ 26 | status: 400, 27 | message: "Sender email is not defined.", 28 | }); 29 | } 30 | 31 | try { 32 | await sendFeedbackEmail(noreplyEmail, email, feedback); 33 | return Response.json({ status: 200, message: "Email sent successfully." }); 34 | } catch (error) { 35 | return Response.json({ status: 500, message: "Failed to send email." }); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /app/web/src/components/layout/PrivacyPalLogo.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | 18 | import Image from "next/image"; 19 | import logo_dark from "@assets/dark_logo_no_name.png"; 20 | import logo_light from "@assets/light_logo_no_name.png"; 21 | import { CSS } from "@lib/utils"; 22 | 23 | interface PrivacyPalLogoProps { 24 | w?: number; 25 | h?: number; 26 | className?: string; 27 | style?: CSS; 28 | dark?: boolean; 29 | } 30 | 31 | export default function PrivacyPalLogo({ 32 | w, 33 | h, 34 | className, 35 | style, 36 | dark = true, 37 | }: PrivacyPalLogoProps) { 38 | return ( 39 | PrivacyPal Shield Logo 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /app/web/src/lib/ses.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses"; 17 | import config from "next/config"; 18 | 19 | export async function sendFeedbackEmail( 20 | noreplyEmail: string, 21 | email: string, 22 | feedback: string, 23 | ) { 24 | const client = new SESClient(config); 25 | 26 | const input = { 27 | Source: noreplyEmail, 28 | Destination: { 29 | ToAddresses: [noreplyEmail], 30 | }, 31 | Message: { 32 | Subject: { 33 | Data: `PrivacyPal: New Feedback from ${email}`, 34 | }, 35 | Body: { 36 | Text: { 37 | Data: `Feedback from ${email}:\n\n${feedback}`, 38 | }, 39 | }, 40 | }, 41 | }; 42 | const command = new SendEmailCommand(input); 43 | const response = await client.send(command); 44 | 45 | return response; 46 | } 47 | -------------------------------------------------------------------------------- /app/web/src/components/CustomAvatar.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { Avatar } from "@patternfly/react-core"; 17 | import avatarImg from "@assets/pf_avatar.svg"; 18 | 19 | interface CustomAvatarProps { 20 | firstName?: string; 21 | lastName?: string; 22 | size?: "sm" | "md" | "lg" | "xl"; 23 | className?: string; 24 | style?: any; 25 | } 26 | export default function CustomAvatar({ 27 | firstName, 28 | lastName, 29 | size, 30 | className, 31 | style, 32 | }: CustomAvatarProps) { 33 | const avatarLink = 34 | firstName && lastName 35 | ? `https://ui-avatars.com/api/?background=random&name=${firstName}+${lastName}` 36 | : avatarImg.src; 37 | return ( 38 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /app/web/src/components/layout/NavButton.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | import { useRouter } from "next/navigation"; 18 | import React from "react"; 19 | 20 | interface NavButtonProps { 21 | href: string; 22 | label: string; 23 | style?: React.CSSProperties; 24 | } 25 | 26 | const buttonStyle = { 27 | background: "none", 28 | border: "none", 29 | padding: "1rem", 30 | font: "inherit", 31 | cursor: "pointer", 32 | color: "black", 33 | fontWeight: "bold", 34 | }; 35 | 36 | export default function NavButton({ href, label, style }: NavButtonProps) { 37 | const router = useRouter(); 38 | 39 | return ( 40 | <> 41 | 48 | 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /app/web/src/components/layout/AppointmentBackground.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import React from "react"; 17 | import background from "@assets/appointment_background.png"; 18 | import { BackgroundImage } from "@patternfly/react-core"; 19 | import { CSS } from "@lib/utils"; 20 | 21 | const backgroundImageContainerStyle: CSS = { 22 | width: "100%", 23 | height: "100%", 24 | position: "fixed", 25 | zIndex: 2, 26 | margin: 0, 27 | display: "flex", 28 | justifyContent: "center", 29 | alignItems: "center", 30 | }; 31 | 32 | const backgroundImageStyle: CSS = { 33 | width: "100%", 34 | height: "100%", 35 | objectFit: "cover", 36 | }; 37 | 38 | export const BackgroundImageBasic: React.FunctionComponent = () => ( 39 |
40 | Background 41 |
42 | ); 43 | -------------------------------------------------------------------------------- /app/video-processing/deprecated/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/g 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Environments 63 | .env 64 | .venv 65 | env/ 66 | venv/ 67 | ENV/ 68 | env.bak/ 69 | venv.bak/ 70 | 71 | # Python mode for VIM 72 | .ropeproject 73 | **/.ropeproject 74 | 75 | # Vim swap files 76 | **/*.swp 77 | 78 | # VS Code 79 | .vscode/ 80 | 81 | # Video diectory 82 | *videos/ 83 | 84 | # Taskfile 85 | .task 86 | 87 | # Logs 88 | **/*.log 89 | 90 | # Exlude samples 91 | !/samples/*.mp4 92 | !/samples/*.jpg 93 | 94 | # Makefile-win 95 | Makefile-win 96 | -------------------------------------------------------------------------------- /app/smoketest/compose/privacypal.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | privacypal: 5 | image: ghcr.io/cosc-499-w2023/privacypal:0.1.0 6 | build: ../../web/ 7 | pull_policy: build 8 | depends_on: 9 | db-init: 10 | condition: service_completed_successfully 11 | networks: 12 | - backend 13 | hostname: privacypal 14 | expose: 15 | - 8080 16 | ports: 17 | - "8080:8080" 18 | environment: 19 | PORT: 8080 20 | AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} 21 | AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} 22 | AWS_SESSION_TOKEN: ${AWS_SESSION_TOKEN} 23 | COGNITO_CLIENT: ${COGNITO_CLIENT} 24 | COGNITO_CLIENT_SECRET: ${COGNITO_CLIENT_SECRET} 25 | COGNITO_POOL_ID: ${COGNITO_POOL_ID} 26 | AWS_REGION: ca-central-1 27 | PRIVACYPAL_AUTH_MANAGER: cognito 28 | PRIVACYPAL_AUTH_SECRET: NZFbGxlrFl5Ae2kh0pcKbsiNVL37eEvtSg4zunBpfmw= 29 | PRIVACYPAL_PROCESSOR_LAMBDA: processVideoContainer 30 | PRIVACYPAL_CONVERSION_LAMBDA: mediaConvert 31 | PRIVACYPAL_OUTPUT_BUCKET: privacypal-output 32 | PRIVACYPAL_TMP_BUCKET: privacypal-input 33 | NEXTAUTH_URL: http://localhost:8080 34 | PRIVACYPAL_POSTGRES_USERNAME: privacypal 35 | PRIVACYPAL_POSTGRES_PASSWORD: password 36 | PRIVACYPAL_POSTGRES_HOST: db 37 | PRIVACYPAL_POSTGRES_PORT: 5432 38 | PRIVACYPAL_POSTGRES_DATABASE: privacypal 39 | NOREPLY_EMAIL: no-reply@privacypal.awsapps.com 40 | restart: unless-stopped 41 | 42 | networks: 43 | backend: 44 | -------------------------------------------------------------------------------- /app/web/src/app/staff/layout.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import Content from "@components/layout/Content"; 18 | 19 | import { getLoggedInUser } from "@app/actions"; 20 | import { Metadata } from "next"; 21 | 22 | export async function generateMetadata(): Promise { 23 | const user = await getLoggedInUser(); 24 | 25 | return { 26 | title: { 27 | template: `%s | ${user?.username} | PrivacyPal`, 28 | default: `Staff Area | ${user?.username}`, 29 | }, 30 | }; 31 | } 32 | 33 | interface StaffAreaLayoutProps { 34 | children?: React.ReactNode; 35 | } 36 | 37 | export default async function StaffAreaLayout({ 38 | children, 39 | }: StaffAreaLayoutProps) { 40 | return <>{children}; // if this line is removed, the staff appointment inbox at /staff/appointments will be squished to the center of the screen 41 | // return {children}; 42 | } 43 | -------------------------------------------------------------------------------- /app/web/src/lib/db.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { PrismaClient } from "@prisma/client"; 17 | 18 | const prismaClientSingleton = () => { 19 | const userName = process.env.PRIVACYPAL_POSTGRES_USERNAME; 20 | const host = process.env.PRIVACYPAL_POSTGRES_HOST; 21 | const port = process.env.PRIVACYPAL_POSTGRES_PORT; 22 | const database = process.env.PRIVACYPAL_POSTGRES_DATABASE; 23 | const password = process.env.PRIVACYPAL_POSTGRES_PASSWORD; 24 | 25 | return new PrismaClient({ 26 | datasources: { 27 | db: { 28 | url: `postgresql://${userName}:${password}@${host}:${port}/${database}`, 29 | }, 30 | }, 31 | }); 32 | }; 33 | 34 | type PrismaClientSingleton = ReturnType; 35 | 36 | const globalForPrisma = globalThis as unknown as { 37 | prisma: PrismaClientSingleton | undefined; 38 | }; 39 | 40 | const prisma = globalForPrisma.prisma ?? prismaClientSingleton(); 41 | 42 | export default prisma; 43 | -------------------------------------------------------------------------------- /app/web/cypress/e2e/staff/staff.cy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | describe("Staff page rendering", () => { 17 | beforeEach(() => { 18 | cy.visit("/staff"); 19 | cy.wait(250); 20 | cy.get("input[name=email]").type("johnny@example.com"); 21 | cy.get("input[name=password]").type("password"); 22 | cy.get("button[type=submit]").click(); 23 | cy.wait(250); 24 | }); 25 | 26 | it("Should show the staff page", () => { 27 | cy.get("main[aria-label='Staff-only page']"); 28 | }); 29 | 30 | it("Should show a sample list of users", () => { 31 | const usersList = cy.get("[aria-label='Example user list']"); 32 | usersList.should("exist"); 33 | usersList.get("h2").should("contain", "Users List"); 34 | }); 35 | }); 36 | 37 | describe("Staff page functionality", () => { 38 | it("Should redirect to /login if not logged in", () => { 39 | cy.visit("/staff"); 40 | cy.wait(250); 41 | cy.url().should("include", "/login"); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /app/web/src/app/staff/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import LinkButton from "@components/form/LinkButton"; 18 | import Content from "@components/layout/Content"; 19 | import { CSS } from "@lib/utils"; 20 | 21 | const buttonsStyles: CSS = { 22 | display: "flex", 23 | flexDirection: "column", 24 | gap: "0.5rem", 25 | justifyContent: "flex-start", 26 | alignItems: "center", 27 | padding: "1rem", 28 | }; 29 | 30 | export default function StaffPage() { 31 | return ( 32 | 33 |
34 | 35 | 36 | 40 | 41 |
42 |
43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/s3.yaml: -------------------------------------------------------------------------------- 1 | {{ $fullName := include "privacypal.fullname" . -}} 2 | --- 3 | apiVersion: s3.services.k8s.aws/v1alpha1 4 | kind: Bucket 5 | metadata: 6 | name: {{ $fullName }}-tmp 7 | labels: 8 | {{- include "privacypal.labels" . | nindent 4 }} 9 | spec: 10 | name: {{ .Release.Namespace }}-{{ $fullName }}-tmp 11 | tagging: 12 | tagSet: 13 | - key: component 14 | value: temporary 15 | notification: 16 | lambdaFunctionConfigurations: 17 | - id: ProcessVideo 18 | events: 19 | - s3:ObjectCreated:Put 20 | # Post-installation step to patch with ARN from Lambda status 21 | lambdaFunctionARN: arn:aws:lambda:ca-central-1:account-id:function:lambda-name 22 | filter: 23 | key: 24 | filterRules: 25 | - name: suffix 26 | value: ".mp4" 27 | - id: VideoConversion 28 | events: 29 | - s3:ObjectCreated:Put 30 | # Post-installation step to patch with ARN from Lambda status 31 | lambdaFunctionARN: arn:aws:lambda:ca-central-1:account-id:function:lambda-name 32 | filter: 33 | key: 34 | filterRules: 35 | - name: suffix 36 | value: ".webm" 37 | --- 38 | apiVersion: s3.services.k8s.aws/v1alpha1 39 | kind: Bucket 40 | metadata: 41 | name: {{ $fullName }}-videos 42 | labels: 43 | {{- include "privacypal.labels" . | nindent 4 }} 44 | spec: 45 | name: {{ .Release.Namespace }}-{{ $fullName }}-videos 46 | tagging: 47 | tagSet: 48 | - key: component 49 | value: persistent 50 | -------------------------------------------------------------------------------- /app/web/src/components/layout/BackButton.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | import { useRouter, usePathname } from "next/navigation"; 18 | import { AngleLeftIcon } from "@patternfly/react-icons"; 19 | import React from "react"; 20 | 21 | interface BackButtonProps { 22 | style?: React.CSSProperties; 23 | } 24 | 25 | const buttonStyle = { 26 | background: "none", 27 | border: "none", 28 | padding: "0", 29 | font: "inherit", 30 | cursor: "pointer", 31 | color: "black", 32 | fontWeight: "bold", 33 | }; 34 | 35 | export default function BackButton({ style }: BackButtonProps) { 36 | const router = useRouter(); 37 | const pathname = usePathname(); 38 | 39 | return ( 40 | <> 41 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /app/web/src/lib/time.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Returns the current time in UTC as a string in the form "T" 19 | */ 20 | export const timeStampUTC = (fromDate?: Date): string => { 21 | const date = fromDate ? fromDate : new Date(); 22 | const year = date.getUTCFullYear(); 23 | const month = date.getUTCMonth() + 1; 24 | const day = date.getUTCDate(); 25 | const hours = date.getUTCHours(); 26 | const minutes = date.getUTCMinutes(); 27 | const seconds = date.getUTCSeconds(); 28 | 29 | const yearString = year.toString(); 30 | const monthString = month.toString().padStart(2, "0"); 31 | const dayString = day.toString().padStart(2, "0"); 32 | const hoursString = hours.toString().padStart(2, "0"); 33 | const minutesString = minutes.toString().padStart(2, "0"); 34 | const secondsString = seconds.toString().padStart(2, "0"); 35 | 36 | return `${yearString}${monthString}${dayString}T${hoursString}${minutesString}${secondsString}`; 37 | }; 38 | -------------------------------------------------------------------------------- /app/smoketest/compose/README.md: -------------------------------------------------------------------------------- 1 | # Compose smoketests 2 | 3 | ## REQUIREMENTS 4 | 5 | - [Podman](https://podman.io/docs/installation) v4.7+ 6 | - [docker-compose](https://docs.docker.com/compose/install/standalone/) v2+ 7 | 8 | **Notes**: Alternatively, `docker` and `docker compose` plugin can be used. 9 | 10 | ## RUN 11 | 12 | ### Launch Podman API 13 | 14 | With `podman`, Podman API is required to work with `docker-compose`. Launch Podman API as a user service by running: 15 | 16 | 17 | ```bash 18 | systemctl --user enable --now podman.socket 19 | ``` 20 | 21 | Tell `docker-compose` about the API server: 22 | 23 | ```bash 24 | export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock 25 | ``` 26 | 27 | **Note:** Above steps are not required for `docker` usage. 28 | 29 | ### Configure AWS Credentials 30 | 31 | To export the credentials for the processing server, run: 32 | 33 | ```bash 34 | eval $(aws configure export-credentials --profile --format env) 35 | ``` 36 | 37 | 38 | ### Configure AWS Cognito 39 | 40 | The application requires Cognito connection information in order to authenticate users, set the following environment variables: 41 | 42 | ```bash 43 | export AWS_CLIENT= 44 | export AWS_CLIENT_SECRET= 45 | export AWS_POOL_ID= 46 | ``` 47 | 48 | Note: You can find these values in AWS Cognito console. 49 | 50 | ### Launch services 51 | 52 | To launch composed services, run: 53 | 54 | ```bash 55 | bash smoketest.sh 56 | ``` 57 | 58 | To keep the video volumes after canceling run, use the `KEEP_VOLUMES` environment variable: 59 | 60 | ```bash 61 | KEEP_VOLUMES=true bash smoketest.sh 62 | ``` 63 | -------------------------------------------------------------------------------- /app/web/src/components/form/SelectedItem.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | "use client"; 17 | import { CSS } from "@lib/utils"; 18 | import { Text } from "@patternfly/react-core"; 19 | import { CheckIcon, TimesIcon } from "@patternfly/react-icons"; 20 | 21 | const selectedItemStyle: CSS = { 22 | display: "flex", 23 | justifyContent: "center", 24 | alignItems: "center", 25 | gap: "0.5rem", 26 | }; 27 | 28 | interface SelectedItemProps { 29 | hide?: boolean; 30 | selected?: boolean; 31 | style?: CSS; 32 | children?: React.ReactNode; 33 | } 34 | 35 | export const SelectedItem = ({ 36 | hide, 37 | selected = true, 38 | style, 39 | children, 40 | }: SelectedItemProps) => { 41 | if (hide) { 42 | return null; 43 | } 44 | 45 | const icon = selected ? ( 46 | 47 | ) : ( 48 | 49 | ); 50 | 51 | return ( 52 | 53 | {icon} 54 | {children} 55 | 56 | ); 57 | }; 58 | -------------------------------------------------------------------------------- /helm-charts/charts/privacypal/templates/lambda.yaml: -------------------------------------------------------------------------------- 1 | {{ $fullName := include "privacypal.fullname" . -}} 2 | --- 3 | apiVersion: lambda.services.k8s.aws/v1alpha1 4 | kind: Function 5 | metadata: 6 | name: {{ $fullName }}-vidproc 7 | labels: 8 | {{- include "privacypal.labels" . | nindent 4 }} 9 | annotations: 10 | services.k8s.aws/region: ca-central-1 11 | spec: 12 | name: {{ .Release.Namespace }}-{{ $fullName }}-vidproc 13 | packageType: Image 14 | environment: 15 | variables: 16 | OUTPUT_BUCKET: {{ .Release.Namespace }}-{{ $fullName }}-videos 17 | {{- with .Values.lambda.videoProcessor }} 18 | code: 19 | imageURI: "{{ .image.repository }}:{{ .image.tag }}" 20 | role: {{ .iamRole }} 21 | description: Video processing Lambda to process videos submitted by users 22 | ephemeralStorage: 23 | size: {{ .ephemeralStorageSize }} 24 | memorySize: {{ .memorySize }} 25 | timeout: {{ .timeout }} 26 | {{- end }} 27 | --- 28 | apiVersion: lambda.services.k8s.aws/v1alpha1 29 | kind: Function 30 | metadata: 31 | name: {{ $fullName }}-vidconvert 32 | labels: 33 | {{- include "privacypal.labels" . | nindent 4 }} 34 | annotations: 35 | services.k8s.aws/region: ca-central-1 36 | spec: 37 | name: {{ .Release.Namespace }}-{{ $fullName }}-vidconvert 38 | packageType: Image 39 | {{- with .Values.lambda.videoConversion }} 40 | code: 41 | imageURI: "{{ .image.repository }}:{{ .image.tag }}" 42 | role: {{ .iamRole }} 43 | description: Video conversion Lambda to convert videos from webm to mp4 44 | ephemeralStorage: 45 | size: {{ .ephemeralStorageSize }} 46 | memorySize: {{ .memorySize }} 47 | timeout: {{ .timeout }} 48 | {{- end -}} 49 | -------------------------------------------------------------------------------- /app/web/src/components/layout/NotFoundContainer.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | "use client"; 18 | 19 | import { 20 | Button, 21 | EmptyState, 22 | EmptyStateActions, 23 | EmptyStateBody, 24 | EmptyStateFooter, 25 | EmptyStateHeader, 26 | EmptyStateIcon, 27 | } from "@patternfly/react-core"; 28 | import { MapMarkedAltIcon } from "@patternfly/react-icons"; 29 | 30 | export default function NotFound() { 31 | const handleClickHome = () => { 32 | window.location.href = "/"; 33 | }; 34 | 35 | return ( 36 | 37 | } 41 | /> 42 | 43 | Unfortunately, we couldn't find that page. 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/license-check.yaml: -------------------------------------------------------------------------------- 1 | name: License check 2 | 3 | concurrency: 4 | group: ${{ github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - "develop" 11 | - "master" 12 | - "main" 13 | pull_request: 14 | types: 15 | - opened 16 | - reopened 17 | - synchronize 18 | 19 | jobs: 20 | web-license: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Check out the repository 24 | uses: actions/checkout@v4 25 | with: 26 | token: ${{ github.token }} 27 | - name: Set up Node 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: '18' 31 | cache: 'npm' 32 | cache-dependency-path: app/web/package-lock.json 33 | - name: Install dependencies 34 | uses: bahmutov/npm-install@v1 35 | with: 36 | working-directory: app/web 37 | - name: Check license headers 38 | working-directory: app/web 39 | run: npm run license:check 40 | 41 | video-processing-lambda-license: 42 | runs-on: ubuntu-latest 43 | steps: 44 | - name: Check out the repository 45 | uses: actions/checkout@v4 46 | with: 47 | token: ${{ github.token }} 48 | - name: Check license headers 49 | working-directory: app/video-processing 50 | run: make check-license 51 | 52 | video-conversion-lambda-license: 53 | runs-on: ubuntu-latest 54 | steps: 55 | - name: Check out the repository 56 | uses: actions/checkout@v4 57 | with: 58 | token: ${{ github.token }} 59 | - name: Check license headers 60 | working-directory: app/video-conversion 61 | run: make check-license 62 | -------------------------------------------------------------------------------- /helm-charts/scripts/eks/aws_lb_controller_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | DIR="$(dirname $(readlink -f $0))" 6 | 7 | EKS_CLUSTER_NAME=${EKS_CLUSTER_NAME:-privacypal-qa} 8 | AWS_REGION=${AWS_REGION:-"ca-central-1"} 9 | 10 | # Create the IAM policy for the Load balancing controller 11 | # If you view the policy in the AWS Management Console, the console shows warnings for the ELB service, but not for the ELB v2 service. 12 | # This happens because some of the actions in the policy exist for ELB v2, but not for ELB. You can ignore the warnings for ELB. 13 | aws iam create-policy \ 14 | --policy-name AWSLoadBalancerControllerIAMPolicy \ 15 | --policy-document file://$DIR/aws_lb_controller_iam_policy.json 16 | 17 | ALB_CONTROLLER_IAM_POLICY_ARN="$(aws iam list-policies --query 'Policies[?PolicyName==`AWSLoadBalancerControllerIAMPolicy`].Arn' --output text)" 18 | 19 | # Create an IAM role with the above policy attached and a service account in namespace kube-system 20 | # for the AWS Load Balancing Controller 21 | eksctl create iamserviceaccount \ 22 | --cluster=$EKS_CLUSTER_NAME \ 23 | --namespace=kube-system \ 24 | --name=aws-load-balancer-controller \ 25 | --role-name AmazonEKSLoadBalancerControllerRole \ 26 | --attach-policy-arn=$ALB_CONTROLLER_IAM_POLICY_ARN \ 27 | --approve 28 | 29 | # Install the AWS Load Balancing Controller via Helm chart 30 | helm repo add eks https://aws.github.io/eks-charts 31 | helm repo update eks 32 | 33 | helm install aws-load-balancer-controller eks/aws-load-balancer-controller \ 34 | -n kube-system \ 35 | --set clusterName=$EKS_CLUSTER_NAME \ 36 | --set region=$AWS_REGION \ 37 | --set serviceAccount.create=false \ 38 | --set serviceAccount.name=aws-load-balancer-controller 39 | -------------------------------------------------------------------------------- /app/web/src/app/user/appointments/page.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getAppointmentMetadata, getLoggedInUser } from "@app/actions"; 18 | import { AppointmentInbox } from "@components/appointment/inbox/AppointmentInbox"; 19 | import Content from "@components/layout/Content"; 20 | import { Metadata } from "next"; 21 | 22 | export const metadata: Metadata = { 23 | title: "Appointments", 24 | }; 25 | 26 | export default async function UserAppointmentsPage() { 27 | const loggedInUser = await getLoggedInUser(); 28 | 29 | if (!loggedInUser) { 30 | return User not logged in.; 31 | } 32 | 33 | const appointmentsMetadata = await getAppointmentMetadata(loggedInUser); 34 | 35 | return ( 36 |
47 | 51 |
52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /app/web/src/app/api/video/count/route.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { getVideoCount } from "@app/actions"; 17 | import db from "@lib/db"; 18 | import { JSONResponse, JSONError } from "@lib/response"; 19 | import { NextRequest, NextResponse } from "next/server"; 20 | 21 | // GET /api/video/count?id=1 returns a JSON object with the 22 | // number of videos associated with the specified appointment id 23 | export async function GET(req: NextRequest) { 24 | const searchParams = req.nextUrl.searchParams; 25 | const apptIdString = searchParams.get("id"); 26 | if (!apptIdString) { 27 | const response: JSONError = { 28 | status: 400, 29 | title: "No appointment id", 30 | detail: 31 | "No appointment id was requested in the search parameters of the API call", 32 | }; 33 | return NextResponse.json(response, { status: 400 }); 34 | } else { 35 | // search by apptId 36 | const id = Number(apptIdString); 37 | const videos = await getVideoCount(id); 38 | 39 | const response: JSONResponse = { data: { count: videos } }; 40 | return NextResponse.json(response, { status: 200 }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/web/src/app/api/video/processed/route.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { getLoggedInUser } from "@app/actions"; 18 | import { JSONResponse, RESPONSE_NOT_AUTHORIZED } from "@lib/response"; 19 | import { NextRequest, NextResponse } from "next/server"; 20 | import { createPresignedUrl, getOutputBucket } from "@lib/s3"; 21 | 22 | export async function GET(req: NextRequest) { 23 | const searchParams = req.nextUrl.searchParams; 24 | const fileKey = searchParams.get("file"); 25 | 26 | if (!fileKey) { 27 | const error: JSONResponse = { 28 | errors: [ 29 | { 30 | status: 400, 31 | title: "Missing file parameter.", 32 | }, 33 | ], 34 | }; 35 | return Response.json(error, { status: 400 }); 36 | } 37 | 38 | const user = await getLoggedInUser(); 39 | if (!user) { 40 | return Response.json(RESPONSE_NOT_AUTHORIZED, { status: 401 }); 41 | } 42 | 43 | const url = await createPresignedUrl({ 44 | bucket: getOutputBucket(), 45 | key: fileKey, 46 | }); 47 | return NextResponse.json( 48 | { 49 | data: url, 50 | }, 51 | { status: 200 }, 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /app/video-processing/deprecated/.dockerignore: -------------------------------------------------------------------------------- 1 | # Git 2 | .git 3 | .gitignore 4 | .gitattributes 5 | 6 | # CI 7 | .github 8 | .codeclimate.yml 9 | .travis.yml 10 | .taskcluster.yml 11 | 12 | # Docker 13 | docker-compose.yml 14 | Dockerfile 15 | .docker 16 | .dockerignore 17 | 18 | # Byte-compiled / optimized / DLL files 19 | **/__pycache__/ 20 | **/*.py[cod] 21 | 22 | # C extensions 23 | *.so 24 | 25 | # Distribution / packaging 26 | .Python 27 | build/ 28 | develop-eggs/ 29 | dist/ 30 | downloads/ 31 | eggs/ 32 | .eggs/ 33 | lib/ 34 | lib64/ 35 | parts/ 36 | sdist/ 37 | var/ 38 | wheels/ 39 | share/python-wheels/ 40 | *.egg-info/ 41 | .installed.cfg 42 | *.egg 43 | MANIFEST 44 | 45 | # PyInstaller 46 | # Usually these files are written by a python script from a template 47 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 48 | *.manifest 49 | *.spec 50 | 51 | # Installer logs 52 | pip-log.txt 53 | pip-delete-this-directory.txt 54 | 55 | # Unit test / coverage reports 56 | htmlcov/ 57 | .tox/ 58 | .nox/ 59 | .coverage 60 | .coverage.* 61 | .cache 62 | nosetests.xml 63 | coverage.xml 64 | *.cover 65 | *.py,cover 66 | .hypothesis/ 67 | .pytest_cache/ 68 | cover/ 69 | 70 | # Translations 71 | *.mo 72 | *.pot 73 | 74 | # Virtual environment 75 | .env 76 | .venv 77 | env/ 78 | venv/ 79 | ENV/ 80 | env.bak/ 81 | venv.bak/ 82 | 83 | # Python mode for VIM 84 | .ropeproject 85 | **/.ropeproject 86 | 87 | # Vim swap files 88 | **/*.swp 89 | 90 | # VS Code 91 | .vscode/ 92 | 93 | # Makefile 94 | Makefile 95 | 96 | # Docs 97 | **/*.md 98 | 99 | # Test resources 100 | **/*.mp4 101 | **/*.jpg 102 | **/*.png 103 | test-samples/ 104 | *-videos/ 105 | 106 | # Test 107 | test_* 108 | -------------------------------------------------------------------------------- /app/web/src/components/staff/AttributeFilter.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import { 17 | SearchInput, 18 | ToolbarFilter, 19 | ToolbarFilterProps, 20 | } from "@patternfly/react-core"; 21 | 22 | interface AttributeFilterProps { 23 | show: boolean; 24 | displayValues: string[]; 25 | inputValue: string; 26 | onChipDelete: ToolbarFilterProps["deleteChip"]; 27 | onChipGroupDelete: ToolbarFilterProps["deleteChipGroup"]; 28 | onInputChange: (value: string) => void; 29 | category: string; 30 | } 31 | export const AttributeFilter = ({ 32 | show, 33 | displayValues, 34 | inputValue, 35 | category, 36 | onInputChange, 37 | onChipDelete, 38 | onChipGroupDelete, 39 | }: AttributeFilterProps) => { 40 | return ( 41 | 48 | onInputChange(value)} 52 | onClear={() => onInputChange("")} 53 | /> 54 | 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /.github/workflows/lambda-lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lambda Format Check 2 | 3 | concurrency: 4 | group: ${{ github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | branches: 10 | - "develop" 11 | - "master" 12 | - "main" 13 | pull_request: 14 | paths: 15 | - "app/video-conversion/**" 16 | - "app/video-processing/**" 17 | - "!app/video-processing/deprecated/**" 18 | types: 19 | - opened 20 | - reopened 21 | - synchronize 22 | workflow_dispatch: 23 | 24 | jobs: 25 | video-processing-flake8: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Check out the repository 29 | uses: actions/checkout@v4 30 | with: 31 | token: ${{ github.token }} 32 | - name: Set up Python 33 | uses: actions/setup-python@v4 34 | with: 35 | python-version: '3.12' 36 | cache: 'pip' 37 | cache-dependency-path: "**/requirements*.txt" 38 | - name: Install dependencies 39 | working-directory: app/video-processing/lambda 40 | run: pip install -r requirements_dev.txt 41 | - name: Run flake8 check 42 | working-directory: app/video-processing 43 | run: make lint 44 | 45 | video-conversion-flake8: 46 | runs-on: ubuntu-latest 47 | steps: 48 | - name: Check out the repository 49 | uses: actions/checkout@v4 50 | with: 51 | token: ${{ github.token }} 52 | - name: Set up Python 53 | uses: actions/setup-python@v4 54 | with: 55 | python-version: '3.12' 56 | cache: 'pip' 57 | cache-dependency-path: "**/requirements*.txt" 58 | - name: Install dependencies 59 | working-directory: app/video-conversion/lambda 60 | run: pip install -r requirements_dev.txt 61 | - name: Run flake8 check 62 | working-directory: app/video-conversion 63 | run: make lint 64 | -------------------------------------------------------------------------------- /app/web/src/components/layout/Header.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | "use server"; 18 | 19 | import NavigationBar from "./NavigationBar"; 20 | import { auth } from "src/auth"; 21 | import { Stylesheet } from "@lib/utils"; 22 | 23 | const style: Stylesheet = { 24 | header: { 25 | textAlign: "center", 26 | height: "var(--pal-header-height)", 27 | display: "flex", 28 | flexDirection: "column", 29 | justifyContent: "center", 30 | alignItems: "center", 31 | padding: "0", 32 | top: "0", 33 | zIndex: "1", 34 | }, 35 | logo: { 36 | maxWidth: "6rem", 37 | height: "auto", 38 | }, 39 | text: { 40 | fontSize: "30px", 41 | fontWeight: "bolder", 42 | color: "white", 43 | margin: "0.5rem 0", 44 | }, 45 | loginLinks: { 46 | width: "100%", 47 | padding: "0.5rem 1rem", 48 | display: "flex", 49 | justifyContent: "flex-end", 50 | gap: "1rem", 51 | }, 52 | link: { 53 | color: "var(--pf-v5-global--primary-color--100)", 54 | textDecoration: "underline", 55 | }, 56 | }; 57 | 58 | export const Header = async () => { 59 | const session = await auth(); 60 | 61 | return ( 62 |
63 | 64 |
65 | ); 66 | }; 67 | -------------------------------------------------------------------------------- /app/web/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2023] [Privacypal Authors] 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import type { Metadata } from "next"; 17 | import "@patternfly/react-core/dist/styles/base.css"; 18 | import "./globals.css"; 19 | import { Inter } from "next/font/google"; 20 | import Footer from "@components/layout/Footer"; 21 | import { Header } from "@components/layout/Header"; 22 | import { BackgroundImageBasic } from "@components/layout/BackgroundImageBasic"; 23 | import { Stylesheet } from "@lib/utils"; 24 | 25 | const inter = Inter({ subsets: ["latin"] }); 26 | 27 | const style: Stylesheet = { 28 | pageContent: { 29 | flexGrow: "1", 30 | }, 31 | }; 32 | 33 | export const metadata: Metadata = { 34 | metadataBase: new URL(process.env.NEXTAUTH_URL ?? "http://localhost:3000"), 35 | title: { 36 | template: "%s | PrivacyPal", 37 | default: "PrivacyPal", 38 | }, 39 | description: "COSC 499 Capstone Team 1 2023W1", 40 | }; 41 | 42 | export default function RootLayout({ 43 | children, 44 | }: { 45 | children: React.ReactNode; 46 | }) { 47 | return ( 48 | 49 | 50 | 51 |
52 |
{children}
53 |