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

Automated testing for the bug-log button in admin dashboard navigation (User Story 2) #45

Open
wants to merge 8 commits into
base: f24
Choose a base branch
from
55 changes: 54 additions & 1 deletion public/src/admin/dashboard/bug-logs.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,59 @@
'use strict';

define('admin/dashboard/bug-logs', [], () => {
define('admin/dashboard/bug-logs', ['jquery', 'api'], ($, api) => {
const BugLogs = {};

BugLogs.init = () => {
// Fetch and display bug logs
fetchBugLogs();

// Handle bug report submission
$('#submit-bug-report').on('click', submitBugReport);
};

function fetchBugLogs() {
api.get('/api/admin/get-bug-log')
.then((data) => {
const bugLogsContainer = $('#bug-logs-container');
bugLogsContainer.empty();

if (data.bugLogs && data.bugLogs.length > 0) {
data.bugLogs.forEach((log) => {
const logElement = $('<div>').addClass('bug-log');
logElement.append($('<p>').text(`User: ${log.user}`));
logElement.append($('<p>').text(`Description: ${log.description}`));
logElement.append($('<p>').text(`Timestamp: ${log.timestamp}`));
bugLogsContainer.append(logElement);
});
} else {
bugLogsContainer.append($('<p>').text('No bug logs found.'));
}
})
.catch((err) => {
console.error('Error fetching bug logs:', err);
$('#bug-logs-container').append($('<p>').text('Error fetching bug logs.'));
});
}

function submitBugReport() {
const description = $('#bug-report-description').val().trim();

if (!description) {
alert('Description is required');

Check warning on line 42 in public/src/admin/dashboard/bug-logs.js

View workflow job for this annotation

GitHub Actions / test

Unexpected alert
return;
}

api.post('/api/admin/submit-bug-report', { description })
.then(() => {
alert('Bug report submitted successfully');

Check warning on line 48 in public/src/admin/dashboard/bug-logs.js

View workflow job for this annotation

GitHub Actions / test

Unexpected alert
$('#bug-report-description').val('');
fetchBugLogs();
})
.catch((err) => {
console.error('Error submitting bug report:', err);
alert('Error submitting bug report');

Check warning on line 54 in public/src/admin/dashboard/bug-logs.js

View workflow job for this annotation

GitHub Actions / test

Unexpected alert
});
}

return BugLogs;
});
40 changes: 39 additions & 1 deletion src/controllers/admin/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,44 @@ dashboardController.getSearches = async (req, res) => {
});
};

const bugLogs = [];

dashboardController.getBugLogs = async function (req, res) {
res.render('admin/dashboard/bug-logs', {});
console.log('getbuglogs'); // Add logging
try {
// Sanitize and format bug logs before rendering
const sanitizedBugLogs = bugLogs.map(log => ({
user: validator.escape(String(log.user)),
description: validator.escape(String(log.description)),
timestamp: new Date(log.timestamp).toISOString(),
}));

// Pass the sanitized bug logs to the view for rendering
res.render('admin/dashboard/bug-logs', { bugLogs: sanitizedBugLogs });
} catch (error) {
console.error('Error fetching bug logs:', error); // Log the error for debugging
res.status(500).json({ message: 'Internal server error' });
}
};


dashboardController.submitBugReport = async function (req, res) {
try {
const { description } = req.body;
if (!description) {
return res.status(400).json({ message: 'Description is required' });
}

const sanitizedDescription = validator.escape(description);
const timestamp = Date.now();
const user = req.user ? req.user.username : 'Anonymous'; // Assuming req.user contains the user information

// Add the bug report to the in-memory array
bugLogs.push({ user, description: sanitizedDescription, timestamp });

res.status(201).json({ message: 'Bug report submitted successfully' });
} catch (error) {
console.error('Error submitting bug report:', error); // Log the error for debugging
res.status(500).json({ message: 'Internal server error' });
}
};
76 changes: 61 additions & 15 deletions src/views/bug-report-form.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bug Report Form</title>
<meta name="csrf-token" content="{{csrfToken}}">
<style>
.container {
background-color: #fff;
Expand Down Expand Up @@ -95,21 +96,66 @@
<input type="submit" value="Submit">
</form>
</div>
<script>
document.getElementById('bug-report-form').addEventListener('submit', function(event) {
event.preventDefault(); // Prevent the form from submitting the traditional way
const banner = document.getElementById('form-banner');
const form = document.getElementById('bug-report-form');
banner.style.display = 'block'; // Show the banner
banner.classList.add('show'); // Add the class to slide in the banner
setTimeout(() => {
banner.classList.remove('show'); // Remove the class to slide out the banner

</body>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('bug-report-form');
const banner = document.getElementById('form-banner');

form.addEventListener('submit', function(event) {
event.preventDefault();

const formData = new FormData(form);
const data = {
name: formData.get('name'),
email: formData.get('email'),
'bug-description': formData.get('bug-description')
};
console.log(data);

// Get CSRF token from meta tag or other source
const csrfTokenMeta = document.querySelector('meta[name="csrf-token"]');
const csrfToken = csrfTokenMeta ? csrfTokenMeta.getAttribute('content') : '';

fetch('/api/admin/submit-bug-report', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'CSRF-Token': csrfToken // Include CSRF token in headers
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(result => {
if (result.success) {
banner.textContent = 'Form Submitted Successfully';
banner.classList.add('show');
setTimeout(() => {
banner.classList.remove('show');
}, 3000);
} else {
banner.textContent = 'Form Submission Failed';
banner.classList.add('show');
setTimeout(() => {
banner.style.display = 'none'; // Hide the banner after the slide out
}, 500); // Match the transition duration
}, 3000); // Display the banner for 3 seconds
form.reset(); // Reset the form fields
banner.classList.remove('show');
}, 3000);
}
})
.catch(error => {
console.error('Error:', error);
banner.textContent = 'Form Submission Failed';
banner.classList.add('show');
setTimeout(() => {
banner.classList.remove('show');
}, 3000);
});
</script>
</body>
});
});
</script>
</html>
12 changes: 12 additions & 0 deletions test/controllers-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ describe('Admin Controllers', () => {
});
});

it('should load admin dashboard with bug-logs', async () => {
await groups.join('administrators', adminUid);
const dashboards = [
'/admin', '/admin/dashboard/logins', '/admin/dashboard/users', '/admin/dashboard/topics', '/admin/dashboard/searches', '/admin/dashboard/bug-logs',
];
await async.each(dashboards, async (url) => {
const { response, body } = await request.get(`${nconf.get('url')}${url}`, { jar: jar });
assert.equal(response.statusCode, 200, url);
assert(body);
});
}); // Ensure no tab characters or trailing spaces here

it('should load admin analytics', async () => {
const { response, body } = await request.get(`${nconf.get('url')}/api/admin/analytics?units=hours`, { jar: jar });
assert.equal(response.statusCode, 200);
Expand Down