Skip to the content.

DOCSE 5 Things

This is a blog for my DOCSE 5 Things for tri 2 final.

1. Planning issues and Burndown Lists (all integrated into KanBan)

I also created a burndown for this review!

I brainstormed and organized my project information in issues and user stories to help me ensure I was following Agile Methodology in relationship to my team members and that we stayed on task. I made use of a few checklists and burndowns to keep track of my progress and make sure my feature is complete. Me and my team used a KanBan Board to help collectivly store and present all of our documentaitona nd what we wanted to accomplish in one place for ease to look at and stay organized.

2. Dynamic API with CRUD and backend database

import jwt
from flask import Blueprint, request, jsonify, g
from flask_restful import Api, Resource
from flask_cors import CORS, cross_origin
from datetime import datetime
from __init__ import app, db  # Ensure db is imported
from api.jwt_authorize import token_required
from model.budgeting import Budgeting  # Assuming your Budgeting model is in the 'budgeting' module
from model.user import User

budgeting_api = Blueprint('budgeting_api', __name__, url_prefix='/api')
CORS(budgeting_api, supports_credentials=True, methods=["GET", "POST", "PUT", "DELETE"])
api = Api(budgeting_api)

class BudgetingAPI:
    """
    Define the API CRUD endpoints for the Budgeting model.
    Operations include creating, retrieving, updating, and deleting budgeting entries.
    """
    
    class _CRUD(Resource):
        @token_required()
        @cross_origin(supports_credentials=True)
        def post(self):
            current_user = g.current_user
            data = request.get_json()
            
            if not data or 'expense' not in data or 'cost' not in data or 'category' not in data:
                return jsonify({"message": "Expense, cost, and category are required"}), 400
            
            budgeting = Budgeting(
                expense=data.get('expense'),
                cost=data.get('cost'),
                category=data.get('category'),
                user_id=current_user.id
            )
            
            db.session.add(budgeting)
            db.session.commit()
            
            return jsonify({"message": "Budgeting entry created successfully"})
        
        @token_required()
        def get(self):
            current_user = g.current_user
            budgeting_entries = Budgeting.query.filter_by(user_id=current_user.id).all()
            return jsonify([entry.read() for entry in budgeting_entries])
        
        @token_required()
        def put(self):
            current_user = g.current_user
            data = request.get_json()
            budgeting_id = data.get('id')
            
            if not budgeting_id:
                return jsonify({"message": "ID is required for updating a budgeting entry"}), 400
            
            budgeting = Budgeting.query.filter_by(id=budgeting_id, user_id=current_user.id).first()
            if not budgeting:
                return jsonify({"message": "Budgeting entry not found"}), 404
            
            budgeting.expense = data.get('expense', budgeting.expense)
            budgeting.cost = data.get('cost', budgeting.cost)
            budgeting.category = data.get('category', budgeting.category)
            
            db.session.commit()
            return jsonify({"message": "Budgeting entry updated successfully"})
        
        @token_required()
        def delete(self):
            current_user = g.current_user
            data = request.get_json()
            budgeting_id = data.get('id')
            
            if not budgeting_id:
                return jsonify({"message": "ID is required for deleting a budgeting entry"}), 400
            
            budgeting = Budgeting.query.filter_by(id=budgeting_id, user_id=current_user.id).first()
            if not budgeting:
                return jsonify({"message": "Budgeting entry not found"}), 404
            
            db.session.delete(budgeting)
            db.session.commit()
            return jsonify({"message": "Budgeting entry deleted successfully"})

api.add_resource(BudgetingAPI._CRUD, '/budgeting')
    async function submitBudgeting(expense, cost, category) {
        try {
            const response = await fetch(`${pythonURI}/api/budgeting`, {
                ...fetchOptions,
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ expense, cost, category, user_id: USER_ID }),
            });

            if (response.ok) {
                createBudgetingTable();
                updateRemainingBudget();
            } else {
                console.error('Failed to submit budgeting entry:', await response.json());
            }
        } catch (error) {
            console.error("Error creating new budgeting entry:", error);
        }
    }

