Questa è la sesta procedura dettagliata della serie di procedure dettagliate dei componenti aggiuntivi di Classroom.
In questa procedura dettagliata, modifichi l'esempio del passaggio precedente per produrre un allegato di tipo attività con valutazione. Puoi anche restituire un voto a Google Classroom in modo programmatico, che viene visualizzato nel registro dell'insegnante come bozza.
Questa procedura dettagliata si differenzia leggermente dalle altre della serie in quanto presenta due possibili approcci per restituire i voti a Classroom. Entrambi hanno un impatto distinto sull'esperienza di sviluppatori e utenti. Considerali entrambi durante la progettazione del tuo componente aggiuntivo Classroom. Per ulteriori informazioni sulle opzioni di implementazione, consulta la nostra pagina della guida Interagire con gli allegati.
Tieni presente che le funzionalità di valutazione nell'API sono facoltative. Possono essere utilizzati con qualsiasi allegato di tipo attività.
Nel corso di questa procedura dettagliata, completerai le seguenti operazioni:
- Modifica le richieste di creazione degli allegati precedenti all'API Classroom per impostare anche il denominatore del voto dell'allegato.
- Valuta in modo programmatico il compito inviato dallo studente e imposta il numeratore del voto dell'allegato.
- Implementa due approcci per trasferire il voto dell'invio a Classroom utilizzando le credenziali dell'insegnante con accesso o offline.
Al termine, i voti vengono visualizzati nel registro di Classroom dopo l'attivazione del comportamento di restituzione. Il momento esatto in cui ciò si verifica dipende dall'approccio di implementazione.
Ai fini di questo esempio, riutilizza l'attività della procedura dettagliata precedente, in cui a uno studente viene mostrata l'immagine di un famoso monumento e gli viene chiesto di inserire il suo nome. Assegna il punteggio massimo all'allegato se lo studente inserisce il nome corretto, zero in caso contrario.
Informazioni sulla funzionalità di valutazione dell'API dei componenti aggiuntivi di Classroom
Il componente aggiuntivo può impostare sia il numeratore che il denominatore del voto per un
allegato. Questi valori vengono impostati rispettivamente utilizzando i valori pointsEarned
e maxPoints
nell'API. Una scheda allegato nella UI di Classroom mostra
il valore di maxPoints
quando è stato impostato.
Figura 1. L'interfaccia utente per la creazione di compiti con tre schede di allegati di componenti aggiuntivi che
hanno impostato maxPoints
.
L'API componenti aggiuntivi di Classroom consente di configurare le impostazioni e impostare
il punteggio ottenuto per i voti degli allegati. Questi non sono gli stessi dei voti
dell'assegnazione. Tuttavia, le impostazioni del voto dell'attività seguono le impostazioni del voto dell'allegato che ha l'etichetta Sincronizzazione dei voti sulla scheda dell'allegato. Quando l'allegato "Sincronizzazione dei voti" imposta pointsEarned
per
l'invio di uno studente, imposta anche il voto in bozza dello studente per il compito.
In genere, il primo allegato aggiunto al compito che imposta
maxPoints
riceve l'etichetta "Sincronizzazione dei voti". Per un esempio dell'etichetta "Sincronizzazione voti", consulta l'esempio dell'interfaccia utente di creazione di un compito mostrato nella Figura 1. Tieni presente che
la scheda "Allegato 1" ha l'etichetta "Sincronizzazione del voto" e che il voto del compito
nella casella rossa è stato aggiornato a 50 punti. Tieni presente inoltre che, sebbene la Figura 1
mostri tre schede degli allegati, solo una scheda ha l'etichetta "Sincronizzazione voti". Si tratta di
una limitazione fondamentale dell'implementazione attuale: solo un allegato può avere
l'etichetta "Sincronizzazione dei voti".
Se sono presenti più allegati con maxPoints
impostato, la rimozione dell'allegato con"Sincronizzazione dei voti" non attiva "Sincronizzazione dei voti" su nessuno degli allegati rimanenti. L'aggiunta di un altro allegato che imposta maxPoints
attiva
la sincronizzazione dei voti nel nuovo allegato e il voto massimo dell'assegnazione viene modificato
di conseguenza. Non esiste un meccanismo per visualizzare in modo programmatico quale allegato ha l'etichetta
"Sincronizzazione dei voti" né per vedere quanti allegati ha un determinato compito.
Impostare il voto massimo di un allegato
Questa sezione descrive l'impostazione del denominatore per il voto di un allegato, ovvero il punteggio massimo possibile che tutti gli studenti possono ottenere per i loro invii. Per farlo, imposta il valore maxPoints
dell'allegato.
Per attivare le funzionalità di classificazione è necessaria solo una piccola modifica all'implementazione esistente. Quando crei un allegato, aggiungi il valore maxPoints
nello stesso oggetto AddOnAttachment
che contiene studentWorkReviewUri
, teacherViewUri
e altri campi dell'allegato.
Tieni presente che il punteggio massimo predefinito per un nuovo compito è 100. Ti consigliamo di impostare maxPoints
su un valore diverso da 100 per verificare che i voti vengano impostati correttamente. Imposta maxPoints
su 50 come dimostrazione:
Python
Aggiungi il campo maxPoints
durante la costruzione dell'oggetto attachment
, appena
prima di inviare una richiesta CREATE
all'endpoint courses.courseWork.addOnAttachments
. Puoi trovarlo nel file
webapp/attachment_routes.py
se segui l'esempio fornito.
attachment = {
# Specifies the route for a teacher user.
"teacherViewUri": {
"uri":
flask.url_for(
"load_activity_attachment",
_scheme='https',
_external=True),
},
# Specifies the route for a student user.
"studentViewUri": {
"uri":
flask.url_for(
"load_activity_attachment",
_scheme='https',
_external=True)
},
# Specifies the route for a teacher user when the attachment is
# loaded in the Classroom grading view.
"studentWorkReviewUri": {
"uri":
flask.url_for(
"view_submission", _scheme='https', _external=True)
},
# Sets the maximum points that a student can earn for this activity.
# This is the denominator in a fractional representation of a grade.
"maxPoints": 50,
# The title of the attachment.
"title": f"Attachment {attachment_count}",
}
Ai fini di questa dimostrazione, memorizzi anche il valore maxPoints
nel database degli allegati locale. In questo modo, non dovrai effettuare un'ulteriore chiamata API in un secondo momento, quando valuterai i lavori inviati dagli studenti. Tieni presente, tuttavia, che è possibile che
gli insegnanti modifichino le impostazioni di valutazione dei compiti indipendentemente dal componente aggiuntivo. Invia
una richiesta GET
all'endpoint courses.courseWork
per visualizzare il valore
maxPoints
a livello di assegnazione. In questo caso, trasmetti itemId
nel campo
CourseWork.id
.
Ora aggiorna il modello di database in modo che contenga anche il valore maxPoints
dell'allegato.
Ti consigliamo di utilizzare il valore maxPoints
della risposta CREATE
:
Python
Innanzitutto, aggiungi un campo max_points
alla tabella Attachment
. Puoi trovare questo
nel file webapp/models.py
se segui il nostro esempio.
# Database model to represent an attachment.
class Attachment(db.Model):
# The attachmentId is the unique identifier for the attachment.
attachment_id = db.Column(db.String(120), primary_key=True)
# The image filename to store.
image_filename = db.Column(db.String(120))
# The image caption to store.
image_caption = db.Column(db.String(120))
# The maximum number of points for this activity.
max_points = db.Column(db.Integer)
Torna alla richiesta courses.courseWork.addOnAttachments
CREATE
. Memorizza
il valore maxPoints
restituito nella risposta.
new_attachment = Attachment(
# The new attachment's unique ID, returned in the CREATE response.
attachment_id=resp.get("id"),
image_filename=key,
image_caption=value,
# Store the maxPoints value returned in the response.
max_points=int(resp.get("maxPoints")))
db.session.add(new_attachment)
db.session.commit()
L'allegato ora ha un grado massimo. Ora dovresti essere in grado di testare questo comportamento: aggiungi un allegato a un nuovo compito e osserva che la scheda dell'allegato mostra l'etichetta "Sincronizzazione voti" e il valore "Punti" del compito cambia.
Impostare un voto per i contenuti inviati da uno studente in Classroom
Questa sezione descrive l'impostazione del numeratore per il voto di un allegato, ovvero
il punteggio di un singolo studente per l'allegato. Per farlo, imposta il valore pointsEarned
dell'invio di un allegato dello studente.
Ora devi prendere una decisione importante: in che modo il componente aggiuntivo deve inviare una
richiesta per impostare pointsEarned
?
Il problema è che l'impostazione pointsEarned
richiede l'ambito OAuth teacher
.
Non devi concedere l'ambito teacher
agli utenti studenti, in quanto ciò potrebbe comportare
un comportamento imprevisto quando gli studenti interagiscono con il tuo componente aggiuntivo, ad esempio il caricamento dell'iframe
Visualizzazione insegnante anziché dell'iframe Visualizzazione studente. Pertanto, hai due
opzioni per impostare pointsEarned
:
- Utilizzando le credenziali dell'insegnante che ha eseguito l'accesso.
- Utilizzo delle credenziali dell'insegnante memorizzate (offline).
Le sezioni seguenti illustrano i compromessi di ciascun approccio prima di mostrare ogni implementazione. Tieni presente che gli esempi forniti mostrano entrambi gli approcci per trasferire un voto a Classroom. Consulta le istruzioni specifiche per la lingua riportate di seguito per scoprire come selezionare un approccio quando esegui gli esempi forniti:
Python
Trova la dichiarazione SET_GRADE_WITH_LOGGED_IN_USER_CREDENTIALS
nella parte superiore
del file webapp/attachment_routes.py
. Imposta questo valore su True
per restituire
i voti utilizzando le credenziali dell'insegnante che ha eseguito l'accesso. Imposta questo valore su False
per restituire i voti utilizzando le credenziali archiviate quando lo studente invia
l'attività.
Impostare i voti utilizzando le credenziali dell'insegnante che ha eseguito l'accesso
Utilizza le credenziali dell'utente che ha eseguito l'accesso per inviare la richiesta di impostazione di pointsEarned
.
Dovrebbe sembrarti abbastanza intuitivo, in quanto rispecchia il resto dell'implementazione
finora e richiede poco sforzo per essere realizzato.
Tuttavia, tieni presente che l'insegnante interagisce solo con l'invio dello studente nell'iframe Revisione del lavoro dello studente. Ciò ha alcune importanti implicazioni:
- In Classroom non vengono inseriti voti finché l'insegnante non interviene nell'interfaccia utente di Classroom.
- Un insegnante potrebbe dover aprire ogni compito inviato dagli studenti per inserire tutti i voti.
- Si verifica un breve ritardo tra la ricezione del voto da parte di Classroom e la sua visualizzazione nella UI di Classroom. Il ritardo è in genere di 5-10 secondi, ma può arrivare fino a 30 secondi.
La combinazione di questi fattori significa che gli insegnanti potrebbero dover svolgere un lavoro manuale considerevole e dispendioso in termini di tempo per compilare completamente i voti di una classe.
Per implementare questo approccio, aggiungi una chiamata API aggiuntiva alla route di revisione dei lavori degli studenti esistente.
Dopo aver recuperato i record dei contenuti inviati e degli allegati dello studente, valuta i contenuti inviati dallo studente e memorizza il voto risultante. Imposta il voto nel campo
pointsEarned
di un oggetto AddOnAttachmentStudentSubmission
. Infine,
invia una richiesta PATCH
all'endpoint
courses.courseWork.addOnAttachments.studentSubmissions
con l'istanza
AddOnAttachmentStudentSubmission
nel corpo della richiesta. Tieni presente che dobbiamo
specificare anche pointsEarned
in updateMask
nella nostra richiesta PATCH
:
Python
# Look up the student's submission in our database.
student_submission = Submission.query.get(flask.session["submissionId"])
# Look up the attachment in the database.
attachment = Attachment.query.get(student_submission.attachment_id)
grade = 0
# See if the student response matches the stored name.
if student_submission.student_response.lower(
) == attachment.image_caption.lower():
grade = attachment.max_points
# Create an instance of the Classroom service.
classroom_service = ch._credential_handler.get_classroom_service()
# Build an AddOnAttachmentStudentSubmission instance.
add_on_attachment_student_submission = {
# Specifies the student's score for this attachment.
"pointsEarned": grade,
}
# Issue a PATCH request to set the grade numerator for this attachment.
patch_grade_response = classroom_service.courses().courseWork(
).addOnAttachments().studentSubmissions().patch(
courseId=flask.session["courseId"],
itemId=flask.session["itemId"],
attachmentId=flask.session["attachmentId"],
submissionId=flask.session["submissionId"],
# updateMask is a list of fields being modified.
updateMask="pointsEarned",
body=add_on_attachment_student_submission).execute()
Impostare i voti utilizzando le credenziali offline dell'insegnante
Il secondo approccio all'impostazione dei voti richiede l'utilizzo delle credenziali archiviate
per l'insegnante che ha creato l'allegato. Questa implementazione richiede di
creare le credenziali utilizzando i token di accesso e di aggiornamento di un insegnante autorizzato in precedenza e
utilizzare queste credenziali per impostare pointsEarned
.
Un vantaggio fondamentale di questo approccio è che i voti vengono compilati senza richiedere l'intervento dell'insegnante nell'interfaccia utente di Classroom, evitando i problemi menzionati sopra. Il risultato è che gli utenti finali percepiscono l'esperienza di classificazione come fluida ed efficiente. Inoltre, questo approccio ti consente di scegliere il momento in cui restituire i voti, ad esempio quando gli studenti completano l'attività o in modo asincrono.
Completa le seguenti attività per implementare questo approccio:
- Modifica i record del database utenti per archiviare un token di accesso.
- Modifica i record del database degli allegati per memorizzare un ID insegnante.
- Recupera le credenziali dell'insegnante e (facoltativamente) crea una nuova istanza del servizio Classroom.
- Imposta il voto di un invio.
Ai fini di questa dimostrazione, imposta il voto quando lo studente completa l'attività, ovvero quando invia il modulo nel percorso della visualizzazione studente.
Modificare i record del database utenti per memorizzare il token di accesso
Per effettuare chiamate API sono necessari due token univoci: il token di aggiornamento e il
token di accesso. Se hai seguito finora la serie di procedure dettagliate, lo
schema della tabella User
dovrebbe già memorizzare un token di aggiornamento. L'archiviazione del token di aggiornamento è sufficiente quando effettui chiamate API solo con l'utente che ha eseguito l'accesso, in quanto ricevi un token di accesso nell'ambito del flusso di autenticazione.
Tuttavia, ora devi effettuare chiamate come persona diversa dall'utente che ha eseguito l'accesso,
il che significa che il flusso di autenticazione non è disponibile. Pertanto, devi archiviare il
token di accesso insieme al token di aggiornamento. Aggiorna lo schema della tabella User
per
includere un token di accesso:
Python
Nell'esempio fornito, questo si trova nel file webapp/models.py
.
# Database model to represent a user.
class User(db.Model):
# The user's identifying information:
id = db.Column(db.String(120), primary_key=True)
display_name = db.Column(db.String(80))
email = db.Column(db.String(120), unique=True)
portrait_url = db.Column(db.Text())
# The user's refresh token, which will be used to obtain an access token.
# Note that refresh tokens will become invalid if:
# - The refresh token has not been used for six months.
# - The user revokes your app's access permissions.
# - The user changes passwords.
# - The user belongs to a Google Cloud organization
# that has session control policies in effect.
refresh_token = db.Column(db.Text())
# An access token for this user.
access_token = db.Column(db.Text())
Quindi, aggiorna qualsiasi codice che crea o aggiorna un record User
per archiviare anche il token di accesso:
Python
Nell'esempio fornito, questo si trova nel file webapp/credential_handler.py
.
def save_credentials_to_storage(self, credentials):
# Issue a request for the user's profile details.
user_info_service = googleapiclient.discovery.build(
serviceName="oauth2", version="v2", credentials=credentials)
user_info = user_info_service.userinfo().get().execute()
flask.session["username"] = user_info.get("name")
flask.session["login_hint"] = user_info.get("id")
# See if we have any stored credentials for this user. If they have used
# the add-on before, we should have received login_hint in the query
# parameters.
existing_user = self.get_credentials_from_storage(user_info.get("id"))
# If we do have stored credentials, update the database.
if existing_user:
if user_info:
existing_user.id = user_info.get("id")
existing_user.display_name = user_info.get("name")
existing_user.email = user_info.get("email")
existing_user.portrait_url = user_info.get("picture")
if credentials and credentials.refresh_token is not None:
existing_user.refresh_token = credentials.refresh_token
# Update the access token.
existing_user.access_token = credentials.token
# If not, this must be a new user, so add a new entry to the database.
else:
new_user = User(
id=user_info.get("id"),
display_name=user_info.get("name"),
email=user_info.get("email"),
portrait_url=user_info.get("picture"),
refresh_token=credentials.refresh_token,
# Store the access token as well.
access_token=credentials.token)
db.session.add(new_user)
db.session.commit()
Modificare i record del database degli allegati per memorizzare un ID insegnante
Per impostare un voto per un'attività, chiama per impostare pointsEarned
come
insegnante del corso. Esistono diversi modi per farlo:
- Memorizza una mappatura locale delle credenziali dell'insegnante agli ID corso. Tuttavia, tieni presente che lo stesso insegnante potrebbe non essere sempre associato a un determinato corso.
- Invia
GET
richieste all'endpointcourses
dell'API Classroom per ottenere l'insegnante o gli insegnanti attuali. Quindi, esegui una query sui record utente locali per individuare le credenziali dell'insegnante corrispondenti. - Quando crei un allegato del componente aggiuntivo, memorizza un ID insegnante nel database degli allegati locale. Quindi, recupera le credenziali dell'insegnante dal
attachmentId
passato all'iframe della visualizzazione studente.
Questo esempio mostra l'ultima opzione, poiché stai impostando i voti quando lo studente completa un allegato di attività.
Aggiungi un campo ID insegnante alla tabella Attachment
del tuo database:
Python
Nell'esempio fornito, questo si trova nel file webapp/models.py
.
# Database model to represent an attachment.
class Attachment(db.Model):
# The attachmentId is the unique identifier for the attachment.
attachment_id = db.Column(db.String(120), primary_key=True)
# The image filename to store.
image_filename = db.Column(db.String(120))
# The image caption to store.
image_caption = db.Column(db.String(120))
# The maximum number of points for this activity.
max_points = db.Column(db.Integer)
# The ID of the teacher that created the attachment.
teacher_id = db.Column(db.String(120))
Poi, aggiorna il codice che crea o aggiorna un record Attachment
in modo da memorizzare anche l'ID del creatore:
Python
Nell'esempio fornito, questo si trova nel metodo create_attachments
nel file
webapp/attachment_routes.py
.
# Store the attachment by id.
new_attachment = Attachment(
# The new attachment's unique ID, returned in the CREATE response.
attachment_id=resp.get("id"),
image_filename=key,
image_caption=value,
max_points=int(resp.get("maxPoints")),
teacher_id=flask.session["login_hint"])
db.session.add(new_attachment)
db.session.commit()
Recuperare le credenziali dell'insegnante
Trova la route che gestisce l'iframe della visualizzazione studente. Subito dopo aver memorizzato la risposta dello studente nel database locale, recupera le credenziali dell'insegnante dallo spazio di archiviazione locale. Questa operazione dovrebbe essere semplice, data la preparazione nei due passaggi precedenti. Puoi anche utilizzarli per creare una nuova istanza del servizio Classroom per l'utente insegnante:
Python
Nell'esempio fornito, questo si trova nel metodo load_activity_attachment
nel file webapp/attachment_routes.py
.
# Create an instance of the Classroom service using the tokens for the
# teacher that created the attachment.
# We're assuming that there are already credentials in the session, which
# should be true given that we are adding this within the Student View
# route; we must have had valid credentials for the student to reach this
# point. The student credentials will be valid to construct a Classroom
# service for another user except for the tokens.
if not flask.session.get("credentials"):
raise ValueError(
"No credentials found in session for the requested user.")
# Make a copy of the student credentials so we don't modify the original.
teacher_credentials_dict = deepcopy(flask.session.get("credentials"))
# Retrieve the requested user's stored record.
teacher_record = User.query.get(attachment.teacher_id)
# Apply the user's tokens to the copied credentials.
teacher_credentials_dict["refresh_token"] = teacher_record.refresh_token
teacher_credentials_dict["token"] = teacher_record.access_token
# Construct a temporary credentials object.
teacher_credentials = google.oauth2.credentials.Credentials(
**teacher_credentials_dict)
# Refresh the credentials if necessary; we don't know when this teacher last
# made a call.
if teacher_credentials.expired:
teacher_credentials.refresh(Request())
# Request the Classroom service for the specified user.
teacher_classroom_service = googleapiclient.discovery.build(
serviceName=CLASSROOM_API_SERVICE_NAME,
version=CLASSROOM_API_VERSION,
credentials=teacher_credentials)
Impostare il voto di un invio
La procedura da questo punto in poi è identica a quella di utilizzo delle credenziali dell'insegnante che ha eseguito l'accesso. Tuttavia, tieni presente che devi effettuare la chiamata con le credenziali dell'insegnante recuperate nel passaggio precedente:
Python
# Issue a PATCH request as the teacher to set the grade numerator for this
# attachment.
patch_grade_response = teacher_classroom_service.courses().courseWork(
).addOnAttachments().studentSubmissions().patch(
courseId=flask.session["courseId"],
itemId=flask.session["itemId"],
attachmentId=flask.session["attachmentId"],
submissionId=flask.session["submissionId"],
# updateMask is a list of fields being modified.
updateMask="pointsEarned",
body=add_on_attachment_student_submission).execute()
Testare il componente aggiuntivo
Come nella procedura dettagliata precedente, crea un compito con un allegato di tipo attività in qualità di insegnante, invia una risposta in qualità di studente, quindi apri l'invio nell'iframe di revisione del lavoro dello studente. Dovresti essere in grado di visualizzare il voto in momenti diversi a seconda dell'approccio di implementazione:
- Se hai scelto di restituire un voto quando lo studente ha completato l'attività, dovresti già visualizzare la bozza del voto nell'interfaccia utente prima di aprire l'iframe Revisione del lavoro dello studente. Puoi visualizzarlo anche nell'elenco degli studenti quando apri il compito e nella casella "Voto" accanto all'iframe di revisione del lavoro dello studente.
- Se hai scelto di restituire un voto quando l'insegnante apre l'iframe Revisione lavori dello studente, il voto dovrebbe essere visualizzato nella casella "Voto" subito dopo il caricamento dell'iframe. Come accennato in precedenza, l'operazione può richiedere fino a 30 secondi. Dopodiché, il voto per lo studente specifico dovrebbe essere visualizzato anche nelle altre visualizzazioni del registro di Classroom.
Verifica che per lo studente venga visualizzato il punteggio corretto.
Complimenti! Ora puoi procedere al passaggio successivo: creare allegati al di fuori di Google Classroom.