Individual Blog & Feature Showcase
Individual Blog listing contributions
Individual Blog (Ian):
Scribble Personal Story Issue
Scribble Burndown List
Scribble Khanban Board & Code Overview
Major Commits:
-
Built API (api/competition.py) that fetches username based on a JWT authentication token from login, amount of time taken from fetching through api/competition/timer, and word given.
-
Made model file (model/competition.py) to create a seperate db tables inside of user_management.db to store information with fetched username, time, and given word, storing information inside database.
-
Developed Deployment Blog with port 8203, overview of setup on backend page (scribble.stu.nighthawkcodingsociety.com) [Assistant Deployment Admin]
-
Made navigation bar and nav to main homepage, styled individual page + deployment blog, changed readability on site. [Frontend Developer]
Minor Commits:
-
Changed overall JWT Token request from jwt_authorize.py to fetch user_name details and formatting.
-
Adjusted port on makefile, put files such as /sass-cache/ into .gitignore to help with github deployment.
-
Made issue on 4.2, 4.3 about fault tolerances and computing models (Sequential, Parallel, Distributed, Efficiency Comparisons).
Features Showcase:
Description
-
Competition is a timed drawing game that fetches users JSON data into an api (competition.py) and updates/stores progress after timer ends, such as the users (profile name, time taken, and a user’s given word).
-
The user’s saved data is stored within a separate model file named competition.py, which creates a separate db_table under user_manangement.db with separate variables from Competition.
CPT Requirements:
Component | Competency (What It Does) | Performance (How It Works) | Task (Implementation Details) | Correlations |
---|---|---|---|---|
Page Layout & Metadata | Defines page structure and access requirements | Uses layout: needsAuth to restrict access; sets title: Competition |
Ensures only authenticated users can access the competition page | Frontend: Layout design; Backend: Access control; Security and Authentication: Authentication handling; HTTP & RESTful APIs: Request filtering |
Timer Controls | Allows users to manage a countdown timer | Inputs a duration, starts/stops the timer, and updates the display | Uses #timerDuration , #startTimer , and #stopTimer buttons |
Frontend: Timer controls UI; Backend: Timer management APIs; HTTP & RESTful APIs: Timer state handling |
Timer Display | Displays remaining time dynamically | Updates text inside #timerDisplay using JavaScript |
Calls updateTimerDisplay() to refresh every second |
Frontend: JavaScript for updating DOM; Backend: Timer synchronization if needed |
Save Drawing | Allows users to save their drawings | Converts the canvas to a PNG image and downloads it | Uses toDataURL('image/png') and <a> tag for download |
Frontend: Image conversion and download handling; Image Upload and Storage: Storing drawings on server-side if needed |
Results Table | Displays competition results | Fetches and populates user entries from an API | Uses fetchResults() to update #resultsBody dynamically |
Frontend: DOM population; Backend: Results API; Database Management with SQLite: Storing competition results |
Timer API Integration | Communicates with backend to start/stop timer | Sends POST , PUT , and GET requests to /api/competition/timer |
Uses fetch() with credentials: 'include' for authentication |
Backend: Timer management API; Postman Testing: API testing for timer operations; HTTP & RESTful APIs: API interaction for timer control |
Error Handling | Displays errors to the user | Shows and hides an error message div dynamically | Uses showError(message) to alert users of issues |
Frontend: Error handling UI; Backend: Error handling in API responses; Monitoring and Logging: Logging errors for troubleshooting |
Procedure Steps
- Initialize Repeated Execution:
- Start a recurring interval (
setInterval
) that executes every 1000ms (1 second).
- Start a recurring interval (
- Perform API Request:
- Send an asynchronous HTTP GET request to the competition timer API endpoint (
/api/competition/timer
). - Include credentials (
'include'
) for authentication/session handling.
- Send an asynchronous HTTP GET request to the competition timer API endpoint (
- Process API Response:
- Await the API response and parse it into JSON format.
- If the response status is not OK (
!response.ok
), throw an error with the server-provided message.
- Update Timer Display:
- Extract
time_remaining
from the API response. - Modify the DOM element with ID
timerDisplay
to display the remaining time.
- Extract
- Evaluate Timer State:
- If
is_active
isfalse
, execute the following actions:- Stop the interval (
clearInterval(timerInterval)
). - Enable the “Start Timer” button (
#startTimer
). - Disable the “Stop Timer” button (
#stopTimer
).
- Stop the interval (
- If
- Error Handling:
- If any error occurs, log the error to the console.
- Stop the interval (
clearInterval(timerInterval)
) to prevent redundant API calls.
Code Implementation
async function updateTimerDisplay() {
timerInterval = setInterval(async () => {
try {
const response = await fetch(`${pythonURI}/api/competition/timer`, {
method: 'GET',
credentials: 'include'
});
const data = await response.json();
if (!response.ok) throw new Error(data.message);
document.getElementById('timerDisplay').textContent =
`Time: ${data.time_remaining}s`;
if (!data.is_active) {
clearInterval(timerInterval);
document.getElementById('startTimer').disabled = false;
document.getElementById('stopTimer').disabled = true;
}
} catch (error) {
console.error('Error:', error);
clearInterval(timerInterval);
}
}, 1000);
}
Requirements & Constraints
- The function must be executed in a browser environment.
- The API endpoint (
/api/competition/timer
) must be accessible and return a valid JSON response. - The target DOM elements (
#timerDisplay
,#startTimer
,#stopTimer
) must exist before function execution. - The function must handle network errors and API failures gracefully.
setInterval
must be cleared whenis_active
isfalse
to prevent unnecessary API calls.
User Results
Objective
To fetch competition result data from an API and update the user interface dynamically.
Procedure Steps
- Perform API Request:
- Send an asynchronous HTTP GET request to the competition results API endpoint (
/api/competition/times
). - Include credentials (
'include'
) for authentication/session handling.
- Send an asynchronous HTTP GET request to the competition results API endpoint (
- Validate API Response:
- Check if the response status is OK (
response.ok
). - If not, throw an error with the message
'Failed to fetch results'
.
- Check if the response status is OK (
- Process API Data:
- Parse the JSON response and extract the list of result entries.
- Select the target table body element (
#resultsBody
). - Clear any existing content in the table body.
- Populate Table with Results:
- Iterate through each entry in the response data.
- Create a new table row (
<tr>
) for each entry. - Insert the following data into the corresponding cells (
<td>
):- User’s Name (
users_name
) or'Unknown'
if not available. - Time Taken (
time_taken
) or'0'
if not available. - Drawn Word (
drawn_word
) or'Unknown'
if not available.
- User’s Name (
- Error Handling:
- If any error occurs during execution:
- Log the error message to the console.
- Display an alert to inform the user that the fetch operation failed.
- If any error occurs during execution:
async function fetchResults() {
try {
const response = await fetch(`${pythonURI}/api/competition/times`, {
credentials: 'include'
});
if (!response.ok) {
throw new Error('Failed to fetch results');
}
const entries = await response.json();
const tbody = document.getElementById('resultsBody');
tbody.innerHTML = '';
entries.forEach(entry => {
const row = tbody.insertRow();
row.insertCell().textContent = entry.users_name || 'Unknown'; // Changed from profile_name
row.insertCell().textContent = entry.time_taken || '0';
row.insertCell().textContent = entry.drawn_word || 'Unknown'; // Changed from word_drawn
});
} catch (error) {
console.error('Error:', error);
alert('Failed to fetch results: ' + error.message);
}
}
// Initial fetch of results
document.addEventListener('DOMContentLoaded', fetchResults);
Requirements & Constraints
- The function must be executed in a browser environment.
- The API endpoint (
/api/competition/times
) must be accessible and return a valid JSON response. - The target DOM element (
#resultsBody
) must exist before function execution. - The function must handle network errors and API failures gracefully.
- Data fields (
users_name
,time_taken
,drawn_word
) must be validated to prevent rendering issues.
Admin Panel, Delete Records & restore:
Objective
To display and manage competition data in a structured table, allowing admins to delete entries.
Procedure Steps
1. Template Inheritance & Styling
- Extend the base template (
layouts/base.html
). - Apply CSS styles to improve the UI, including:
- White background with padding and shadow for the container.
- Speed factor color coding based on performance.
2. Render Competition Data in a Table
- Create a responsive HTML table (
#competitionTable
). - Populate rows dynamically using
competition_data
. - Display the following fields:
- ID
- Player Name (
users_name
) - Drawing Word (
drawn_word
) - Timer Duration (
timer_duration
) - Time Taken (
time_taken
) - Speed Factor (
timer_duration / time_taken
) - Date Created (
date_created
)
- Conditionally display the Delete button for Admin users.
3. Admin-Only Delete Functionality
- If the user role is
'Admin'
, enable the Delete button. - Use JavaScript to:
- Attach click events to
.delete-btn
. - Confirm deletion before sending an API request.
- Send a
DELETE
request to/api/competition/times
with the entry ID. - Reload the page upon success or show an error message upon failure.
- Attach click events to
4. Initialize DataTable (for Enhanced Table Management)
- Use jQuery DataTables to:
- Enable sorting (default: by speed factor descending).
- Set pagination (
pageLength: 25
).
5. Error Handling
- If API deletion fails:
- Log the error to the console.
- Show an alert to notify the user.
- If the request is successful:
- Display a success message.
- Refresh the page to reflect changes.
<style>
.container {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-top: 2rem;
margin-bottom: 2rem;
}
.table {
background: white;
}
.speed-factor {
font-weight: bold;
color: #2196F3;
}
.speed-high {
color: #4CAF50;
}
.speed-medium {
color: #FFC107;
}
.speed-low {
color: #FF5722;
}
</style>
<div class="container">
<h1 class="mb-4">Competition Management</h1>
<table class="table table-striped" id="competitionTable">
<thead>
<tr>
<th>ID</th>
<th>Player</th>
<th>Drawing Word</th>
<th>Timer Duration</th>
<th>Time Taken</th>
<th>Speed Factor</th>
<th>Date Created</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
$(document).ready(function() {
// Initialize DataTable
$("#competitionTable").DataTable({
order: [[5, 'desc']], // Sort by speed factor by default
pageLength: 25
});
// Handle delete button clicks
$(document).on("click", ".delete-btn", function() {
var id = $(this).data("id");
if (!confirm("Are you sure you want to delete this competition entry?")) {
return;
}
fetch("/api/competition/times", {
method: "DELETE",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: id })
})
.then(response => response.json())
.then(data => {
if (data.message) {
alert(data.message);
location.reload();
} else {
alert(data.error || "Operation failed");
}
})
.catch(error => {
console.error('Error:', error);
alert("Failed to process request");
});
});
});
</script>
Requirements & Constraints
- Must be used within a Flask/Jinja templating environment.
- The
competition_data
variable must be populated before rendering. - The
current_user.role
variable must be available to determine Admin access. - JavaScript/jQuery must be enabled for table sorting and delete functionality.
- The API endpoint
/api/competition/times
must supportDELETE
requests with an entry ID.
N@TM Feedback:
During N@TM, we recieved a moderate feedback in regards to our site about the functionality of Scribble and the purpose of the project. When people tried to use our site, most people were able to figure out how to work the site, however didn’t understand its efficiency and the general purpose of the website.
What we could do in the future of fixing this issue is adding a purpose for the website at the main page (our index.md) instead of a regular drawing board at the start of the website. This way people are able to get a “semi-tutorial” of the website and what each link does with the game.
N@TM Prism
A good example of how we’d fix this problem was with a group called Prism, where they put an explanation of their grading function while it was running. The page was simple without any hard navigation, and people were able to get the purpose of their website without any questions, as the idea and functions were basic. For example, their website was able to fit CPT requirements due to the idea of grading systems, and how admins can create or delete a students score, giving a purpose for teachers and a goal for students. Contrast to Scribble, although our website was able to fulfill CPT requirements in a way, my contribution of implementing competition between players may be confusing for other players and doesn’t have a clear goal overall.
MCQ Reflection
Plans For Next Trimester
Self-Assessment
Overall in this trimester, I felt that even though I was able to help organize the page and have my general features running and connected to one another, most of my commits were primarly focused on one specific assessments, which wasted the amount of things I was able to do and made my work habits less productive. Because of this, I began to fall a bit behind with making an individual admin page for my website, making deployment blogs for the website, and fixing and adjusting navigation pages.
Criteria | Description | Score |
---|---|---|
5 things you did over 12 weeks, Issues, burndown, presentation | Committed, however focused too much on one subject that it limited how much work I did for others in regards to my role as Assistant Deployment Admin. | 3.9/5 |
Full Stack Project Demo, including CPT requirement highlights, and N@tM feedback | Highlights CPT requirements and spands Full Stack demo, however CPT requirements are choppy and wordy. | 1.8/2 |
Project Feature blog write up, using CPT/FRQ language | Feature blog showing each feature coorelating with CPT requirements (ex: frontend to backend [big idea 1.4], and HTTPS requests [big idea 4.0]) | 0.9/1 |
MCQ | Reviewed 2020 MCQ review, went over problems missed and went over the overall section of the error and what to look out for. | 0.9/1 |
10th point | Mentioned strengths and weaknesses, plans on going forward but not much depth. | 0.5/1 |
Overall | 8.5/10 |
Looking further I’ll attempt to become more productive with tasks and understand what i’m doing as well. This could be done with making more effective burndown lists at the start, and mark things down with what is achievable and what isn’t.