3. Integration into existing features; Budget API filtering system using UserIDs

Read Function:

    @token_required()
    def get(self):
        current_user = g.current_user
        budgeting_entries = Budgeting.query.filter_by(user_id=current_user.id).all()
        return jsonify([entry.read() for entry in budgeting_entries])

Integration with user API

    let USER_ID = null;

    async function getCurrentUserId() {
        try {
            const response = await fetch(`${pythonURI}/api/id`, fetchOptions);
            if (!response.ok) throw new Error("Failed to fetch user ID");

            const userData = await response.json();
            USER_ID = userData.id; 
            createBudgetingTable(); // Fetch entries after getting user ID
        } catch (error) {
            console.error("Error fetching user ID:", error);
        }
    }

Display on frontend webpage

    async function fetchAndDisplayBudgeting() {
        try {
            const response = await fetch(`${pythonURI}/api/budgeting?user_id=${USER_ID}`, fetchOptions);
            const data = await response.json();
            const displayElement = document.getElementById('budgeting-display');

            displayElement.innerHTML = data.length === 0 
                ? "No budgeting entries available."
                : data.map(entry => `<br>Expense: ${entry.expense}, Cost: ${entry.cost}, Category: ${entry.category}`).join('');

            updateRemainingBudget();
        } catch (error) {
            console.error("Error fetching budgeting entries:", error);
            document.getElementById('budgeting-display').textContent = "Failed to load budgeting entries.";
        }
    }

4. Frontend-Backend connection with Static APIs(About Us and Currency)

Currency Converter API

from flask import Blueprint, request, jsonify
from flask_restful import Api, Resource
import requests

# blueprint for the currency conversion api
currency_api = Blueprint('currency_api', __name__, url_prefix='/api')
api = Api(currency_api)

# API key and API URL for the currency conversion API
api_key = 'whtBMWOKRMxDm+KkxJidew==WPks2hKmgV3Lqogd'
currency_api_url = 'https://api.api-ninjas.com/v1/convertcurrency?have={}&want={}&amount={}'

class CurrencyAPI:
    
    # Define the API CRUD endpoints for currency conversion
    
    class _CurrencyConversion(Resource):
        
        def get(self):
            # Retrieve the currency data for the conversion request
            
            have = request.args.get('have', '')  # Get the currency to convert from
            want = request.args.get('want', '')  # Get the currency to convert to
            amount = request.args.get('amount', '')  # Get the amount to convert
            
            if not have or not want or not amount:
                return jsonify({"error": "Missing required parameters (have, want, amount)"}), 400
            
            # Get the conversion result from the external API
            conversion_data = get_conversion_data(have, want, amount)
            
            if conversion_data:
                return jsonify(conversion_data)
            else:
                return jsonify({"error": "Failed to get currency conversion data"}), 500
    
    # Add the resource for /currency_conversion
    api.add_resource(_CurrencyConversion, '/convertcurrency')

# Function to fetch conversion data from the API
def get_conversion_data(have, want, amount):
    # Construct the URL for the API request
    api_url = currency_api_url.format(have, want, amount)
    
    response = requests.get(api_url, headers={'X-Api-Key': api_key})
    
    if response.status_code == requests.codes.ok:
        return response.json()
    else:
        print("Error:", response.status_code, response.text)
        return None
<script type="module">
    import { pythonURI, fetchOptions } from '/DerekCSP/assets/js/api/config.js';
    document.getElementById('convertButton').addEventListener('click', function() {
        const have = document.getElementById('have').value.trim();
        const want = document.getElementById('want').value.trim();
        const amount = document.getElementById('amount').value.trim();
        const resultElement = document.getElementById('conversionResult');
        // Validate input fields
        if (!have || !want || !amount) {
            resultElement.textContent = 'Please fill out all fields.';
            return;
        }
        // Make a request to the backend API (Flask)
        fetch(`${pythonURI}/api/convertcurrency?have=${have}&want=${want}&amount=${amount}`, {
            ...fetchOptions,
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        })
        .then(response => response.json())
        .then(result => {
            if (result.new_amount) {
                resultElement.textContent = `${amount} ${have} = ${result.new_amount} ${want}`;
            } else {
                resultElement.textContent = `Error: Unable to convert currency.`;
            }
        })
        .catch(error => {
            resultElement.textContent = `Error: ${error.message}`;
        });
    });
