GoGrow is a python flask application consisting of several Python modules, javascript, HTML and .CSS files that handle various functionalities, including configuration management, database operations, file handling, and API endpoints, structure of the web pages, and styling of the elements on them. This documentation provides an overview of the key components and their functions.
Keep in mind many of these functions, endpoints, and settings may be deprecated or obsolete now or in the near future, or in need of refactoring - therefore much of what follows is subject to change at any time.
The backend code follows a specific file structure:
gogrow_app/
directory: Contains the core application files.app.py
: Initializes the Flask application and defines routes.settings.py
: Imports configuration data fromconfig.cfg
.__init__.py
: Initializes the Flask application package and serves the static folder.views.py
: Contains the main views and routes for the application.
Gogrow depends on Python 3.11. If installing and using as a flask application, please make sure you have installed the right version of Python.
The following Python packages are used in the backend, and will be installed automatically using pip if you follow the installation instructions in the included readme:
- altgraph
- bleach
- blinker
- click
- colorama
- dnspython
- Flask
- importlib-metadata
- itsdangerous
- Jinja2
- MarkupSafe
- pefile
- Pillow
- pip
- pyinstaller
- pyinstaller-hooks-contrib
- pywin32-ctypes
- setuptools
- six
- waitress
- webencodings
- Werkzeug
- zipp
- imageio
- numpy
- rawpy
- certifi
- charset-normalizer
- idna
- psutil
- requests
- urllib3
The application utilizes two configuration files: config.cfg
and settings.py
. These files are used to manage various settings and configurations for the application.
The config.cfg
file is where you can modify the settings to fit your application, like the custom theme and where the icon and thumbnail directories are located. It is recommended for securtity purposes to change the secret key.
The config.cfg file uses an INI-style format with sections and keys - below is an example config.cfg
with a terrible theme:
[AppSettings]
secret_key = YOUR_SECRET_KEY
[Directories]
icon_dir = icons
thumbnail_dir = thumbs
[ImageSettings]
image_folder = default_folder
[background]
texture = denim.png
[Theme]
mode = dark
[Custom Theme]
primary-bg = #ff0099
primary-text = #ffffff
secondary-bg = #00ffcc
secondary-text = #000000
table-row-bg = #9900ff
table-row-alt-bg = #ff9900
table-row-text = #ffffff
details-head-text = #ffffff
details-body-text = #000000
details-footer-text = #ffffff
about-head-text = #000000
about-body-text = #ffffff
about-footer-text = #000000
error-head-text = #ffffff
error-body-text = #000000
error-footer-text = #ffffff
right-side-column = #000000
edit-marker-modal = #ffffff
primary-hover-text = #ffcc00
primary-hover-bg = #3300ff
tertiary-bg = #00ffff
tertiary-bg-text = #000000
tertiary-bg-alt = #ffccff
tertiary-bg-alt-text = #000000
primary-btn-bg = #00ff00
primary-btn-text = #000000
secondary-btn-bg = #ff00cc
secondary-btn-text = #ffffff
The settings.py
file is responsible for loading the configuration settings from config.cfg
and applying them to the application.
import os
import secrets
import configparser
from gogrow_app import app
def load_app_settings():
config = configparser.ConfigParser()
config.read(os.path.join(app.root_path, 'config.cfg'))
app.secret_key = config.get('AppSettings', 'secret_key', fallback=secrets.token_hex(16))
app.config['ICON_DIR'] = os.path.join(app.root_path, config.get('Directories', 'icon_dir', fallback='icons'))
app.config['THUMBNAIL_DIR'] = os.path.join(app.root_path, config.get('Directories', 'thumbnail_dir', fallback='thumbs'))
app.config['IMAGE_FOLDER'] = config.get('ImageSettings', 'image_folder', fallback='default_folder')
print("Settings.py importing configuration data from config.cfg...")
load_app_settings()
IMAGE_FOLDER = app.config['IMAGE_FOLDER']
ICON_DIR = app.config['ICON_DIR']
THUMBNAIL_DIR = app.config['THUMBNAIL_DIR']
The frontend code of the application handles various functionalities related to map display, marker management, theme, and image handling. This documentation attempts to provide an overview of the key components and their functions. Apologies ahead of time - a bit could probably be refactored and simplified.
map
: Holds the map instance.icons
: Stores the icon data.iconDirectory
: Specifies the directory path for icons.markerListBody
: Represents the body element of the marker list table.markerInstances
: An array to store all marker instances.lineInstances
: An array to store all line instances.
- Description: Sets the text color of an element based on the background color.
- Parameters:
bgColor
: The background color.element
: The element to modify.
- Description: Initializes the index page.
- Actions:
- Retrieves the saved theme setting and applies it.
- Calls the
changeTheme
function.
- Description: Retrieves a setting value from the backend.
- Parameters:
section
: The section of the setting.key
: The key of the setting.
- Returns: The value of the setting.
- Description: Applies the saved map background texture.
- Actions:
- Retrieves the saved background texture setting and calls the
changeMapBackground
function.
- Retrieves the saved background texture setting and calls the
- Description: Changes the map background texture.
- Parameters:
texture
: The texture name.
- Actions:
- Modifies the background image and size of the map element.
- Description: Changes the theme of the application.
- Parameters:
theme
: The theme name.
- Actions:
- Modifies the body class to apply the selected theme.
- Description: Loads the image to display as an overlay on the map.
- Actions:
- Sends a request to the backend to retrieve the image URL.
- Calls the
addImageOverlay
function to add the image overlay to the map.
- Description: Adds an image overlay to the map.
- Parameters:
imageUrl
: The URL of the image to overlay.
- Returns: A promise that resolves when the image is loaded.
- Actions:
- Removes any existing image overlay from the map.
- Creates a new image overlay using the provided URL and bounds.
- Sets the map view to the center of the image.
- Description: Clears existing markers from the map and the marker list.
- Actions:
- Removes all marker instances from the map.
- Clears the marker list table.
- Description: Loads markers and lines for a specific folder.
- Parameters:
folderName
: The name of the folder.
- Actions:
- Fetches markers from the backend and creates marker instances.
- Fetches lines from the backend and creates line instances.
- Define global variables such as
map
,icons
,iconDirectory
,markerListBody
,markerInstances
, andlineInstances
. - Call the
initializeIndexPage
function to initialize the index page. - Use the
loadImage
function to load the image overlay. - Call the
clearExistingMarkers
function to clear existing markers. - Call the
loadFeatures
function to load markers and lines for a specific folder
This class extends L.Icon
and represents an SVG icon used as a Leaflet icon.
constructor(options)
: Creates a newSvgIcon
instance.options.iconUrl
: The URL of the SVG icon.options.iconColor
(optional): The color of the icon. Defaults to#000000
.
createIcon(oldIcon)
: Creates the icon element.oldIcon
: The existing icon element to reuse ornull
.- Returns: The created icon element.
This function loads the list of folders from the server and displays them on the page.
This function displays the list of folders on the page.
folderList
: An array of folder names.
This function loads the image and database for a specific folder.
folderName
: The name of the folder.- Returns: A Promise that resolves when the image and database are loaded.
This function generates a random UUID (Universally Unique Identifier).
- Returns: A randomly generated UUID.
This function updates a marker with new information.
markerUUID
: The UUID of the marker to update.description
: The updated description of the marker.iconType
: The updated icon type of the marker.iconColor
: The updated icon color of the marker.notes
: The updated notes of the marker.
This function adds a new marker to the map and table.
lat
: The latitude coordinate of the marker.lng
: The longitude coordinate of the marker.info
: The information or description of the marker.iconType
: The icon type of the marker.icon color
: The color of the marker icon.markerNotes
(optional): The notes associated with the marker.folderName
(optional): The name of the folder to associate the marker with.
This function creates a new marker on the map and adds it to the marker list table.
newMarkerData
: An object containing the marker data, includinglat
,lng
,info
,iconType
,iconColor
, andmarkerNotes
.- Returns: The created marker instance.
This function deletes a marker from the map and table.
markerUUID
: The UUID of the marker to delete.- Returns: A Promise that resolves when the marker is successfully deleted.
This function loads the list of folders from the server and displays them on the page.
This function displays the list of folders on the page.
folderList
: An array of folder names.
This function loads the image and database for a specific folder.
folderName
: The name of the folder.- Returns: A Promise that resolves when the image and database are loaded.
This function generates a random UUID (Universally Unique Identifier).
- Returns: A randomly generated UUID.
This function adds a new line to the map and table.
startLatLng
: The start coordinates of the line as aLatLng
object.endLatLng
: The end coordinates of the line as aLatLng
object.info
: Additional information about the line.color
: The color of the line.notes
(optional): The notes associated with the line.folderName
(optional): The name of the folder to associate the line with.
This function creates a new line on the map and adds it to the marker list table.
newLineData
: An object containing the line data, includingstart_lat
,start_lng
,end_lat
,end_lng
,info
,color
, andnotes
.- Returns: The created line instance.
This function deletes a line from the map and table.
lineUUID
: The UUID of the line to delete.- Returns: A Promise that resolves when the line is successfully deleted.
This function toggles the visibility of the markers on the map.
This function toggles the visibility of the lines on the map.
Event Listener: document.querySelector('#marker-list-body').addEventListener('click', async function (event)
This event listener handles the click event on the marker list table. It identifies if the click was made on a delete icon for a marker or line, retrieves the UUID and description of the corresponding item, and prompts the user to confirm the deletion. If confirmed, it calls the deleteMarker()
or deleteLine()
function accordingly.
This variable stores the current add mode, which can be either 'marker' or 'line'. It is initially set to 'marker' and can be toggled by clicking the toggle add mode button. The add mode determines whether clicking on the map creates a marker or a line.
This event listener executes when the page finishes loading. It initializes the map, loads the icons, and sets up event listeners for form submission, map clicks, input changes, and sidebar toggling.
This event listener handles the click event on the toggle add mode button. It toggles the add mode between 'marker' and 'line', and updates the button text accordingly.
Event Listener: sidebarToggler.addEventListener('click', toggleSidebar)
, navSidebarToggler.addEventListener('click', toggleSidebar)
, hideSidebarBtn.addEventListener('click', toggleSidebar)
These event listeners handle the click events on the sidebar toggler buttons. They toggle the visibility of the sidebar and adjust the map view accordingly.
Event Listener: document.querySelector('#marker-list-body').addEventListener('click', function (event)
This event listener handles the click event on the note cell of the marker list table. When clicked, it creates a modal to display the note associated with the marker or line. The modal is appended to the body and can be closed by clicking the close button.
This event listener handles the beforeunload event and closes any open popups on the map.
Event Listener: document.querySelector('#marker-list-body').addEventListener('click', function (event)
This event listener handles the click event on the ID cell of the marker list table. When clicked, it highlights the clicked ID cell by adding the 'highlight' class and removes the highlight from other ID cells.
lines(selected_dir=None): Handles GET and POST requests related to lines.
GET: Retrieves lines from the database.
POST: Adds a new line to the database.
update_line(): Updates an existing line in the database.
get_lines(image_folder=None): Retrieves lines from the database.
delete_line(): Deletes a line from the database.
get_markers(image_folder=None): Retrieves markers from the database.
markers(selected_dir=None): Handles GET and POST requests related to markers.
GET: Retrieves markers from the database.
POST: Adds a new marker to the database.
update_marker(): Updates an existing marker in the database.
delete_marker(): Deletes a marker from the database.
process_image_upload(image, image_directory): Handles the image upload process.
allowed_file(filename): Checks if the file extension is allowed.
create_directories_if_needed(image_directory, filename): Creates directories if they don't exist.
save_image_and_thumbnail(image, file_directory, filename): Saves the uploaded image and its thumbnail.
update_session_variables(filename, file_directory): Updates session variables for the uploaded image.
create_thumbnail(input_path, output_path, size): Creates a thumbnail image.
index(): Handles the main index page and image upload.
serve_image(filename): Serves images from the subdirectories.
get_icon_directory(): Retrieves the directory path for icons.
icon_filenames(): Retrieves a list of icon filenames.
serve_icon(icon_name): Serves icons.
get_image_url(selected_dir): Retrieves the URL of the latest image in the selected directory.
image_folders(): Retrieves a list of image folders.
export(folder): Exports markers and lines data as a CSV file.
details(): Renders the details page.
settings(): Renders the settings page.
about(): Renders the about page.
The backend provides the following API endpoints:
Lines API Endpoints
GET /lines/<selected_dir>
Description: Retrieves lines from the database for the specified directory.
Parameters:
selected_dir: The selected directory name (optional).
Returns: A JSON array of line objects.
POST /lines/<selected_dir>
Description: Adds a new line to the database for the specified directory.
Parameters:
- `selected_dir`: The selected directory name (optional).
- Request Body: JSON object containing line data.
Returns: A JSON object with the line_id of the newly added line.
POST /update_line
Description: Updates an existing line in the database.
Request Body: JSON object containing line data, including id, info, color, and notes.
Returns: Status code indicating the success of the operation.
POST /delete_line
Description: Deletes a line from the database.
Request Body: JSON object containing the id of the line to be deleted.
Returns: Status code indicating the success of the operation.
GET /markers/<selected_dir>
Description: Retrieves markers from the database for the specified directory.
Parameters:
- `selected_dir`: The selected directory name (optional).
Returns: A JSON array of marker objects.
POST /markers/<selected_dir>
Description: Adds a new marker to the database for the specified directory.
Parameters:
- `selected_dir`: The selected directory name (optional).
- Request Body: JSON object containing marker data.
Returns: A JSON object with the marker_id of the newly added marker.
POST /update_marker
Description: Updates an existing marker in the database.
Request Body: JSON object containing marker data, including id, info, iconType, iconColor, and markerNotes.
Returns: Status code indicating the success of the operation.
POST /delete_marker
Description: Deletes a marker from the database.
Request Body: JSON object containing the id of the marker to be deleted.
Returns: Status code indicating the success of the operation.
GET /get_icon_directory
Description: Retrieves the directory path for icons.
Returns: The directory path as a string.
GET /icon_filenames
Description: Retrieves a list of icon filenames.
Returns: A JSON array of icon filenames.
GET /get_image_url/<selected_dir>
Description: Retrieves the URL of the latest image in the selected directory.
Parameters:
- `selected_dir`: The selected directory name.
Returns: The URL of the latest image as a string.
GET /get_folders
Description: Retrieves a list of image folders.
Returns: A JSON array of folder names.
GET /export/<folder>
Description: Exports markers and lines data as a CSV file for the specified folder.
Parameters:
- `folder`: The folder name.
Returns: The exported CSV file.
The backend also provides the following routes:
GET /: The main index page that allows image upload and displays the uploaded image, markers, and icons. Handles both GET and POST requests.
GET /serve_image/<path:filename>: Serves images from the subdirectories.
GET /serve_icon/<path:icon_name>: Serves icons.
GET /backups: Retrieves a list of backup files stored in the "backups" directory. Returns a JSON array of backup filenames.
The backend provides routes for creating backups and restoring from backups:
POST /backup
Description: Creates a backup of the selected directory and its associated database file. The backup is stored in the "backups" directory as a compressed tarball file (.tar.gz).
Request Body: Form data containing the directory parameter specifying the selected directory.
Returns: A JSON object with the status ("success" or "error") and filename of the created backup, or an error message if the backup creation fails.
POST /restore
Description: Restores a previously created backup by extracting the tarball file. It checks for any conflicts with existing directories before proceeding with the restoration.
Request Body: Form data containing the backup_file parameter specifying the backup file to restore.
Returns: A JSON object with the status ("success" or "error"), indicating the success of the restoration process, or an error message if the restoration fails.