Collections

  • Blog Python API code and use of List and Dictionaries.

  • This code initializes a database of our own for storing the images.


def initializeDatabase():
    global engine, Session, session

    engine = create_engine('sqlite:///database2.db')
    Session = sessionmaker(bind=engine)
    session = Session()

    Base.metadata.create_all(engine)

def clearDatabase():
    initializeDatabase()
    session.query(Images).delete()
    session.commit()
    session.close()

class Images(Base):
    __tablename__ = 'images'
    imageName = Column(String, primary_key=True, nullable=False, unique=False)  # Added nullable=False for primary key
    imageFunc = Column(String, nullable=False, unique=False)  # Added nullable=False for non-nullable columns
    imageBase64 = Column(String, nullable=False, unique=False)

def createImage(name, func, image):
    initializeDatabase()
    newImage = Images(imageName=name, imageFunc=func, imageBase64=image)
    session.add(newImage)
    session.commit()

  • From VSCode using SQLite3 Editor, show your unique collection/table in database, display rows and columns in the table of the SQLite database.
    • This data table comprises stored memes, organized by whether the creator opted to save them. Screenshot-2024-04-17-at-3-31-23-PM
  • From VSCode model, show your unique code that was created to initialize table and create test data.
    • Utilizes two regular accounts and one administrator account as directed.
def initUsers():
    with app.app_context():
        """Create database and tables"""
        db.create_all()
        """Tester data for table"""
        u1 = User(name='Thomas Edison', uid='toby', password='123toby', type="standard")
        u2 = User(name='Imaad Muzaffer', uid='imaad', password='123imaad', type="standard")
        u3 = User(name='Admin Account', uid='admin', type="admin")
        users = [u1, u2, u3]

        """Builds sample user/note(s) data"""
        for user in users:
            try:
                '''add a few 1 to 4 notes per user'''
                '''add user/post data to table'''
                user.create()
            except IntegrityError:
                '''fails with bad or duplicate data'''
                db.session.remove()
                print(f"Records exist, duplicate email, or error: {user.uid}")
  • In VSCode using Debugger, show a list as extracted from database as Python objects.
    • This demonstrates the extraction of the user data object in the debugger following a Postman request. Screenshot-2024-04-24-at-10-47-12-PM
  • In VSCode use Debugger and list, show two distinct example examples of dictionaries, show Keys/Values using debugger.
    • The user data is displayed below, where the key is represented by purple text and its corresponding value is adjacent to it.
    • Upon user creation, the data appears beneath the user, with the key denoted by purple text and its corresponding value positioned alongside it. Screenshot-2024-04-24-at-10-47-12-PM

APIS and JSON

Blog Python API code and use of Postman to request and respond with JSON.

  • In VSCode, show Python API code definition for request and response using GET, POST, UPDATE methods. Discuss algorithmic condition used to direct request to appropriate Python method based on request method.
    • The API encompasses numerous CRUD definitions for GET, POST, and UPDATE responses, facilitating the modification of objects.
    • Defining a resource is necessary to create endpoints.
    • This code defines the endpoint for the user API, enabling GET, POST, and PUT responses.
    # building RESTapi endpoint
    api.add_resource(_CRUD, '/')
    api.add_resource(_Security, '/authenticate')
  • In VSCode, show algorithmic conditions used to validate data on a POST condition.
    • The algorithmic requirements ensure the validity of input data. The condition incorporated into the user code validates the password’s security by verifying its minimum length and ensuring the presence of both a name and a password.
            # validate name
            name = body.get('name')
            if name is None or len(name) < 2:
                return {'message': f'Name is missing, or is less than 2 characters'}, 400
            # validate uid
            uid = body.get('uid')
            if uid is None or len(uid) < 2:
                return {'message': f'User ID is missing, or is less than 2 characters'}, 400
  • In Postman, display the URL requests and body specifications for GET, POST, and UPDATE methods.
  • In Postman, demonstrate the JSON response data for successful 200 conditions on GET, POST, and UPDATE methods. Screenshot-2024-04-24-at-11-14-20-PM Screenshot-2024-04-24-at-11-14-40-PM Screenshot-2024-04-24-at-11-14-48-PM

  • In Postman, show the JSON response for error for 400 when missing body on a POST request.
    • When the body is absent, there is no JSON data to send, which defeats the purpose of a POST request. Screenshot-2024-04-24-at-11-17-02-PM
  • In Postman, show the JSON response for error for 404 when providing an unknown user ID to a UPDATE request.
    • This error is a 400 status code, indicating that the user was not found. Screenshot-2024-04-24-at-11-17-40-PM
  • This code deciphers the JWT and retrieves the user ID.
  • An application of this approach is to remove the necessity of using a user ID (UID).
user = jwt.decode(token, current_app.config["SECRET_KEY"], algorithms=["HS256"])['_uid']

