working demo
This commit is contained in:
parent
b194d2031d
commit
a8de581c09
6 changed files with 216 additions and 27 deletions
|
|
@ -45,7 +45,7 @@ passport.use(
|
||||||
// If the user is a parent, query the parent's students
|
// If the user is a parent, query the parent's students
|
||||||
// and store the students' UPNs in the session
|
// and store the students' UPNs in the session
|
||||||
else if (user_type === directory.USER_TYPE.PARENT) {
|
else if (user_type === directory.USER_TYPE.PARENT) {
|
||||||
let students = await directory.listStudents(username);
|
let students = await directory.getStudentsByParent(username);
|
||||||
profile["students"] = students;
|
profile["students"] = students;
|
||||||
} else {
|
} else {
|
||||||
console.log("Unknown user type");
|
console.log("Unknown user type");
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ async function getPrimaryParent(student_upn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listStudents(upn) {
|
async function getStudentsByParent(upn) {
|
||||||
// Search for students with the parent's UPN in their primaryParent attribute
|
// Search for students with the parent's UPN in their primaryParent attribute
|
||||||
let opts = {
|
let opts = {
|
||||||
filter: `(primaryParent=${upn})`,
|
filter: `(primaryParent=${upn})`,
|
||||||
|
|
@ -136,7 +136,7 @@ module.exports = {
|
||||||
getUserType: getUserType,
|
getUserType: getUserType,
|
||||||
getUserTypeFromDN: getUserTypeFromDN,
|
getUserTypeFromDN: getUserTypeFromDN,
|
||||||
setPrimaryParent: setPrimaryParent,
|
setPrimaryParent: setPrimaryParent,
|
||||||
listStudents: listStudents,
|
getStudentsByParent: getStudentsByParent,
|
||||||
getPrimaryParent: getPrimaryParent,
|
getPrimaryParent: getPrimaryParent,
|
||||||
USER_TYPE: USER_TYPE
|
USER_TYPE: USER_TYPE
|
||||||
};
|
};
|
||||||
|
|
@ -97,6 +97,9 @@ router.get('/parent/:parent_upn', async function (req, res) {
|
||||||
allowedAttributes.forEach(function (attribute) {
|
allowedAttributes.forEach(function (attribute) {
|
||||||
parent[attribute] = req.user[attribute];
|
parent[attribute] = req.user[attribute];
|
||||||
});
|
});
|
||||||
|
// Get the list of students linked to the parent
|
||||||
|
let students = await directory.getStudentsByParent(parent.username);
|
||||||
|
parent.students = students;
|
||||||
res.json(parent);
|
res.json(parent);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,8 @@ router.get('/student/:upn', function (req, res) {
|
||||||
allowedAttributes.forEach(function (attribute) {
|
allowedAttributes.forEach(function (attribute) {
|
||||||
student[attribute] = req.user[attribute];
|
student[attribute] = req.user[attribute];
|
||||||
});
|
});
|
||||||
|
// Return the student's linked parent in the response in JSON format
|
||||||
|
student['primary_parent'] = req.user['primaryParent'];
|
||||||
res.json(student);
|
res.json(student);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
152
statics/selfservice/parent.html
Normal file
152
statics/selfservice/parent.html
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
<!-- FILEPATH: /D:/Git/satitm-sso-node/statics/selfservice/student.html -->
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.parent-box {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-box {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-student {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#generate-token-btn {
|
||||||
|
background-color: #007bff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logout-btn {
|
||||||
|
background-color: #dc3545;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="input-modal" style="display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4);">
|
||||||
|
<div style="background-color: #fefefe; margin: 20% auto; padding: 20px; border: 1px solid #888; width: 50%; border-radius: 10px; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);">
|
||||||
|
<span id="input-close" style="color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer;">×</span>
|
||||||
|
<p>Please enter the link ID:</p>
|
||||||
|
<input id="link-id-input" type="text">
|
||||||
|
<button id="submit-btn">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="modal" style="display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4);">
|
||||||
|
<div style="background-color: #fefefe; margin: 20% auto; padding: 20px; border: 1px solid #888; width: 50%; border-radius: 10px; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);">
|
||||||
|
<span id="close" style="color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer;">×</span>
|
||||||
|
<p id="modal-text" style="font-size: 18px; color: #333;"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="parent-box">
|
||||||
|
<div class="inner-box">
|
||||||
|
<h2>Parent Information</h2>
|
||||||
|
<p><span id="parent-name">Name:</span> </p>
|
||||||
|
<p><span id="parent-surname">Surname:</span> </p>
|
||||||
|
<p><span id="parent-email">Email:</span> </p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="linked-student">
|
||||||
|
<h2>Linked Student</h2>
|
||||||
|
<p><span id="linked-student-info"></span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="generate-token-btn">Link a Student</button>
|
||||||
|
|
||||||
|
<a href="/selfservice/api/logout" style="text-decoration: none;">
|
||||||
|
<button id="logout-btn">Logout</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$.get('/selfservice/api/whoami')
|
||||||
|
.done(function(response) {
|
||||||
|
const upn = response.upn;
|
||||||
|
$.get(`/selfservice/api/parent/${upn}`)
|
||||||
|
.done(function(parent) {
|
||||||
|
$('#parent-name').text(`Name: ${parent.first_name}`);
|
||||||
|
$('#parent-surname').text(`Surname: ${parent.last_name}`);
|
||||||
|
$('#parent-email').text(`Email: ${parent.username}`);
|
||||||
|
// Linked student is in key "students" and is a list
|
||||||
|
// format as
|
||||||
|
// - Student 1
|
||||||
|
// - Student 2
|
||||||
|
// - Student 3
|
||||||
|
let student_str = '';
|
||||||
|
for (let i = 0; i < parent.students.length; i++) {
|
||||||
|
student_str += `- ${parent.students[i]}`
|
||||||
|
if (i < parent.students.length - 1) {
|
||||||
|
student_str += '<br>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#linked-student-info').html(student_str);
|
||||||
|
$('#generate-token-btn').click(function() {
|
||||||
|
$('#input-modal').show();
|
||||||
|
});
|
||||||
|
$('#submit-btn').click(function() {
|
||||||
|
const linkId = $('#link-id-input').val();
|
||||||
|
if (linkId) {
|
||||||
|
$.get(`/selfservice/api/parent/${upn}/add-student`, { 'pairing_code': linkId })
|
||||||
|
.done(function() {
|
||||||
|
showModal('Student linked successfully');
|
||||||
|
$('#input-modal').hide();
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
showModal('Failed to link student');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
showModal('Session expired, please login again');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/selfservice';
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
showModal('Session expired, please login again');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/selfservice';
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
function showModal(text) {
|
||||||
|
$('#modal-text').text(text);
|
||||||
|
$('#modal').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#close').click(function() {
|
||||||
|
$('#modal').hide();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -50,6 +50,13 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="modal" style="display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4);">
|
||||||
|
<div style="background-color: #fefefe; margin: 20% auto; padding: 20px; border: 1px solid #888; width: 50%; border-radius: 10px; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);">
|
||||||
|
<span id="close" style="color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer;">×</span>
|
||||||
|
<p id="modal-text" style="font-size: 18px; color: #333;"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="student-box">
|
<div class="student-box">
|
||||||
<div class="inner-box">
|
<div class="inner-box">
|
||||||
<h2>Student Information</h2>
|
<h2>Student Information</h2>
|
||||||
|
|
@ -69,26 +76,51 @@
|
||||||
<button id="logout-btn">Logout</button>
|
<button id="logout-btn">Logout</button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</body>
|
||||||
<script>
|
<script>
|
||||||
// Get student information on page load
|
|
||||||
// Student information is at /selfservice/api/student/${upn}
|
|
||||||
// UPN can be obtained from /selfservice/api/whoami
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$.get('/selfservice/api/whoami')
|
$.get('/selfservice/api/whoami')
|
||||||
.done(function(response) {
|
.done(function(response) {
|
||||||
$.get(`/selfservice/api/student/${response.upn}`)
|
const upn = response.upn;
|
||||||
|
$.get(`/selfservice/api/student/${upn}`)
|
||||||
.done(function(student) {
|
.done(function(student) {
|
||||||
$('#student-name').text(`Name: ${student.first_name}`);
|
$('#student-name').text(`Name: ${student.first_name}`);
|
||||||
$('#student-surname').text(`Surname: ${student.last_name}`);
|
$('#student-surname').text(`Surname: ${student.last_name}`);
|
||||||
$('#student-email').text(`Email: ${student.username}`);
|
$('#student-email').text(`Email: ${student.username}`);
|
||||||
|
$('#linked-parent-info').text(student.primary_parent ? `Email: ${student.primary_parent}` : 'No linked parent');
|
||||||
})
|
})
|
||||||
.fail(function() {
|
.fail(function() {
|
||||||
alert('Failed to get student information');
|
showModal('Session expired, please login again');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/selfservice';
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add click event handler to the "Generate Parent Link Token" button
|
||||||
|
$('#generate-token-btn').click(function() {
|
||||||
|
$.get(`/selfservice/api/student/${upn}/pairing-code`)
|
||||||
|
.done(function(pairingCode) {
|
||||||
|
showModal(`Your pairing code is: ${pairingCode}`);
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
showModal('Failed to generate pairing code');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.fail(function() {
|
.fail(function() {
|
||||||
alert('Failed to get user information');
|
showModal('Session expired, please login again');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/selfservice';
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
function showModal(text) {
|
||||||
|
$('#modal-text').text(text);
|
||||||
|
$('#modal').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#close').click(function() {
|
||||||
|
$('#modal').hide();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue