Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
dbc1486
fixed typo, reviewed spelling of everything in JSON files to possibly…
TinaMcComiskey Sep 16, 2025
446c145
Merge remote-tracking branch 'origin/master' into all-games
TinaMcComiskey Sep 17, 2025
482fdec
Starting to change point structure of Context Integ game to be less b…
TinaMcComiskey Dec 10, 2025
ef1ea78
Now there are four results you can get for the CI game, based on if y…
TinaMcComiskey Dec 10, 2025
1c09914
Added descriptions for each privacy category
TinaMcComiskey Dec 10, 2025
1b52d26
Cleaned up score vars that aren't being used anymore
TinaMcComiskey Dec 10, 2025
c13ca30
More cleanup
TinaMcComiskey Dec 10, 2025
04881ef
Changed red incorrect color in CI to yellow
TinaMcComiskey Dec 11, 2025
49e5c53
Made CI game functional on mobile
TinaMcComiskey Dec 11, 2025
b874425
Changed wording on safe to share answers. Also started to make unit t…
TinaMcComiskey Dec 16, 2025
02c8b4e
Added link redirects to the github and to additional resources from t…
TinaMcComiskey Dec 16, 2025
eb7e061
Small description edits. Got rid of extra start screen on CI game
TinaMcComiskey Dec 16, 2025
9b2f351
Fixed some typos in comicviewer.html
TinaMcComiskey Dec 16, 2025
eee7a62
Fixed incrementing error in nextPage fuction in comicviewer.js
TinaMcComiskey Dec 16, 2025
b0eeec1
Updated readme screenshots
TinaMcComiskey Dec 16, 2025
4879bbe
Typo fixing, more fine tuning
TinaMcComiskey Dec 16, 2025
dae1705
Added image to results screen to match category
TinaMcComiskey Dec 17, 2025
e81ecef
Added half the new assets for new CI score systm
TinaMcComiskey Dec 17, 2025
f06b393
Added final assets of CI game results
TinaMcComiskey Dec 22, 2025
05c0183
Updated README with new CI End example
TinaMcComiskey Dec 22, 2025
65c2619
Adding JSON to keep track of alt text for comic pages
TinaMcComiskey Dec 22, 2025
951f559
Alt text is now attached to all comic panels
TinaMcComiskey Dec 23, 2025
30a0d2a
fixed script formatiing in COicViewer html
TinaMcComiskey Dec 23, 2025
328b457
Added more documentation to the README
TinaMcComiskey Dec 23, 2025
323a055
Typo photos
TinaMcComiskey Dec 23, 2025
600b03f
Formatting README
TinaMcComiskey Dec 23, 2025
824df73
Implemented quick changes
TinaMcComiskey Jan 8, 2026
2df5154
Create LICENSE
TinaMcComiskey Jan 8, 2026
f16daf1
Added team page
TinaMcComiskey Jan 8, 2026
b4b3273
Merge branch 'all-games' of https://github.com/DIPrLab/EduPrivacy int…
TinaMcComiskey Jan 8, 2026
a8df913
Added privacy policy
TinaMcComiskey Jan 9, 2026
87d81b9
Added functional mobile drop down menu
TinaMcComiskey Jan 9, 2026
342652f
Added base instructions for each game
TinaMcComiskey Jan 9, 2026
0231132
Refined instructions
TinaMcComiskey Jan 12, 2026
17f64b5
Modified routes to make it easier to find the base directory.
TinaMcComiskey Jan 12, 2026
e05c961
Adjusted some images
TinaMcComiskey Jan 13, 2026
f4d866e
Adjusted instructions
TinaMcComiskey Jan 13, 2026
05953a4
Fixed bug with drag and drop on mobile
TinaMcComiskey Jan 13, 2026
72d2590
Fixed broken reset on mobile safe to share
TinaMcComiskey Jan 13, 2026
fee237e
Fixed reset bug without having to reload the page
TinaMcComiskey Jan 13, 2026
bfb5a14
Cleaned up, fixed typos
TinaMcComiskey Jan 13, 2026
b69c995
Contact form, text adjustments
TinaMcComiskey Jan 21, 2026
c76d2ba
Last minute adjustments
TinaMcComiskey Jan 27, 2026
f10bc40
Typos
TinaMcComiskey Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

50 changes: 48 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,55 @@ Whether you're a parent guiding your child, a student learning about digital saf
| **Best Practices** | Password hygiene, Data minimization, 2FA | Proactive protection, Security habits | Account security, Reducing digital footprint |