</script>

About Us API

from flask import Blueprint, request, jsonify, g
from flask_restful import Api, Resource

derek_api = Blueprint('derek_api', __name__, url_prefix='/api')
api = Api(derek_api)

class DerekAPI:
    class Student(Resource):
        def get(self):
            return jsonify({
                "name": "Derek Kang",
                "age": 15,
                "classes": ["AP CSP", "AP Physics Mechanics", "Ap Seminar", "AP Calculus AB", "AP World History"],
                "favorite": {
                    "color": "Blue",
                    "food": "Pasta"
                }
            })
    

api.add_resource(DerekAPI.Student, "/people/derek")
async function fetchTeamInfo() {
        try {
            // Fetch data from multiple endpoints (e.g., /api/derek, /api/john, /api/sarah)
            const responses = await Promise.all([
                fetch('http://127.0.0.1:8101/api/people/derek'),
                fetch('http://127.0.0.1:8101/api/people/kiruthic'),
                fetch('http://127.0.0.1:8101/api/people/tarun'),
                fetch('http://127.0.0.1:8101/api/people/aadi'),
                fetch('http://127.0.0.1:8101/api/people/aaditya'),
                fetch('http://127.0.0.1:8101/api/people/arhaan'),
                fetch('http://127.0.0.1:8101/api/people/rohan')
            ]);
    
            // Convert all the responses to JSON
            const data = await Promise.all(responses.map(response => response.json()));
    
            // Display team info using the data returned by the backend
            data.forEach(member => displayTeamInfo(member)); // Display each member's info
        } catch (error) {
            console.error('Error fetching team info:', error);
        }
    }

5. Backend Admin role: customized backend UI to reflect our project with admin features

<div class="col-4">
    <div class="card">
        <img class="card-img-top" src="" alt="Python Development" height="350">
        <div class="card-body">
        <h5 class="card-title">What are the features of <mark>InterTravel?</mark>?</h5>
        <p class="card-text">
            <ol>
                <li>Wellness Waypoints</li>
                <li>Lodging Listings</li>
                <li>Activity Planner</li>
                <li>Packing Portal</li>
                <li>Cuisine Chronicles</li>
                <li>Fair Fares</li>
                <li>Budget Brilliance</li>
            </ol>
        </p>
        <a class="btn btn-primary" href="https://kiruthic-selvakumar.github.io/travel_frontend/">Check them out!</a>
        </div>
    </div>
</div>
  async function fetchBudgetingEntries() {
    try {
      const response = await fetch('/api/budgeting');
      if (!response.ok) throw new Error('Failed to fetch budgeting entries');
      const budgetingEntries = await response.json();
      const budgetBody = document.getElementById('budgetBody');
      budgetBody.innerHTML = '';
      budgetingEntries.forEach(entry => {
        budgetBody.innerHTML += `
          <tr data-id="${entry.id}" 
              data-expense="${entry.expense}" 
              data-cost="${entry.cost}" 
              data-category="${entry.category}">
            <td>${entry.id}</td>
            <td>${entry.expense}</td>
            <td>${entry.cost}</td>
            <td>${entry.category}</td>
            <td>
              <button class="btn btn-primary edit-btn" data-id="${entry.id}">Edit</button>
              <button class="btn btn-danger delete-btn" data-id="${entry.id}">Delete</button>
            </td>
          </tr>`;
      });
    } catch (error) {
      console.error('Error fetching budgeting entries:', error);
    }
  }