Connect to google classroom from external website/app? - google-classroom

I need to somehow connect to google classroom from a students perspective, and list all assignments coming up soon. I can't find anything about this in the documentation, but using the google authentication I should be able to do it?

You can use the method courses.courseWork.list this will return a list of course work that the user is permitted to view.
For the scope, as the document says:
API requests also require the correct user scopes. Teachers can view assignments, create assignments, attach links to assignment submissions, and set submission grades. Students can view assignments, attach links to their assignment records, and turn-in and reclaim their submissions. Domain administrators can view coursework, but have no write permissions.
Here's a sample code using appscript, you can just play around with it to familiarize yourself.
function listCourses() {
var optionalArgs = {
pageSize: 10
};
var response = Classroom.Courses.list(optionalArgs);
var courses = response.courses;
if (courses && courses.length > 0) {
for (i = 0; i < courses.length; i++) {
var course = courses[i];
Logger.log('%s (%s)', course.name, course.id);
}
} else {
Logger.log('No courses found.');
}
}

Related

How do you identify questions that the bot could not answer

My organisation is starting to experiment with the Microsoft bot framework. One of the questions our enterprise architect has asked is as follows:
How do we identify questions that the bot was unable to answer?
I've checked the documentation but I'm still unclear. Can anyone elaborate on the techniques that they use to identify unanswered questions? We feel this is important as it identifies opportunities for further growth.
You can achieve this using a number of techniques. Essentially, what you are trying to do is to store any questions the Bot has not been able to provide an answer for analysis.
You can do this by using the scoring mechanism in the QnAMaker. For example, if the QnAMaker returns a score of zero, an answer doesn't exist, so we need to write that question back to storage for analysis.
You can use a number of storage solutions for this in the Azure stack, such as Application Insights, Cosmos, Blob, SharePoint Lists etc.
In the example below (code trimmed for brevity), I'm using Application Insights to store this information. I have imported the botbuilder-applicationinsights package and have created a simple custom event to capture any responses that score zero against the QnAMaker.
const {
ApplicationInsightsTelemetryClient,
ApplicationInsightsWebserverMiddleware
} = require('botbuilder-applicationinsights');
const {
MessageFactory,
CardFactory
} = require('botbuilder');
const {
QnAServiceHelper
} = require('../helpers/qnAServiceHelper');
const {
CardHelper
} = require('../helpers/cardHelper');
const {
FunctionDialogBase
} = require('./functionDialogBase');
// Setup Application Insights
settings = require('../settings').settings;
const appInsightsClient = new ApplicationInsightsTelemetryClient(settings.instrumentationKey);
class QnADialog extends FunctionDialogBase {
constructor() {
super('qnaDialog');
}
async processAsync(oldState, activity) {
var newState = null;
var query = activity.text;
var qnaResult = await QnAServiceHelper.queryQnAService(query, oldState);
var qnaAnswer = qnaResult[0].answer;
var qnaNonResponse = qnaResult[0].score;
var prompts = null;
if (qnaResult[0].context != null) {
prompts = qnaResult[0].context.prompts;
}
var outputActivity = null;
if (prompts == null || prompts.length < 1) {
outputActivity = MessageFactory.text(qnaAnswer);
} else {
var newState = {
PreviousQnaId: qnaResult[0].id,
PreviousUserQuery: query
}
outputActivity = CardHelper.GetHeroCard(qnaAnswer, prompts);
}
if (qnaNonResponse === 0) {
const {
NonResponseCard
} = require('../dialogs/non-response');
const quicknonresponseCard = CardFactory.adaptiveCard(NonResponseCard);
outputActivity = ({
attachments: [quicknonresponseCard]
});
console.log("Cannot find QnA response for" + " " + query);
appInsightsClient.trackEvent({
name: "Non-response",
properties: {
question: query
}
});
}
return ([newState, outputActivity, null]);
}
}
module.exports.QnADialog = QnADialog;
I can then hook up the query I might use in Application Insights in Power Bi to surface those non-answered questions.
There are multiple ways to achieve this, but this was one I ended up going with.
Depending of the size and the complexity of your model you will want to use LUIS or qnamaker. If your mother is very simple qnamaker will works. for something a bit more complex especially if you want to make use of entities LUIS is definitely the way to go. Each of them have their own technique and #steviebleeds describe how to do it on qnamaker. For Louis you are going to look at your confidence threshold and you should record that have below the confidence threshold you have set. each time you get a prediction from Lewis it send you a list of intent each of them having a confidence percentage on the predictions. You should assess this confidence percentage and decide depending of your fresh hold if you want or not to answer you users. You also want to look at all questions that have return none intent.

