Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6f2de01
#70 Updated Docks for new settings feature
CoderTobi Nov 19, 2025
4bfca56
#70 Finished planing API and updating docs
CoderTobi Nov 19, 2025
01b1a67
Updated package versions
CoderTobi Nov 19, 2025
79967c7
#70 Added DB migration to add settings table
CoderTobi Nov 19, 2025
82839d0
#70 corrected API
CoderTobi Nov 19, 2025
d44e18e
#70 added default value for "watering_profile" and more logs to dbMig…
CoderTobi Nov 19, 2025
85fab1e
#70 added settings DAO and API Endpoint with validation
CoderTobi Nov 19, 2025
8d4fbf4
#70 Added TODOs to Backend
CoderTobi Nov 19, 2025
93e3254
#70 finished DB Migration Tool
CoderTobi Nov 21, 2025
17eadec
updated API Docs, null when never repotted
CoderTobi Nov 23, 2025
236a366
Updated plantsDao
CoderTobi Nov 23, 2025
ecdc19d
changed calculateDaysBetween from floor to round
CoderTobi Nov 23, 2025
02c1201
#70 fixed incorrect use of extendPlantObject and extendPlantObjects
CoderTobi Nov 23, 2025
50185a3
#70 updated plants service
CoderTobi Nov 23, 2025
2a72743
#70 fixed days_until_watering being of by a day
CoderTobi Nov 23, 2025
7abfaf3
#70 Made days since and until calculations more robust because they w…
CoderTobi Nov 24, 2025
ce7139d
#70 removed wateringIntervalToLocation from Frontend as its not neede…
CoderTobi Nov 24, 2025
fe527ea
#77 Cleaned up activitiesDao
CoderTobi Nov 24, 2025
3b699e5
#70 basic implementation of the new intervals. Probably better with l…
CoderTobi Nov 24, 2025
2312080
#70 forgot to change SQL Statement for update in plantsDao
CoderTobi Nov 25, 2025
ac122c0
#70 added colors to CSS for the three temperatures
CoderTobi Nov 25, 2025
4fc86ae
#70 redesigned plant details page
CoderTobi Nov 25, 2025
b8af32f
Added user feedback for saving changes
CoderTobi Nov 26, 2025
199a9f4
#70 Updated plant edit page now includes new intervals
CoderTobi Nov 26, 2025
d79b57c
Added basic validation to plant edit page
CoderTobi Nov 26, 2025
6cac5d4
Moved navbar JS into its own file
CoderTobi Dec 11, 2025
eebc091
#70 added watering profile selector to navbar
CoderTobi Dec 11, 2025
792c8b4
#70 added TODOs
CoderTobi Dec 14, 2025
66ed3d3
#70 Added functions to fetch and update settings in the backend
CoderTobi Dec 14, 2025
b7979de
#70 Added WIP JS Code for the Watering Profile Selector
CoderTobi Dec 14, 2025
0334034
Alerts Display now initializes itself
CoderTobi Mar 30, 2026
cee01ab
#70 Fixed and implemented error handling on wps
CoderTobi Mar 30, 2026
3346384
#70 Dashboard and plant overview now updated when WPS changes
CoderTobi Mar 30, 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
133 changes: 103 additions & 30 deletions backend/dao/activitiesDao.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,92 @@ class activitiesDao {
this._conn = dbConnection;
}

/**
* Adds additional information to the provided activity.
* Note: This method modifies the activity object in place.
* Not intended to be called from outside the DAO.
* @param {object} activities The activity object to process
*/
#extendActivityObject(activity) {
if (activity && activity.date) {
const activityDate = new Date(activity.date);
const currentDate = new Date();
const daysSince = helper.calculateDaysBetween(activityDate, currentDate);
activity.days_since = daysSince;
}
}

/**
* Adds additional information to each activity in the provided array.
* Note: This method modifies the activity objects in place.
* Not intended to be called from outside the DAO.
* @param {object[]} activities The array of activity objects to process
*/
#extendActivityObjects(activities) {
activities.forEach(activity => {
this.#extendActivityObject(activity);
});
}

/**
* Loads an activity by its ID
* @param {int} id The activity ID
* @returns The activity object
*/
loadById(id) {
var sql = 'SELECT * FROM activities WHERE id=? ORDER BY date DESC';
var statement = this._conn.prepare(sql);
var result = statement.get(id);
let sql = 'SELECT * FROM activities WHERE id=? ORDER BY date DESC';
let statement = this._conn.prepare(sql);
let result = statement.get(id);

if (helper.isUndefined(result)){
throw new Error('No record found by id=' + id);
}

this.#extendActivityObject(result);
return result;
}

