Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code coverage increase, and manual code trigger - src/flags.js #87

Open
wants to merge 10 commits into
base: f24
Choose a base branch
from
2 changes: 1 addition & 1 deletion src/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const utils = require('./utils');
const batch = require('./batch');

const Flags = module.exports;

Flags._states = new Map([
['open', {
label: '[[flags:state-open]]',
Expand Down Expand Up @@ -390,6 +389,7 @@ Flags.deleteNote = async function (flagId, datetime) {
};

Flags.create = async function (type, id, uid, reason, timestamp, forceFlag = false) {
console.log('Flags.created RAYYAN');
let doHistoryAppend = false;
if (!timestamp) {
timestamp = Date.now();
Expand Down
152 changes: 91 additions & 61 deletions src/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,25 @@ questions.optional = [
},
];

// gpt assisted code
function checkSetupFlagEnv() {
let setupVal = install.values;
const envConfMap = getEnvConfMap();
if (hasRelevantEnvVars(envConfMap)) {
winston.info('[install/checkSetupFlagEnv] checking env vars for setup info...');
setupVal = setUpValuesFromEnv(setupVal, envConfMap);
}
setupVal = getSetupValuesFromJson(setupVal);

if (setupVal && typeof setupVal === 'object') {
validateSetupValues(setupVal);
} else if (nconf.get('database')) {
setDatabaseValues();
}
}

const envConfMap = {
function getEnvConfMap() {
return {
CONFIG: 'config',
NODEBB_CONFIG: 'config',
NODEBB_URL: 'url',
Expand All @@ -66,90 +81,105 @@ function checkSetupFlagEnv() {
NODEBB_DB_NAME: 'database',
NODEBB_DB_SSL: 'ssl',
};
}

// Set setup values from env vars (if set)
function hasRelevantEnvVars(envConfMap) {
const envKeys = Object.keys(process.env);
if (Object.keys(envConfMap).some(key => envKeys.includes(key))) {
winston.info('[install/checkSetupFlagEnv] checking env vars for setup info...');
setupVal = setupVal || {};

Object.entries(process.env).forEach(([evName, evValue]) => { // get setup values from env
if (evName.startsWith('NODEBB_DB_')) {
setupVal[`${process.env.NODEBB_DB}:${envConfMap[evName]}`] = evValue;
} else if (evName.startsWith('NODEBB_')) {
setupVal[envConfMap[evName]] = evValue;
}
});
return Object.keys(envConfMap).some(key => envKeys.includes(key));
}

setupVal['admin:password:confirm'] = setupVal['admin:password'];
}
function setUpValuesFromEnv(setupVal, envConfMap) {
setupVal = setupVal || {};
Object.entries(process.env).forEach(([evName, evValue]) => {
if (evName.startsWith('NODEBB_DB_')) {
setupVal[`${process.env.NODEBB_DB}:${envConfMap[evName]}`] = evValue;
} else if (evName.startsWith('NODEBB_')) {
setupVal[envConfMap[evName]] = evValue;
}
});
setupVal['admin:password:confirm'] = setupVal['admin:password'];
return setupVal;
}

// try to get setup values from json, if successful this overwrites all values set by env
// TODO: better behaviour would be to support overrides per value, i.e. in order of priority (generic pattern):
// flag, env, config file, default
function getSetupValuesFromJson(setupVal) {
try {
if (nconf.get('setup')) {
const setupJSON = JSON.parse(nconf.get('setup'));
setupVal = { ...setupVal, ...setupJSON };
return { ...setupVal, ...setupJSON };
}
} catch (err) {
winston.error('[install/checkSetupFlagEnv] invalid json in nconf.get(\'setup\'), ignoring setup values from json');
}
return setupVal;
}

if (setupVal && typeof setupVal === 'object') {
if (setupVal['admin:username'] && setupVal['admin:password'] && setupVal['admin:password:confirm'] && setupVal['admin:email']) {
install.values = setupVal;
} else {
winston.error('[install/checkSetupFlagEnv] required values are missing for automated setup:');
if (!setupVal['admin:username']) {
winston.error(' admin:username');
}
if (!setupVal['admin:password']) {
winston.error(' admin:password');
}
if (!setupVal['admin:password:confirm']) {
winston.error(' admin:password:confirm');
}
if (!setupVal['admin:email']) {
winston.error(' admin:email');
}

process.exit();
}
} else if (nconf.get('database')) {
install.values = install.values || {};
install.values.database = nconf.get('database');
function validateSetupValues(setupVal) {
if (setupVal['admin:username'] && setupVal['admin:password'] && setupVal['admin:password:confirm'] && setupVal['admin:email']) {
install.values = setupVal;
} else {
winston.error('[install/checkSetupFlagEnv] required values are missing for automated setup:');
logMissingSetupValues(setupVal);
process.exit();
}
}

function logMissingSetupValues(setupVal) {
if (!setupVal['admin:username']) winston.error(' admin:username');
if (!setupVal['admin:password']) winston.error(' admin:password');
if (!setupVal['admin:password:confirm']) winston.error(' admin:password:confirm');
if (!setupVal['admin:email']) winston.error(' admin:email');
}

function setDatabaseValues() {
install.values = install.values || {};
install.values.database = nconf.get('database');
}

// GPT assisted code
function checkCIFlag() {
let ciVals;
const ciVals = getCIVals();

if (isValidCIVals(ciVals)) {
install.ciVals = ciVals;
} else {
handleMissingCIValues(ciVals);
}
}

function getCIVals() {
try {
ciVals = JSON.parse(nconf.get('ci'));
return JSON.parse(nconf.get('ci'));
} catch (e) {
ciVals = undefined;
return undefined;
}
}

function isValidCIVals(ciVals) {
return ciVals && ciVals instanceof Object &&
ciVals.hasOwnProperty('host') &&
ciVals.hasOwnProperty('port') &&
ciVals.hasOwnProperty('database');
}

function handleMissingCIValues(ciVals) {
winston.error('[install/checkCIFlag] required values are missing for automated CI integration:');

if (!ciVals.hasOwnProperty('host')) {
winston.error(' host');
}

if (ciVals && ciVals instanceof Object) {
if (ciVals.hasOwnProperty('host') && ciVals.hasOwnProperty('port') && ciVals.hasOwnProperty('database')) {
install.ciVals = ciVals;
} else {
winston.error('[install/checkCIFlag] required values are missing for automated CI integration:');
if (!ciVals.hasOwnProperty('host')) {
winston.error(' host');
}
if (!ciVals.hasOwnProperty('port')) {
winston.error(' port');
}
if (!ciVals.hasOwnProperty('database')) {
winston.error(' database');
}
if (!ciVals.hasOwnProperty('port')) {
winston.error(' port');
}

process.exit();
}
if (!ciVals.hasOwnProperty('database')) {
winston.error(' database');
}

process.exit();
}


async function setupConfig() {
const configureDatabases = require('../install/databases');

Expand Down
34 changes: 33 additions & 1 deletion test/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -1169,9 +1169,41 @@ describe('Flags', () => {
assert.strictEqual(statusCode, 200, `${opts.method.toUpperCase()} ${opts.uri} => ${statusCode}`);
}
});
// COPILOT ASSISTED CODE
describe('.getFlagIdByTarget()', () => {
it('should return the flagId for a post', async () => {
// Create a new post
const { postData } = await Topics.post({
cid: category.cid,
uid: uid1,
title: utils.generateUUID(),
content: utils.generateUUID(),
});
const postId = postData.pid;

const flagId = await Flags.create('post', postId, uid1, 'Test flag');
const result = await Flags.getFlagIdByTarget('post', postId);
assert.strictEqual(result, flagId.flagId);
await Flags.purge([flagId.flagId]); // Cleanup
});

it('should return the flagId for a user', async () => {
const userId = uid1;
const flagId = await Flags.create('user', userId, uid1, 'Test flag');
const result = await Flags.getFlagIdByTarget('user', userId);
assert.strictEqual(result, flagId.flagId);
await Flags.purge([flagId.flagId]); // Cleanup
});

it('should throw an error when type is invalid', async () => {
await assert.rejects(
Flags.getFlagIdByTarget('invalidType', 'someId'),
new Error('[[error:invalid-data]]')
);
});
});

it('should NOT allow access to privileged endpoints to moderators if the flag target is a post in a cid they DO NOT moderate', async () => {
// This is a new category the user will moderate, but the flagged post is in a different category
const { cid } = await Categories.create({
name: utils.generateUUID(),
});
Expand Down