## Table of Contents
- [Homepage](#homepage)
- [Spot the Sensitive Information](#spot-the-sensitive-information)
- [Safe to Share](#safe-to-share)
- [Installation](#installation)
- [Setup Virtual Environment](#setup-virtual-environment)
- [Running the Project](#running-the-project)
- [Contributing](#contributing)
- [License](#license)
- [License](#Heroku)
- [Adding Questions](#adding-questions)

## Homepage
![EduPrivacy Logo](screenshots/homepage1.png)
A description of each of the reocurring characters so audiences understand
their role before they see them in the comcis and games.
![EduPrivacy Logo](screenshots/homepage2.png)
Cards that redirect to each of the lessons.

## Spot the Sensitive Information
![EduPrivacy Logo](screenshots/Spot-Comic.png)
When you begin a game, you're presented with a comic that reflects the lesson of double-checking
images before you post them online.

![EduPrivacy Logo](screenshots/Spot1.png)
Each question in this game mimics the UI of an Instagram post. You're able to hover over
each square and choose which one you think is revealing sensitive information. The square becomes
green if you guessed correctly, and red if it's incorrect.

![EduPrivacy Logo](screenshots/Spot2.png)
![EduPrivacy Logo](screenshots/SpotRight.png)
![EduPrivacy Logo](screenshots/SpotWrong.png)
![EduPrivacy Logo](screenshots/SpotEnd.png)
The end screen displays the total number of correct answers you got.

## Safe to Share
![EduPrivacy Logo](screenshots/CI1.png)
![EduPrivacy Logo](screenshots/CI2.png)
![EduPrivacy Logo](screenshots/CI-Comic.png)
When you begin a game, you're presented with a comic that reflects the lesson of paying
attention to the context of a situation before deciding to share it.

![EduPrivacy Logo](screenshots/CIDrag.png)
Each question in this game has drag and drop answers that you put into the answer box. It presents you
with a specific situation and you can choose whether you would want to share information in that situation.
This is meant to be more nuanced than simple "right" or "wrong" so the wrong answers highlight yellow and you
get a hint to help you consider what you might have missed.

![EduPrivacy Logo](screenshots/CIRight.png)
![EduPrivacy Logo](screenshots/CIWrong.png)
![EduPrivacy Logo](screenshots/CIEnd.png)
The ending displays which category you ended up in based on your answers. It might say you may be too protective of your information (Clam), not protective enough (Goldfish), good at knowing the difference between when to share data and when not to (Octopus), or still new to understanding the concept (Baby Sea Turtle).

## Installation

Expand Down Expand Up @@ -279,3 +303,25 @@ git push heroku master
- `-r, --remote REMOTE` - Use custom git remote
- `--tail` - Stream live output
- `-n NUM` - Limit output lines

## Adding Questions

Each multiple-choice question is pulled from a JSON file that follows a simple template so even a non-programmer could easily add more sets of questions to a particular game.

An entire set of questions in a file is surrounded by square brackets. Each question is surrounded by curly brackets. A comma separates each question. For the “Spot the Sensitive Information” game, each question follows this format:

| Field | Description |
|---------|-------------|
| `question` | A description to introduce the scenario. |
| `type` | The format of the question, in this case, “image-grid”. |
| `image` | The file path to the visual asset. |
| `options` | A list of answers to choose from with descriptions and feedback. The options are surrounded by square brackets, each option is surrounded by curly brackets, and a comma separates each option. The correct option is set to “true”. |

And the "Safe to Share" game follows this format:

| Field | Description |
|---------|-------------|
| `question` | A character asking you to share specific information |
| `context` | The context for why the character is asking for that information |
| `answers` | The choice of "Share" and "Do Not Share". They each have their own attributes that determine whether they're right or wrong, and reasoning or a hint.
| `characterName` | The name of the character asking for your information. |
2 changes: 1 addition & 1 deletion Spot_the_Sensitive_Information_Design_Doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
- Sensitive info: Phone number on dog tag
- Learning: Pet photos can reveal contact information

2. **School Photo** (`Spot_the_violation_SChool.png`)
2. **School Photo** (`Spot_the_violation_School.png`)
- Sensitive info: School name visible in background
- Learning: Location information can be identifying

Expand Down
57 changes: 44 additions & 13 deletions app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
from flask import render_template, send_from_directory
from app import app

BASE_DIR = os.path.dirname(app.root_path)

def load_json(filename):
path = os.path.join(BASE_DIR, filename)
with open(path, 'r') as f:
return json.load(f)


@app.route("/")
@app.route("/index")
def EduPrivacy():
Expand All @@ -12,11 +20,22 @@ def EduPrivacy():
def about():
return render_template("about.html")

@app.route("/team")
def team():
return render_template("team.html")

@app.route("/privacypolicy")
def privacypolicy():
return render_template("PrivacyPolicy.html")

@app.route('/quiz')
def quiz():
with open('questions.json', 'r') as f:
questions = json.load(f)
return render_template('quiz.html', questions=questions)
questions = load_json('questions.json')
return render_template('Quiz.html', questions=questions)

@app.route("/SpotInstructions")
def spotinstructions():
return render_template("SpotInstructions.html")

@app.route('/ctf/<path:path>')
def serve_ctf_asset(path):
Expand All @@ -33,29 +52,41 @@ def serve_ctf_index():

@app.route('/ContextualIntegrity')
def ContextualIntegrity():
with open('questionsCI.json', 'r') as f:
questions = json.load(f)
questions = load_json('questionsCI.json')
return render_template("ContextualIntegrity.html", questions=questions)

@app.route("/ContextInstructions")
def contextinstructions():
return render_template("ContextInstructions.html")

# The first route is for the Spot Comic
# The secoond route is for the CI Comic
@app.route('/SpotComic')
def SpotComic():
comic_info = {'total_pages': 6, 'folder': 'assets/SpotPages-Short', 'filename_pattern': 'MyPalSpotComicShort',
'quiz_route': '/quiz', 'title': 'Spot the Sensitive Information',
'subtitle': 'Read the comic story before taking the quiz!'}
comic_alt = load_json('comics.json')[0]
comic_info = {
'total_pages': 6,
'folder': 'assets/SpotPages-Short',
'filename_pattern': 'MyPalSpotComicShort',
'quiz_route': '/SpotInstructions',
'title': 'Spot the Sensitive Information',
'subtitle': 'Read the comic story before taking the quiz!',
'panel_desc': comic_alt["SpotPages-Short"]
}
return render_template('ComicViewer.html', comic=comic_info)


@app.route('/CIComic') # ← New route for CI comic

@app.route('/CIComic')
def CIComic():
comic_alt = load_json('comics.json')[0]
comic_info = {
'total_pages': 7, # ← Different number of pages
'folder': 'assets/CI-Pages',
'total_pages': 7,
'folder': 'assets/CI-Pages',
'filename_pattern': 'MyPalCIComic',
'quiz_route': '/ContextualIntegrity',
'quiz_route': '/ContextInstructions',
'title': 'Safe to Share',
'subtitle': 'Learn about contextual integrity!'
'subtitle': 'Learn about contextual integrity!',
'panel_desc': comic_alt["CI-Pages"]
}
return render_template('ComicViewer.html', comic=comic_info)
20 changes: 14 additions & 6 deletions app/static/JSScript/ComicViewer.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// SpotComic.js - Implements the navigation functionality for the comics

const configPages = document.getElementById('comicConfig');
const comicConfig = JSON.parse(configPages.textContent);

let currentPage = 1;
let totalPages = window.comicConfig.totalPages;
let folder = window.comicConfig.folder;
let filePattern = window.comicConfig.filePattern;
let quizRoute = window.comicConfig.quizRoute;
let totalPages = Number(comicConfig.totalPages);
let folder = comicConfig.folder || "";
let filePattern = comicConfig.filePattern || "";
let quizRoute = comicConfig.quizRoute || "";
let lastPage = false;
let showingDescription = false;
let altText = comicConfig.panelDescription[String(currentPage)] || "";



function formatPageNumber(fileName) {
// Take filename like "MyPalSpotComicShort_001.png" and extract page number
Expand Down Expand Up @@ -42,11 +48,13 @@ function updateComicDisplay() {
}
else {
pageDisplay.textContent = `Page ${currentPage} of ${totalPages}`;

altText = comicConfig.panelDescription[String(currentPage)];

// Show comic image
const paddedPageNum = currentPage.toString().padStart(3, '0');
comicImageContainer.innerHTML = `
<img id="comic-image" src="/static/${folder}/${filePattern}_${paddedPageNum}.png" alt="Comic Page ${currentPage}">
<img id="comic-image" src="/static/${folder}/${filePattern}_${paddedPageNum}.png" alt="${altText}">
`;

// Update currentPage by parsing the filename we just set
Expand All @@ -69,7 +77,7 @@ function updateComicDisplay() {

function nextPage() {
// 1. Check if we're at the last comic page (page 6)
if (currentPage === totalPages && !showingDescription) {
if (currentPage >= totalPages && !showingDescription) {
// 2. If yes, go to description page
showingDescription = true;
lastPage = true;
Expand Down
Loading