/**
* Loads all activities for a given plant ID
* @param {int} plant_id The plant ID
* @returns {object[]} An array of activity objects
*/
loadByPlantId(plant_id)
{
var sql = 'SELECT * FROM activities WHERE plant_id=? ORDER BY date DESC';
var statement = this._conn.prepare(sql);
var result = statement.all(plant_id);
var arrayResult = daoHelper.guaranteeArray(result);
let sql = 'SELECT * FROM activities WHERE plant_id=? ORDER BY date DESC';
let statement = this._conn.prepare(sql);
let result = statement.all(plant_id);
let arrayResult = daoHelper.guaranteeArray(result);
this.#extendActivityObjects(arrayResult);
return arrayResult;
}

/**
* Loads all activities for a given plant ID and activity type
* @param {int} plant_id The plant ID
* @param {int} type The activity type
* @returns {object[]} An array of activity objects
*/
loadByPlantIdAndType(plant_id, type)
{
var sql = 'SELECT * FROM activities WHERE plant_id=? AND type=? ORDER BY date DESC';
var statement = this._conn.prepare(sql);
var params = [plant_id, type];
var result = statement.get(params);
var arrayResult = daoHelper.guaranteeArray(result);
let sql = 'SELECT * FROM activities WHERE plant_id=? AND type=? ORDER BY date DESC';
let statement = this._conn.prepare(sql);
let params = [plant_id, type];
let result = statement.get(params);
let arrayResult = daoHelper.guaranteeArray(result);
this.#extendActivityObjects(arrayResult);
return arrayResult;
}

/**
* Checks if an activity exists by its ID
* @param {int} id The activity ID
* @returns {boolean} true if the activity exists, false otherwise
*/
exists(id) {
var sql = 'SELECT COUNT(id) AS cnt FROM activities WHERE id=?';
var statement= this._conn.prepare(sql);
var result = statement.get(id);
let sql = 'SELECT COUNT(id) AS cnt FROM activities WHERE id=?';
let statement= this._conn.prepare(sql);
let result = statement.get(id);

if (result.cnt == 1){
return true;
Expand All @@ -54,51 +105,73 @@ class activitiesDao {
return false;
}

/**
* Creates a new activity record
* @param {number} plant_id The plant ID
* @param {number} type The activity type
* @param {String} date The activity date (YYYY-MM-DD)
* @returns {object} The created activity object
*/
create(plant_id, type, date) {
if (typeof(plant_id) != "number"){
throw new Error('Could not insert new record. Invalid plant id of type ' + typeof(plant_id));
}
if (typeof(type) != "number"){
throw new Error('Could not insert new record. Invalid activity type of type ' + typeof(type));
}
var formatted_date = helper.formatToSQLDate(date);
var sql = 'INSERT INTO activities (plant_id, type, date) VALUES (?,?,?)';
var statement = this._conn.prepare(sql);
var params = [plant_id, type, formatted_date];
var result = statement.run(params);
let sql = 'INSERT INTO activities (plant_id, type, date) VALUES (?,?,?)';
let statement = this._conn.prepare(sql);
let params = [plant_id, type, date];
let result = statement.run(params);

if (result.changes != 1){
throw new Error('Could not insert new record. Data: ' + params);
}

return this.loadById(result.lastInsertRowid);
let createdActivity = this.loadById(result.lastInsertRowid);
this.#extendActivityObject(createdActivity);
return createdActivity;
}

/**
* Updates an existing activity record
* @param {number} id The activity ID
* @param {number} plant_id The plant ID
* @param {number} type The activity type
* @param {String} date The activity date (YYYY-MM-DD)
* @returns {object} The updated activity object
*/
update(id, plant_id, type, date) {
if (typeof(plant_id) != "number"){
throw new Error('Could not update existing record. Invalid plant id of type ' + typeof(plant_id));
}
if (typeof(type) != "number"){
throw new Error('Could not update existing record. Invalid activity type of type ' + typeof(type));
}
var formatted_date = helper.formatToSQLDate(date);
var sql = 'UPDATE activities SET plant_id=?, type=?, date=? WHERE id=?';
var statement = this._conn.prepare(sql);
var params = [plant_id, type, formatted_date, id];
var result = statement.run(params);
let sql = 'UPDATE activities SET plant_id=?, type=?, date=? WHERE id=?';
let statement = this._conn.prepare(sql);
let params = [plant_id, type, date, id];
let result = statement.run(params);

if (result.changes != 1){
throw new Error('Could not update existing record. Data: ' + params);
}

return this.loadById(id);
let updatedActivity = this.loadById(id);
this.#extendActivityObject(updatedActivity);
return updatedActivity;
}

/**
* Deletes an activity by its ID
* @param {number} id The activity ID
* @returns {boolean} true if the activity was deleted, false otherwise
*/
delete(id) {
try{
var sql = 'DELETE FROM activities WHERE id=?';
var statement = this._conn.prepare(sql);
var result = statement.run(id);
let sql = 'DELETE FROM activities WHERE id=?';
let statement = this._conn.prepare(sql);
let result = statement.run(id);

if (result.changes != 1){
throw new Error('Could not delete record by id=' + id);
Expand Down
Loading