const BaseDatabaseController = require('./BaseDatabaseController');
/** Class representing a user controller. */
class UserController extends BaseDatabaseController {
/** Create a user controller. */
constructor() {
super();
}
/**
* Get a user by id.
*
* @param {number} id
* @returns {Promise<object>}
*/
async byId(id) {
const userResponse = await this._query('SELECT * FROM users WHERE id = ?', id);
if (userResponse.length !== 1) {
return null;
}
return userResponse[0];
}
/**
* Get a user by account identifier.
*
* @param {string} accountIdentifier
* @returns {Promise<object>}
*/
async byAccountIdentifier(accountIdentifier) {
const userResponse = await this._query('SELECT * FROM users WHERE account_identifier = ?', accountIdentifier);
if (userResponse.length !== 1) {
return null;
}
return userResponse[0];
}
/**
* Insert a user.
*
* @param {string} name
* @param {string} accountIdentifier
* @param {string} authToken
* @param {string} authMethod
* @returns {Promise<object>}
*/
async insert(name, accountIdentifier, authToken, authMethod) {
const userResponse = await this._query('INSERT INTO users (name, account_identifier, auth_token, auth_method) VALUES (?, ?, ?, ?)', name, accountIdentifier, authToken, authMethod);
return await this.byId(userResponse.insertId);
}
/**
* Delete a user.
*
* @param {number} userId
* @returns {Promise<void>}
*/
async delete(userId) {
await this._query('DELETE FROM users WHERE id = ?', userId);
}
/**
* Set a meta value for a user.
*
* @param {number} userId
* @param {string} name
* @param {any} value
* @returns {Promise<void>}
*/
async setMeta(userId, name, value) {
const existsCheck = await this._query('SELECT * FROM users_meta WHERE user_id = ? AND name = ?', userId, name);
if (existsCheck.length === 0) {
await this._query('INSERT INTO users_meta (user_id, name, value) VALUES (?, ?, ?)', userId, name, value);
} else {
await this._query('UPDATE users_meta SET value = ? WHERE user_id = ? AND name = ?', value, userId, name);
}
}
/**
* Get a meta value for a user.
*
* @param {number} userId
* @param {string} name
* @returns {Promise<any>}
*/
async getMeta(userId, name) {
const meta = await this._query('SELECT * FROM users_meta WHERE user_id = ? AND name = ?', userId, name);
if (meta.length === 0) {
return null;
}
return meta[0].value;
}
/**
* Add a contribution to a user.
*
* @param {number} userId
* @param {string} contributionCode
* @returns {Promise<void>}
*/
async addContribution(userId, contributionCode, contributionRecordId) {
const contributionType = await this._query('SELECT * FROM contribution_types WHERE code = ?', contributionCode);
if (contributionType.length !== 1) {
return;
}
await this._query('INSERT INTO user_contributions (user_id, contribution_type_id, contribution_record_id) VALUES (?, ?, ?)', userId, contributionType[0].id, contributionRecordId);
}
/**
* Get the contribution points of a user.
*
* @param {number} userId
* @returns {Promise<number>}
*/
async getContributionPoints(userId) {
const contributionPoints = await this._query('SELECT SUM(ct.point_value) AS points FROM user_contributions AS uc JOIN contribution_types AS ct WHERE uc.contribution_type_id = ct.id AND uc.user_id = ?', userId);
return contributionPoints[0].points;
}
/**
* Get the goals of a user.
*
* @param {number} userId
* @returns {Promise<object[]>}
*/
async getGoals(userId) {
const allGoals = await this._query('SELECT * FROM user_goals');
const goals = [];
for (const goal of allGoals) {
const goalDescriptionsAndProgress = await this._query('SELECT ugd.id, ugd.target, ugd.description, ugp.progress FROM user_goal_descriptions AS ugd LEFT JOIN user_goal_progress AS ugp ON ugd.id = ugp.goal_desc_id WHERE ugd.goal_id = ? AND ugp.user_id = ?', goal.id, userId);
if (goalDescriptionsAndProgress.length === 0) {
continue;
}
const amountOfPeopleWhoAchievedGoal = await this._query('SELECT COUNT(DISTINCT user_id) AS count FROM user_goal_progress AS ugp JOIN user_goal_descriptions AS ugd ON ugp.goal_desc_id = ugd.id WHERE ugd.goal_id = ? AND ugp.progress >= ugd.target', goal.id);
const goalData = {
id: goal.id,
name: goal.name,
color: goal.color,
icon: goal.icon,
amountOfPeopleWhoAchievedGoal: amountOfPeopleWhoAchievedGoal[0].count,
descriptions: goalDescriptionsAndProgress.map((goalDescription) => {
return {
id: goalDescription.id,
target: goalDescription.target,
description: goalDescription.description,
progress: goalDescription.progress,
};
}),
};
goals.push(goalData);
}
return goals;
}
/**
* Add goals to a user if they do not exist.
*
* @param {number} userId
* @returns {Promise<void>}
*/
async addGoalsIfNotExists(userId) {
const goals = await this._query('SELECT * FROM user_goals');
const userGoals = await this._query('SELECT * FROM user_goal_progress WHERE user_id = ?', userId);
for (const goal of goals) {
if (userGoals.filter((userGoal) => userGoal.goal_desc_id === goal.id).length === 0) {
const goalDescriptions = await this._query('SELECT * FROM user_goal_descriptions WHERE goal_id = ?', goal.id);
for (const goalDescription of goalDescriptions) {
await this._query('INSERT INTO user_goal_progress (user_id, goal_desc_id) VALUES (?, ?)', userId, goalDescription.id);
}
}
}
}
/**
* Change the progress of a goal by the track name.
*
* @param {number} userId
* @param {string} goalName
* @param {string} goalDesc
* @param {number} changeByAmount
* @returns {Promise<void>}
*/
async changeGoalProgressByTrackName(userId, goalName, goalDesc, changeByAmount) {
const goals = await this._query('SELECT * FROM user_goals WHERE name LIKE ?', `%${goalName}`);
for (const goal of goals) {
const goalDescriptions = await this._query('SELECT * FROM user_goal_descriptions WHERE goal_id = ? AND description = ?', goal.id, goalDesc);
for (const goalDescription of goalDescriptions) {
await this._query('UPDATE user_goal_progress SET progress = progress + ? WHERE user_id = ? AND goal_desc_id = ?', changeByAmount, userId, goalDescription.id);
}
}
}
/**
* Get a contribution type by code.
*
* @param {string} code
* @returns {Promise<object>}
*/
async getContributionType(code) {
const contributionType = await this._query('SELECT * FROM contribution_types WHERE code = ?', code);
if (contributionType.length !== 1) {
return null;
}
return contributionType[0];
}
/**
* Get the scans of a user.
*
* @param {number} userId
* @returns {Promise<object[]>}
*/
async getScans(userId) {
return await this._query('SELECT * FROM scans WHERE user_id = ?', userId);
}
}
module.exports = UserController;