De classroom API kan gebruikt worden voor allerhande acties op bestaande classrooms.
Vermits dit een vrij complexe hoeveelheid aan data geeft is er een meervoud aan interacties tussen verschillende tabellen nodig.
In volgende hoofdstukken zullen we een aantal pijnpunten aankaarten en bespreken.
Cursussen waarin cursisten zitten die niet meer bestaan, zorgen bij het editeren van bepaalde topics voor problemen, zeker wanneer je wil werken met een flexibele instap in een cursus, waarbij het open zetten van topic afhankelijk van de behaalde competenties wordt gebruikt.
Deze "UnknownStudents" kan je via deze lijst achterhalen en zo weet je ook in welke classroom je op zoek moet naar "weeskinderen".
Je kan enkel studenten bekijken in een classroom waarin jij als docent bent ingeschreven.
Het is mogelijk dat een student in meerdere calssrooms waarin jij docent bent, is ingeschreven.
De lijst geeft je heel wat informatie nodig voor verdere zoekacties, waarbij de courseID, calendarID, coursealternateLink nuttig kunnen zijn voor verdere afvragingen.
/**
* listCourses
* List all courses where you are member of as teacher or student.
*
* @return {array} courselist array of objects
* Object fields:
* CourseName, CourseId, CourseCalendarId,...
* UnknownStudentCount: indicates of a course has students enlisted, that do no longer exist, should be 0
* IsTeacher:
* -True if you are enlisted as teacher -> Array of students is populeted
* -False -> array of students is nonexisting
*
*
*/
function listCourses() {
var classroomdata = {}
let pageToken = ''
let courseList = []
let responseC = ''
do {
let optionalArgs = {
pageSize: 20,
pageToken: pageToken,
}
responseC = Classroom.Courses.list(optionalArgs);
let courses = responseC.courses;
if (courses && courses.length > 0) {
let courserec = courses.map(course => {
let obj = {}
obj.CourseName = course.name
obj.CourseID = course.id
obj.CourseCalendarId = course.calendarId
obj.CourseTeacherGroupEmail = course.teacherGroupEmail
obj.CourseCourseGroupEmail = course.courseGroupEmail
obj.CourseAlternateLink = course.alternateLink
obj.CourseOwnerId = course.ownerId
obj.CourseEnrollmentCode = course.enrollmentCode
obj.UnknownStudentCount = 0
if (course.hasOwnProperty("teacherFolder")) {
obj.CourseTeacherFolder = course.teacherFolder.id
obj.IsTeacher = true
obj.StudentList = ""
let responseS = Classroom.Courses.Students.list(course.id)
let students = responseS.students
let Stlist = ""
if (students && students.length > 0) {
for (let sc = 0; sc < students.length; sc++) {
if (students[sc].profile.name.fullName != "Unknown user") {
if (sc == 0) {
Stlist = students[sc].profile.name.fullName
} else {
Stlist = Stlist.concat(",")
Stlist = Stlist.concat(students[sc].profile.name.fullName)
}
} else {
obj.UnknownStudentCount = obj.UnknownStudentCount + 1
}
}
}
obj.StudentList = Stlist
} else {
obj.IsTeacher = false
}
return obj
})
courseList = courseList.concat(courserec)
} else {
Logger.log('No courses found.');
}
pageToken = responseC.nextPageToken;
} while (pageToken != null);
InitSheet_("Classrooms")
let courses = ConvertObjArr(courseList)
ObjectToTable(courses, "Classrooms")
return courseList
}
De lijst die wordt opgesteld wordt gemaakt uit een combinatie van de studentenlijsten uit de vershillende classrooms en de alias adressen.
Het gebruik van alias adressen laat toe om scores van een gebruiker samen te brengen onder één primair adres, zodat ondanks het gebruik van verschillende email adressen toch alles verzameld wordt van één gebruiker.
Door de "StudentInNrCourses" krijg je een overzicht van in hoeveel cursussen deze cursist is ingeschreven, waarin jij docent bent.
StudentID en StudentEmail zijn gevens die nodig zijn voor verdere zoekacties.
/**
* ListOwnStudents
* List all unique students in all your courses where you are a teacher.
* @param {string} aliaslist, sheetname of sheet with Aliasses: FullName, Email, AliasEmail1....
* @return {object} object of studentlist FullName, Email, Photo, StudentInNrCourses, StudentId
*
*
*/
function ListOwnStudents(aliaslist) {
var ownstudents = {
'FullName': [],
'Email': [],
'Photo': [],
//'CourseID': [],
//'CourseName': [],
'StudentInNrCourses': [],
'StudentId': [],
}
let pageToken = ''
let pageTokenS = ''
let courseList = []
let responseC = ''
do {
let optionalArgs = {
pageSize: 20,
pageToken: pageToken,
}
responseC = Classroom.Courses.list(optionalArgs);
let courses = responseC.courses;
if (courses && courses.length > 0) {
courses.map(course => {
if (course.hasOwnProperty("teacherFolder")) {
do {
let optionalArgsS = {
pageSize: 20,
pageToken: pageTokenS,
}
let responseS = Classroom.Courses.Students.list(course.id, optionalArgsS)
let students = responseS.students
if (students && students.length > 0) {
// look for next record in Array of key values
let recnr = ownstudents.FullName.length
for (let sc = 0; sc < students.length; sc++) {
if (students[sc].profile.name.fullName != "Unknown user") {
//User does not exist in list, based on email address
let SE = ownstudents.Email.indexOf(students[sc].profile.emailAddress)
if (SE == -1) {
ownstudents.FullName[recnr] = students[sc].profile.name.fullName
ownstudents.Email[recnr] = students[sc].profile.emailAddress
ownstudents.Photo[recnr] = students[sc].profile.photoUrl
//ownstudents.CourseID[recnr] = course.id
//ownstudents.CourseName[recnr] = course.name
ownstudents.StudentInNrCourses[recnr] = 1
ownstudents.StudentId[recnr] = students[sc].profile.id
recnr++
} else {
ownstudents.StudentInNrCourses[SE] = ownstudents.StudentInNrCourses[SE] + 1
}
}
}
}
pageTokenS = responseS.nextPageToken
} while (pageTokenS != null);
} return
})
} else {
Logger.log('No courses found.');
}
pageToken = responseC.nextPageToken;
} while (pageToken != null);
ObjectToTable(ownstudents, "UsersList")
ListAliasEmails("Aliasses", "AliasEmails", "UsersList")
//cleanup list, eliminating doubles and aliasses
let cleanownstudents = CheckAliases(ownstudents, aliaslist)
return cleanownstudents
}
Functie die aan de hand van de aliasses die ingegeven worden in een sheet, de studentenlijst opkuist en enkel de primaire email adressen laat zien.
Dit moet de selectie in de rapportering vergemakkelijken.
/**
* CheckAliasses (helperfunction)
* @param {object} object of studentlist FullName, Email, Photo, StudentInNrCourses
* @param {sheet} aliasses of studentemails: FullName, Email, AliasEmail1....
* @return {object} object of studentlist FullName, Email, Photo, StudentInNrCourses
*
* Walk through the student list and looks for aliasses.
* if an alias email is found, StudentInNrCourses for the primary email is incremented.
* if a student is found in multiple course, StudentInNrCourses for the primary email is incremented.
* Result is a unique list of students and nbr of courses/student
* List can be used to generate reports.
*/
function CheckAliases(obj, sheet) {
let EmailAlias = TableToObject(sheet)
var retobj = {
'FullName': [],
'Email': [],
'Photo': [],
//'CourseID': [],
//'CourseName': [],
'StudentInNrCourses': [],
'StudentId': []
}
// Bepalen aantal alias kolommen
var keys = Object.keys(EmailAlias)
// Loop voor checken alle aliasses
let rc = 0 //return object record counter
for (r = 0; r < obj.Email.length; r++) {
let semail = obj.Email[r]
let AES = EmailAlias.Email.indexOf(semail)
//create array with indexes to Alias columns
let idxf = []
let found = -1
for (i = 0; i < keys.length - 2; i++) {
idxf[i] = EmailAlias[`AliasEmail${i + 1}`].indexOf(semail)
//check for any alias found
if (found == -1) {
if (idxf[i] !== -1) { found = idxf[i] }
}
}
//primary key does not exist in output object
if (retobj.Email.indexOf(semail) == -1) {
// if not found in alias -> copy record and move on to next
if (found == -1) {
retobj.FullName[rc] = obj.FullName[r]
retobj.Email[rc] = obj.Email[r]
retobj.Photo[rc] = obj.Photo[r]
retobj.StudentInNrCourses[rc] = obj.StudentInNrCourses[r]
retobj.StudentId[rc] = obj.StudentId[r]
rc++
//found as any alias
} else {
//walk through indexes
for (fi = 0; fi < idxf.length; fi++) {
if (idxf[fi] != -1) {
let SE = obj.Email.indexOf(EmailAlias.Email[idxf[fi]])
let SE2 = retobj.Email.indexOf(EmailAlias.Email[idxf[fi]])
if (SE != 1 && SE2 == -1) {
//Bestaat in input maar nog niet in output -> update input obj
obj.StudentInNrCourses[SE] = obj.StudentInNrCourses[SE] + 1
} else {
//Bestaat reeds in output
retobj.StudentInNrCourses[SE2] = retobj.StudentInNrCourses[SE2] + 1
}
}
}
}
}
}
return retobj
}
De topics binnen een cursus moeten apart afgevraagd worden.
Deze functie lijst alle topics in alle cursussen waarin jij docent bent met alle gegevens die er in het topic beschikbaar zijn.
/**
* Helperfunctie getTopics_
* @param {object} object, result of classroom search
* @parameter {string} courseId
* @return {array} Topics, array of objects
*/
function getTopics_(obj, courseId) {
let pageToken = ''
let topicList = []
let responseT = ''
do {
let optionalArgs = {
pageSize: 100,
pageToken: pageToken,
}
responseT = Classroom.Courses.Topics.list(courseId)
let topicslists = responseT.topic;
if (topicslists && topicslists.length > 0) {
topicslists.map(topic => {
topicList.push(topic)
})
} else {
Logger.log('No topics found');
}
pageToken = responseT.nextPageToken;
} while (pageToken != null);
return topicList
}
Ook de coursework, opdrachten moetn apart afgevraagd worden.
Deze functie maakt eveneens een lijst van alle opdrachten en alle gegevens die daarin beschikbaar zijn.
/**
* Helperfunctie getWorks_
* @param {object} object, result of classroom search
* @param {string} courseId
* @return {array} Topics, array of objects
*/
function getWorks_(obj, courseId) {
let pageToken = ''
let WorksList = []
let responseW = ''
do {
let optionalArgs = {
pageSize: 100,
pageToken: pageToken,
}
responseW = Classroom.Courses.CourseWork.list(courseId)
let workslists = responseW.courseWork
if (workslists && workslists.length > 0) {
workslists.map(topic => {
WorksList.push(topic)
})
} else {
Logger.log('No works found');
}
pageToken = responseW.nextPageToken;
} while (pageToken != null);
return WorksList
}
Om studenten cijfers te bekomen, moet je een aantal gegevens uit andere lijsten samen brengen.
Zo moet je weten in welke cursus, welke topic en coursework en over welke cursist het gaat.
De samengebouwde functie maakt gebruik van voorgaande helperfuncties om deze gegevens te bekomen.
Door het maken van lookup tabellen voor de coursework en student id's kan je de gegevens van een student samen brengen met de juiste informatie in de grade list.
/**
* Helperfunctie getStudentSubmissions_
* @param {object} object, result of classroom search
* @param {string} courseId
* @return
*/
function getStudentSubmissions_(obj, courseId) {
// Coursework[].materials[].form.title/formUrl/tumbnailUrl/responseUrl
// Coursework[].materials[].link.url/title
// Coursework[].materials[].drivefile.drivefile.title/id/alternateLink/tumbnailUrl
// Coursework[].worktype=ASSIGNMENT/maxPoints=points/title/assigneeMode=ALL_STUDENTS
// Coursework[].Studentlist[].Fullname/Email/Photo/UserId
// create lookup table from object CourseWorks ids
let CourseWorksLookup = {}
if (!CourseWorksLookup.id) { CourseWorksLookup.id = [] }
if (!CourseWorksLookup.title) { CourseWorksLookup.title = [] }
if (!CourseWorksLookup.alternateLink) { CourseWorksLookup.alternateLink = [] }
for (cwl = 0; cwl < obj.CourseWork.length; cwl++) {
CourseWorksLookup.id[cwl] = obj.CourseWork[cwl].id
CourseWorksLookup.title[cwl] = obj.CourseWork[cwl].title
CourseWorksLookup.alternateLink[cwl] = obj.CourseWork[cwl].alternateLink
}
//create lookup table from object students ids
let StudentLookup = []
for (stl = 0; stl < obj.StudentList.length; stl++) {
StudentLookup[stl] = obj.StudentList[stl].UserId
}
let pageTokenSS = ''
let responseSS = ''
let Submissions=[]
do {
let optionalArgsSS = {
pageSize: 20,
pageToken: pageTokenSS,
}
responseSS = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, "-", optionalArgsSS)
let arr = responseSS.getStudentSubmissions()
if (typeof arr != "undefined") {
arr.map(array => Submissions.push(array) )
}
pageTokenSS = responseSS.nextPageToken
} while (pageTokenSS != null);
//let Submissions = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, "-").studentSubmissions
if (typeof Submissions != "undefined") {
let studentsgradelist = []
let sm = 0
for (sg = 0; sg < Submissions.length; sg++) {
// let sgl=sg
let studentgrade = {}
studentgrade.CourseName = obj.CourseName
studentgrade.CourseID = obj.CourseID
studentgrade.studentId = Submissions[sg].userId
//student index lookup
let stidx = StudentLookup.indexOf(studentgrade.studentId)
if (stidx != -1) {
studentgrade.studentFullName = obj.StudentList[stidx].FullName
studentgrade.studentEmail = obj.StudentList[stidx].Email
studentgrade.studentPhoto = obj.StudentList[stidx].Photo
}
studentgrade.assignedGrade = Submissions[sg].assignedGrade
studentgrade.courseworkId = Submissions[sg].courseWorkId
// idx in lookup = idx in objec array CoursWork
let idx = CourseWorksLookup.id.indexOf(studentgrade.courseworkId)
studentgrade.courseworkTitle = obj.CourseWork[idx].title
studentgrade.maxPoints = obj.CourseWork[idx].maxPoints
if (typeof studentgrade.assignedGrade != "undefined") {
studentgrade.grade = parseInt((studentgrade.assignedGrade / studentgrade.maxPoints) * 100)
}
//check empty descrption
if (obj.CourseWork[idx].description != "undefined") {
studentgrade.courseworkDescription = obj.CourseWork[idx].description
}
if (obj.CourseWork[idx].alternateLink != "undefined") {
studentgrade.alternateLink = obj.CourseWork[idx].alternateLink
}
//check empty materials
if (typeof obj.CourseWork[idx].materials != "undefined") {
// loop through materails to find form(s), links(s)
for (m = 0; m < obj.CourseWork[idx].materials.length; m++) {
//form found
if (typeof obj.CourseWork[idx].materials[m].form != "undefined") {
if (!studentgrade.forms) { studentgrade.forms = [] }
let form = {}
form.formUrl = obj.CourseWork[idx].materials[m].form.formUrl
form.formTitle = obj.CourseWork[idx].materials[m].form.title
form.formtumbnailUrl = obj.CourseWork[idx].materials[m].form.tumbnailUrl
form.formresponseUrl = obj.CourseWork[idx].materials[m].form.responseUrl
studentgrade.forms.push(form)
}
if (typeof obj.CourseWork[idx].materials[m].link != "undefined") {
if (!studentgrade.links) { studentgrade.links = [] }
let links = {}
links.linkUrl = obj.CourseWork[idx].materials[m].link.url
links.linkskTitle = obj.CourseWork[idx].materials[m].link.title
studentgrade.links.push(links)
}
}
}
// Only make record if a grade assignment is made and student exist in this class
if (typeof studentgrade.assignedGrade != "undefined" && stidx != -1) {
studentsgradelist[sm] = studentgrade
sm++
}
}
if (sm != 0) {
obj.Studentgrates = studentsgradelist
}
return true
} else {
return false
}
}
Deze functie schrijft de gevonden gegevens in de FireStore Db in een formaat dat we nadien kunnen gebruiken om de rapporten te genereren.
Het document draagt de naam bestaande uit het email adres van de student en de submission topic nummer.
Door deze combinate en de "update" functie van het document wordt er per submission maar één score bewaard en is deze ook als uniek item terug te vinden.
Er zullen dus heel wat documenten onder de classroom collection terug te vinden zijn van een cursist, allemaal met zijn score per topic.
In dit document worden heel wat gegevens verzameld waaronder de coursename en id, de coursworkname en id en de coursworkTitel.
Dit laatste is belangrijk om hergebruik van scores in andere classrooms toe te laten in de rapportering.
Indien een cursist in een andere classroom, hetzelfde courswork (titel, want id zal verschillen) heeft ingedient, dan kan deze score in het rapport gerecupereerd worden en wordt de maximale score uit deze lijst gebruikt.
Het is dus belangrijk om de evaluatie opdrachten "identiek" te benoemen in de verschillende classrooms, als het over dezelfde evaluatie gaat in verschillende centra.
/**
* WriteCoursesGrades
* Writes all grades of students where you are a teacher to the FS collection "Classroomscores"
*
* @return {array} courselist array of objects
*
* document name: studentEmail+CourseworkId
* Object fields:
* CourseID, CourseName, assignedGrade, courseworkDescription, courseworkId,courseworkTitle,studentEmai, studentFullname, studentId, studentPhoto
* links[]
* -linkUrl
* -linksktitle
* forms[]
* -formTitle
* -formUrl
* -formresponseUrl
* -formtumbnailUrl
*
*/
function WriteCoursesGrades() {
try {
// Script run interactive-> Alerts will work, otherwise not
var DisplayAlerts = true;
try {
var ui = SpreadsheetApp.getUi()
}
catch (err) {
DisplayAlerts = false;
}
//Lock access to vars/sheet from triggers
LockService.getScriptLock().waitLock(300000) //max 6min
// get Firestore db
var firestore = getFireStore()
var classroomdata = {}
let pageToken = ''
let pageTokenS = ''
let courseList = []
let responseC = ''
do {
let optionalArgs = {
pageSize: 20,
pageToken: pageToken,
}
responseC = Classroom.Courses.list(optionalArgs);
let courses = responseC.courses;
if (courses && courses.length > 0) {
let courserec = courses.map(course => {
let obj = {}
obj.CourseName = course.name
Logger.log(obj.CourseName)
obj.CourseID = course.id
if (course.hasOwnProperty("teacherFolder")) {
obj.CourseTeacherFolder = course.teacherFolder.id
obj.IsTeacher = true
// studentlist with ID
obj.StudentList = []
// Loop studentsList
do {
let optionalArgsS = {
pageSize: 20,
pageToken: pageTokenS,
}
let responseS = Classroom.Courses.Students.list(course.id, optionalArgsS)
let students = responseS.students
if (students && students.length > 0) {
for (let sc = 0; sc < students.length; sc++) {
let objS = {}
if (students[sc].profile.name.fullName != "Unknown user") {
objS.FullName = students[sc].profile.name.fullName
objS.Email = students[sc].profile.emailAddress
objS.Photo = students[sc].profile.photoUrl
objS.UserId = students[sc].profile.id
}
obj.StudentList = obj.StudentList.concat(objS)
}
}
pageTokenS = responseS.nextPageToken
} while (pageTokenS != null);
obj.CourseTopics = getTopics_(obj, course.id)
//obj.CourseTopics = Classroom.Courses.Topics.list(course.id)
obj.CourseWork = getWorks_(obj, course.id)
//obj.WorkID = Classroom.Courses.CourseWork.StudentSubmissions.list(course.id,"433268543654").studentSubmissions
let submissions = getStudentSubmissions_(obj, course.id)
} else {
obj.IsTeacher = false
}
return obj
})
courseList = courseList.concat(courserec)
} else {
Logger.log('No courses found.');
}
pageToken = responseC.nextPageToken;
} while (pageToken != null);
// Loop courselist for studentgrades write to FS
for (gr = 0; gr < courseList.length; gr++) {
if (courseList[gr].hasOwnProperty("Studentgrates")) {
for (sg = 0; sg < courseList[gr].Studentgrates.length; sg++) {
let document = courseList[gr].Studentgrates[sg]
let name = `${courseList[gr].Studentgrates[sg].studentEmail}_${courseList[gr].Studentgrates[sg].courseworkId}`
let collectionpath = 'Classroomscore'
let updatedoc = firestore.updateDocument(`${collectionpath}/${name}`, document, mask = false);
}
}
}
SpreadsheetApp.flush();
LockService.getScriptLock().releaseLock()
return courseList
} catch (e) {
LockService.getScriptLock().releaseLock()
if (DisplayAlerts) { ui.alert(e); }
Logger.log(e)
}
}
Wanneer zowel de scores vanuit de classrooms als deze vanuit de quizzes in de Firestore db zijn opgeslagen kan je op eenvoudige wijze alle uitslagen van een cursist samen brengen.
De fuctie voert queries uit in twee collections, zijnde deze van de classroom alsook deze van de quizzes en dit op de aangeboden email adres van de cursist.
De uitkomst is een lijst waarbij de items voorzien zijn van hyperlinken en daardoor vanuit de sheet direct benaderbaar zijn.
/**
* Helper function
* GetStudentGrades_(studentEmail)
* @param {string} studentEmail, Email address for queries
* @return {array} arr, 2D array with results.
*/
function getStudentGrades_(studentEmail) {
var firestore = getFireStore()
let arr = [[]]
arr.shift(); //haal eerste leeg array row weg owv het expliciet definieren van een 2d array.
let scoreclassrooms = firestore.query("Classroomscore").Where("studentEmail", "==", studentEmail).Execute();
var studentFullName = ``
if (typeof scoreclassrooms != "undefined" && scoreclassrooms.length != 0) {
for (d = 0; d < scoreclassrooms.length; d++) {
studentFullName = scoreclassrooms[d].fields.studentFullName.stringValue
let studentEmail = scoreclassrooms[d].fields.studentEmail.stringValue
let CourseName = scoreclassrooms[d].fields.CourseName.stringValue
//hyperlink from worktitle
let courseworkTitle = `=HYPERLINK("${scoreclassrooms[d].fields.alternateLink.stringValue}";"${scoreclassrooms[d].fields.courseworkTitle.stringValue}")`
//let courseworkTitle = scoreclassrooms[d].fields.courseworkTitle.stringValue
//let assignedGrade = scoreclassrooms[d].fields.assignedGrade.integerValue
let assignedGrade = scoreclassrooms[d].fields.grade.integerValue
let rec = [studentFullName, studentEmail, CourseName, courseworkTitle, assignedGrade]
arr.push(rec)
}
//Sheet.getRange(1, 1, arr.length, arr[0].length).setValues(arr);
}
let quizscores = firestore.query("HAREC").Where("Email address", "==", studentEmail).Execute();
if (typeof quizscores != "undefined" && quizscores.length != 0) {
for (d = 0; d < quizscores.length; d++) {
let studentEmail = quizscores[d].fields["Email address"].stringValue
let quizname = `=HYPERLINK("${quizscores[d].fields.formURL.stringValue}";"${quizscores[d].fields.quizname.stringValue}")`
//hyperlink from worktitle
let quizresponse = `=HYPERLINK("${quizscores[d].fields.responsesURL.stringValue}";"Response:${quizscores[d].fields.quizname.stringValue}")`
//let courseworkTitle = scoreclassrooms[d].fields.courseworkTitle.stringValue
let Score = quizscores[d].fields.Score.integerValue
let rec = [studentFullName, studentEmail, quizname, quizresponse, Score]
arr.push(rec)
}
//Sheet.getRange(1, 1, arr.length, arr[0].length).setValues(arr);
}
return arr
}
Deze wrapper functie zorgt ervoor dat voorgaande actie ook wordt toegepast op alle aliasses van de betreffende cursist en dat de output in een sheet wordt getoond.
We vinden dus in de sheet zowel de scorens van de coursework topics alsook de quizzes terug en kunnen via de hyperlinks direct naar de betreffende items in de classrooms of naar de antwoorden in de formulieren navigeren.
Vermits zo ook scores van classrooms en quizzes, waartoe jij geen toegang had, kunnen getoond worden, kan je alles wat van een betreffende cursis is gegenereerd in andere classrooms en opleidingen eveneens zien en recupereren.
Hierdoor wordt een volledig competentieprofiel mogelijk en wordt "reeds behaalde competenties" gerecupereerd.
/**
* FSQueryStudentScores
* Query for student scores in classrooms and quizzes
* @param {string} studentEmail, primary email address student
* @param {string} sheetname
* @return {array} arr, 2d array of scores,
*/
function FSQueryStudentScores(studentEmail, sheetname) {
try {
// Script run interactive-> Alerts will work, otherwise not
var DisplayAlerts = true;
try {
var ui = SpreadsheetApp.getUi()
}
catch (err) {
DisplayAlerts = false;
}
//Lock access to vars/sheet from triggers
LockService.getScriptLock().waitLock(300000) //max 6min
// get Firestore db
var firestore = getFireStore()
let Sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var arr = [[]]
arr.shift(); //haal eerste leeg array row weg owv het expliciet definieren van een 2d array.
let header = ['studentFullName', 'studentEmail', 'CourseName/QuizName', 'courseworkTitle/Quizresponse', 'Grade/score']
arr.push(header)
// get aliasses
let aliasses = firestore.query("Aliasses").Where("docname", "==", studentEmail).Execute();
let aliasname = ''
if (aliasses.length != 0) {
//alias loop
for (a = 0; a < aliasses[0].fields.aliasses.arrayValue.values.length; a++) {
aliasname = aliasses[0].fields.aliasses.arrayValue.values[a].stringValue
let score = getStudentGrades_(aliasname)
for (s = 0; s < score.length; s++) {
arr.push(score[s])
}
}
}
let score = getStudentGrades_(studentEmail)
for (s = 0; s < score.length; s++) {
arr.push(score[s])
}
Sheet.clear()
SpreadsheetApp.flush();
Sheet.getRange(1, 1, arr.length, arr[0].length).setValues(arr);
SpreadsheetApp.flush();
// If records found, sort result
if (arr.length > 1) {
let firstRow = 2
var fullRange = Sheet.getRange(firstRow, 1, Sheet.getLastRow() - firstRow + 1, Sheet.getLastColumn());
fullRange.sort(4); // Sort full range according to courseworkname
SpreadsheetApp.flush(); // Refresh spreadsheet
}
Logger.log('einde')
return arr
} catch (e) {
LockService.getScriptLock().releaseLock()
if (DisplayAlerts) { ui.alert(e); }
Logger.log(e)
}
}