Frontend

  • In Chrome inspect, show response of JSON objects from fetch of GET, POST, and UPDATE methods.
    • This POST request forwards the login data to the backend in JSON format within the request body. Screenshot-2024-04-24-at-11-18-27-PM
  • In the Chrome browser, show a demo (GET) of obtaining an Array of JSON objects that are formatted into the browsers screen.
    • This script organizes the base64 data for all images in the database into a gallery table, enabling users to download the images. Screenshot-2024-04-24-at-11-18-58-PM
  • In JavaScript code, describe fetch and method that obtained the Array of JSON objects.
    • The constant apiUrl contains the URL of the API endpoint.
    • The variable images is an array that will eventually store the fetched data.
    • The fetchDatabase function is where the actual data fetching occurs.
    • It utilizes the Fetch API to initiate a network request to the API endpoint specified in apiUrl.
    • The fetch function returns a Promise that resolves to the Response object representing the response to the request. This response object is subsequently converted to JSON using the json method.
    • The then method is employed to specify the subsequent actions once the Promise is resolved. In this instance, it’s another Promise that verifies the status of the response.
const apiUrl = "https://memeforge.stu.nighthawkcodingsociety.com/api/memeforge/get_database";
        let images = [];
        function fetchDatabase() {
            fetch(apiUrl)
                .then(response => response.json())
                .then(response => {
                    if (response.status === 401) {
                        window.location.href = '/student/login';
                        return;
                    }
                    if (response.status === 403) {
                        window.location.href = '/student/403';
                        return;
                    }
                    images = JSON.parse(response).reverse();
                    displayImages(images);
                });
        }
  • In JavaScript code, show code that performs iteration and formatting of data into HTML.
    • The function initially selects the gallery element on the webpage using document.querySelector(‘.gallery’).
    • The function iterates over the images array using forEach. For each image object, it creates a new div element to act as a container for the gallery item (galleryItemContainer).
    • It also generates another div’ for the gallery item itself (galleryItem), an img element for the image, and a button for downloading the image.
    • The src attribute of the img element is configured to the base64 encoded string of the image data, and the alt attribute is set to the name of the image.
function displayImages(images) {
    const gallery = document.querySelector('.gallery');
    gallery.innerHTML = '';
    images.forEach((image, index) => {
        const galleryItemContainer = document.createElement('div');
        galleryItemContainer.className = 'gallery-item-container';
        const galleryItem = document.createElement('div');
        galleryItem.className = 'gallery-item';
        const img = document.createElement('img');
        img.src = 'data:image/jpeg;base64,' + image.image;
        img.alt = image.name;
        img.addEventListener('click', () => {
            openModal(image.image);
        });
        const button = document.createElement('button');
        button.textContent = 'Download';
        button.addEventListener('click', () => {
            downloadImage(image.image, image.name);
        });
        galleryItem.appendChild(img);
        galleryItem.appendChild(button);
        galleryItemContainer.appendChild(galleryItem);
        gallery.appendChild(galleryItemContainer);
    });
}
  • In the Chrome browser, show a demo (POST or UPDATE) gathering and sending input and receiving a response that show update. Repeat this demo showing both success and failure.
    • This converts the image into base64 data, which is then sent to the backend along with the top and bottom text.
    • The backend utilized PIL to overlay the text onto the image and then converted it back into base64 format.
    • The updated image is transmitted to the frontend, where it is subsequently displayed. Screenshot-2024-04-24-at-11-19-55-PM
  • In JavaScript code, show and describe code that handles success. Describe how code shows success to the user in the Chrome Browser screen.
    • If the backend successfully adds the text to the image, the frontend will exhibit a success message, and the image will be displayed.
    • Additionally, the user will have the capability to download the image onto their local machine.
  • In JavaScript code, show and describe code that handles failure. Describe how the code shows failure to the user in the Chrome Browser screen. (same code)
    • If an issue arises with the API, the user is promptly notified about the error and potentially informed about its cause.
    • This is beneficial for distinguishing between whether the backend is operational or if the image file already exists in the database.
fetch(url, image_options)
                    .then(response => {
                        if (response.status !== 200) {
                            error('Api error: ' + response.status);
                            return;
                        }
                        response.json().then(data => {
                            const memeImage = new Image();
                            memeImage.src = 'data:image/' + fileExtension + ';base64,' + data['base64image'];
    
                            memeImage.style.maxHeight = '100%';
    
                            uploadedImage.src = memeImage.src;
                            uploadedImage.style.display = 'block';
    
                            memeImage.onload = function () {
                                const parent = document.querySelector('.bottom-half');
                                const ratio = parent.clientWidth / memeImage.width;
    
                                if (ratio < 1) {
                                    const maxHeight = ratio * memeImage.height;
                                    parent.style.height = (maxHeight + 175) + 'px';
                                } else {
                                    parent.style.height = (memeImage.height + 175) + 'px';
                                }
                            };
                        });
                    });
    function handleDownloadClick() {
        const uploadedImage = document.getElementById('uploadedImage');
        const memeImage = new Image();
        memeImage.src = uploadedImage.src;

        if (uploadedImage.width == 0) {
            alert('Please upload an image before trying to download');
            return;
        }
        const downloadLink = document.createElement('a');
        downloadLink.href = memeImage.src;
        downloadLink.download = uploadedImageName.split('.')[0] + "_meme." + uploadedImageName.split('.')[1];
        downloadLink.style.display = 'none';

        document.body.appendChild(downloadLink);
        downloadLink.click();

        document.body.removeChild(downloadLink);

    }
    const downloadButton = document.getElementById('downloadButton');
    downloadButton.addEventListener('click', handleDownloadClick);