Is it possible to programmatic-ally access the list of contacts in outlook using Office Add In

I am building an Add In which is supposed to grab in addition to the list of contacts an account has, the contacts (to, from, cc and bcc) that are used in the current Item (Message).
As per the documentation, the following instruction gave me zero contacts, although I have contacts in the contacts book, and reading a message with a sender email.
var contacts = Office.context.mailbox.item.getEntities().contacts;
I need to grab the list of contacts I manage in my account:
This list is accessible with the open graph APIs, I wonder if it's also accessible locally with the Office object for Office Add-Ins
Office Js does not provide APIs to get the list of contacts in the account.
But you can get an auth token from Outlook using authentication APIs, then use this token to acquire Graph token to interact with Graph APIs and get the list of contacts
Office.context.auth.getAccessTokenAsync(function (result) {
if (result.status === "succeeded") {
// Use this token to call Web API
var ssoToken = result.value;
// Now send this token to your server and acquire a Graph token
// Server can talk to Graph APIs and get contacts to display
} else {
// Handle error
}
});
Create a Node.js Office Add-in that uses single sign-on
It looks you misunderstood the documentation.
A quote:
The following example accesses the contacts entities in the current item's body.
var contacts = Office.context.mailbox.item.getEntities().contacts;
You could get all contacts using the below link:
Microsoft.Office.Interop.Outlook.Items OutlookItems;
Microsoft.Office.Interop.Outlook.Application outlookObj = new Microsoft.Office.Interop.Outlook.Application();
MAPIFolder Folder_Contacts;
Folder_Contacts = (MAPIFolder)outlookObj.Session.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
OutlookItems = Folder_Contacts.Items;
MessageBox.Show("Wykryto kontaktów: " + OutlookItems.Count.ToString());
for (int i = 0; i < OutlookItems.Count; i++)
{
Microsoft.Office.Interop.Outlook.ContactItem contact = (Microsoft.Office.Interop.Outlook.ContactItem)OutlookItems[i+1];
sNazwa = contact.FullName;
sFirma = contact.CompanyName;
sAdress = contact.BusinessAddressStreet;
sMiejscowosc = contact.BusinessAddressPostalCode + " " + contact.BusinessAddressCity;
sEmail = contact.Email1Address;
dataGridView1.Rows.Add(sNazwa, sFirma, sAdress, sMiejscowosc, sEmail);
}
For more information, please refer to the below link:
Get Outlook contacts into C# form-based application

Can you call an external API to shorten links based on google sheets input?

I have a spreadsheet that contains links created after a form entry. I'd like to call the external API of a link shortening service (not google's link shorten-er) to take the link created in a given cell, shorten it, return the value and have Google Apps Script insert that shortened link into a new cell.
Is this possible? Specifically, can I use jQuery's AJAX methods? Where should I start.
By checking the internet, I found this stackExchange question, you can try to follow the solution in this post. What you need here is URL shortener API under the resources in the script editor (Tools > Script editor) select the Advanced Google Services and activate the UrlShortener.
Here is the sample code that you need to use.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Shorten")
.addItem("Go !!","rangeShort")
.addToUi()
}
function rangeShort() {
var range = SpreadsheetApp.getActiveRange(), data = range.getValues();
var output = [];
for(var i = 0, iLen = data.length; i < iLen; i++) {
var url = UrlShortener.Url.insert({longUrl: data[i][0]});
output.push([url.id]);
}
range.offset(0,1).setValues(output);
}
For more information, explanation and some sample pictures, just check the link above.

Authorization needed for classroom.profile.emails

I'm working on a web app in Google Apps Script, and I'm having some trouble understanding how the authorization is handled. When accessing the web app as the user using the app, it prompts for authorization, and everything appears okay. However, I'm call userProfiles.get and looking for student email addresses, and it returns the profile without the email.
function classRosters() {
var teacher = Classroom.UserProfiles.get(Session.getActiveUser().getEmail());
var classList = Classroom.Courses.list({teacherId: teacher.id}).courses;
var classes = [];
for (i in classList) {
if (classList[i].courseState != 'ACTIVE') {
continue;
}
var class = classList[i];
var classId = classList[i].id;
var className = classList[i].name;
classes.push([className]);
var teacherId = Classroom.Courses.Teachers.get(classId, classList[i].ownerId).userId;
var teacherEmail = Classroom.UserProfiles.get(teacherId);
var title = Classroom.Courses.get(classId).name;
var students = Classroom.Courses.Students.list(classId).students;
var studentArray = [];
if (students) {
for (j in students) {
var currStudent = students[j];
var email = Classroom.UserProfiles.get(currStudent.userId).emailAddress;
var email = Classroom.Courses.Students.get(classId, currStudent.userId).profile.emailAddress;
studentArray.push(email);
Logger.log(email);
}
}
for (j in classes) {
if (className.indexOf(classes[j]) > -1) {
var classIndex = +j;
classes[classIndex].push(studentArray);
}
}
}
return classes;
}
I've played with the API explorer, and it shows that classroom.profile.email is required, but that's not included in the scopes. When I use the API explorer, I can authorize, and it works, and my web app will work as well until the authorization from the explorer expires.
Is there any method to prompt for authorization in the GAS library for the Classroom advanced service? I can't find anything much that's specific to GAS and not part of the overall API.
Thanks,
James
Unfortunately Apps Script doesn't allow you to request additional scopes for your advanced services. The email and photos scopes aren't required to execute the method, but are required to return email and photo data in the response. You can follow issue 3070 for progress on this problem.
Update 2015-08-17:
We just implemented a workaround, which is that the Classroom advanced service now always prompts for the following fixed set of scopes:
https://www.googleapis.com/auth/classroom.courses
https://www.googleapis.com/auth/classroom.rosters
https://www.googleapis.com/auth/classroom.profile.emails
https://www.googleapis.com/auth/classroom.profile.photos
This provides access to emails, but does mean that the scopes requested for a given script may be more than it actually needs. We hope this unblocks admins that are trying to use Apps Script to manage their Classroom data, while we work on a longer-term solution for dealing with optional scopes in Apps Script.

Get Page owner contact email and display in SharePoint 2010 Masterpage

I've built out a solution with multiple masterpages/page layouts as features for a set of SharePoint 2010 publishing site collections.
One consistent request is to be able to grab the page owner contact email and display it in the footer of the masterpage. If the page Contact Email isn't entered, then I need to grab the page owner data from the People Picker, and grab the contact email from that.
I don't want to have to add every single publishing page layout to my solution, and manually add the Contact Email column into a place holder, that seems crazy to me. I figure there has to be a way to grab the page owner data from within the masterpage, but I can't figure it out. I started looking at the jQuery SPServices library, but so far I haven't been able to figure it out there, either.
Does anyone have any experience in adding a contact email using the supplied page owner contact information in the Masterpage?
OK, in order to resolve this, you need jQuery 1.7.x+ and the SPServices jQuery library version 0.7.2 or greater installed on your site.
Use GetListItems as the operation from SPServices.
I'm searching for pages within the Pages directory, so listName is "Pages".
The CAML View Fields are basically the columns for PublishingContactEmail and PublishingContact. I found those using u2u's CAML builder version 4.0.0.0
The ows_ variables can be found in the xml view of the POST object in firebug.
The ows_PublishingContact returns a long nasty string of the contact's information. Fortunately the email address is surrounded by ,#, which made splitting it into an array and then searching for an email # easy, but that's why that's there.
function get_page_contact_email() {
var thisPageID = _spPageContextInfo.pageItemId;
var e;
$().SPServices({
operation: "GetListItems",
async: false,
listName: "Pages",
CAMLViewFields: "<ViewFields><FieldRef Name='PublishingContactEmail' /><FieldRef Name='PublishingContact' /></ViewFields>",
CAMLQueryOptions: "<QueryOptions><ExpandUserField>True</ExpandUserField></QueryOptions>",
completefunc: function (xData, Status) {
$(xData.responseXML).SPFilterNode("z:row").each(function () {
if (thisPageID == $(this).attr("ows_ID")) {
if ($(this).attr("ows_PublishingContactEmail")) { // if page email is set
e = $(this).attr("ows_PublishingContactEmail");
} else if ($(this).attr("ows_PublishingContact")) { //otherwise use contact info
var contact = $(this).attr("ows_PublishingContact").split(",#");
for (var c = 0; c < contact.length; c++) {
if (contact[c].indexOf("#") != -1) {
e = contact[c];
}
}
} else { //or nothing is set.
e = false;
}
}
});
}
});
return e;
}

Resources