Create Classroom annoucement with Google script - google-apps-script

Does exist a way to creare an Announcement in Google Classroom within Google App Script?
I've looked in the reference but only the REST way is documented.
In the editor it seems to exists a Classroom.newAnnouncement, but there's no documentation on what fields it requires and how to attach the created announcement to a course.
Any experience with that?

Here's the code.
function createAnnounce() {
var ClassSource = {
text: "STRINGS"+"\n"+"STRINGS"
};
Classroom.Courses.Announcements.create(ClassSource, COURSEID)
Logger.log(ClassSource);
}

The previous answer is right on the money.
you can also add a file to the announcement as is present in the updated code bellow:
function Announcement() {
var ClassSource = {
text: "STRINGS"+"\n"+"STRINGS",
materials: [
{
driveFile:{
driveFile: {
id: "FileID",
title: "Sample Document"
},
}
}
],
};
Classroom.Courses.Announcements.create(ClassSource, COURSEID)
Logger.log(ClassSource);
}

Related

How to insert Google Event with Extended Properties in GS?

I want to add / insert new event with extened properties in Google Script = .gs file.
I found code example for Calendar API - Events insert - see below. But the code uses the JavaScript client library. I want the code to run from GS file. I tried to modify but it did not work.
When using the code I want to be able to specify any calendar. Not only "primary".
// Refer to the JavaScript quickstart on how to setup the environment:
// https://developers.google.com/calendar/quickstart/js
// Change the scope to 'https://www.googleapis.com/auth/calendar' and delete any
// stored credentials.
var event = {
'summary': 'Google I/O 2015',
'location': '800 Howard St., San Francisco, CA 94103',
'description': 'A chance to hear more about Google\'s developer products.',
'start': {
'dateTime': '2015-05-28T09:00:00-07:00',
'timeZone': 'America/Los_Angeles'
},
'end': {
'dateTime': '2015-05-28T17:00:00-07:00',
'timeZone': 'America/Los_Angeles'
},
'recurrence': [
'RRULE:FREQ=DAILY;COUNT=2'
],
'attendees': [
{'email': 'lpage#example.com'},
{'email': 'sbrin#example.com'}
],
'reminders': {
'useDefault': false,
'overrides': [
{'method': 'email', 'minutes': 24 * 60},
{'method': 'popup', 'minutes': 10}
]
}
};
var request = gapi.client.calendar.events.insert({
'calendarId': 'primary',
'resource': event
});
request.execute(function(event) {
appendPre('Event created: ' + event.htmlLink);
});
Could someone please explain the difference between private and shared extended properties?
I am able to create new event using below code but looks like it will not store extended properties.
function getCalendar() {
var calendarId = 'processor#mydomain.com'
var calendar = CalendarApp.getCalendarById(calendarId)
Logger.log('The calendar is named "%s".', calendar.getName());
var eventOption = {
location: 'The Moon',
description: 'link na akci je https://us02web.zoom.us/j/83314336043',
extendedProperties: { // Extended properties of the event.
private: { // Properties that are private to the copy of the event that appears on this calendar.
creator: "Radek", // The name of the private property and the corresponding value.
},
}
}
var event = calendar.createEvent('test event from the script',
new Date(),
new Date(),
eventOption
);
var eventId = event.getId().replace(/#.*/,'') // // Remove #google.com from eventId
Logger.log('Event ID: ' + eventId)
calendarId = 'primary'
var eventSaved = Calendar.Events.get(encodeURIComponent(calendarId), eventId)
var testEx = event.extendedProperties
var test = event.extendedProperties.private["creator"];
}
Answer for question 1:
Could someone please explain the difference between private and shared extended properties?
The official document says as follows.
extendedProperties.private: Properties that are private to the copy of the event that appears on this calendar.
extendedProperties.shared: Properties that are shared between copies of the event on other attendees' calendars.
For example, when a new event is created with the values of extendedProperties.private and extendedProperties.shared by including the attendees, you can see both values. But, the attendees can see only the value of extendedProperties.shared.
Is this explanation useful?
Answer for question 2:
I want to add / insert new event with extened properties in Google Script = .gs file.
When I saw the official document of the method of createEvent(title, startTime, endTime, options), it seems that options has no property of extendedProperties. Ref I thought that this is the reason for your issue. If you want to create a new event including the values of extendedProperties.private and extendedProperties.shared, how about using Calendar API of Advanced Google services?
The sample script is as follows.
const calendarId = "###"; // Please set your calendar ID.
// Create a new event including extendedProperties.
const params = {
start: { dateTime: "2022-04-27T00:00:00Z" },
end: { dateTime: "2022-04-27T01:00:00Z" },
extendedProperties: {
private: { key1: "value1" },
shared: { key2: "value2" }
},
summary: "sample",
attendees: [{ email: "###" }] // Please set the email of attendee, if you want to include.
};
const res1 = Calendar.Events.insert(params, calendarId);
// Check the value of extendedProperties
const res2 = Calendar.Events.get(calendarId, res1.id);
console.log(res2.extendedProperties)
When this script is run by the owner of the calendar, you can see both values of extendedProperties.private and extendedProperties.shared.
When you get this event by the attendee, you can see only the value of extendedProperties.shared.
References:
createEvent(title, startTime, endTime, options)
Events: insert
Could someone please explain the difference between private and shared extended properties?
Based on documentation, shared extended properties are visible and editable by attendees while private set on one attendee's local "copy" of the event.
To add extended properties to events with Apps Script, you can do it with the advanced Calendar service. For this, you need to add the “Google Calendar API” service in your Apps Script project, on the left side of the screen, click on the “+” next to “Services”, search for “Google Calendar API”, click on it and click “Add”.
After completing the steps mentioned above, you can test this script I created as an example.
function createEvent() {
var calendarId = 'processor#mydomain.com' //you can specify the calendar with the calendar id
var start = new Date();
var end = new Date();
var event = {
"location": "The Moon",
"description": "link na akci je https://us02web.zoom.us/j/83314336043",
"start": {
"dateTime": start.toISOString(),
},
"end": {
"dateTime": end.toISOString()
},
"extendedProperties": {
"private": {
"creator": "Radek"
}
}
};
event = Calendar.Events.insert(event, calendarId);
Logger.log('Event ID: ' + event.id);
}

Show changes to Calendar Event in view after advanced Calendar update

I am programmatically updating a calendar event from a button click in the add-on sidebar. I want to add the conferenceData to the event and have the conference appear in the event when I do so.
I am able to update the event with the conference data fine, but I have to refresh the page to see the conference in the event. How do I get the conference to appear without refresh?
I know it's possible because the zoom add-on does exactly this.
function createConference(e, label, uri) {
var event = Calendar.Events.get(e.calendar.calendarId, event.id);
event.conferenceData = {
conferenceId: newWaitingRoom._id,
entryPoints: [
{
label: label,
entryPointType: 'video',
uri: uri
}
],
conferenceSolution: {
key: { type: 'addOn' },
name: 'Digideck Live',
}
}
try {
event = Calendar.Events.update(event, e.calendar.calendarId, event.id, { conferenceDataVersion: 1 }, { 'If-Match': event.etag });
Logger.log('Successfully updated event: ' + event.id);
} catch (err) {
Logger.log('Fetch threw an exception: ' + err);
throw Error(err);
}
var nav = CardService.newNavigation().updateCard(createdConferenceCard);
return CardService.newActionResponseBuilder()
.setNavigation(nav)
.build();
}
Zoom Add-on example
picture 1:
before clicking Add Meeting button
picture 2:
after clicking Add Meeting Button (no other interactions, no refresh)
any help is greatly appreciated!
I figured it out. Instead of using the advanced Calendar API, you have to return
return CardService.newCalendarEventActionResponseBuilder()
.setConferenceData(ConferenceData).build();
EDIT: also found out that setting "currentEventAccess": "READ_WRITE" in the appsscript.json file is important to be able to get conferenceData from selected events via "eventOpenTrigger" etc

My GSM Gmail addon does not show the card

I have built a GSM add on and published it for my domain. I built the code, on Google Apps Script and set it up in Google API Console. I installed it for my domain, but it does not show the card in Gmail It should show in the sidebar, and in the compose window. It works fine when I install the head version from within google apps script, but then I publish it to GSM for users in my organization it doesn't work. The purpose of the addon is to collect information from fields in a card and use that in an email template. I think it might be something to do with OAuth scopes but I am not sure. This is my very first GSM project and I don't know what OAuth scopes I should declare in my code and in the Google API console.
Here is my code, I have 2 files, appscript.json, and code.gs.
code.gs:
function onGmailCompose(e) {
console.log(e);
var header = CardService.newCardHeader()
.setTitle('Use Template')
.setSubtitle('Use the template for sending an email after a review has been published.');
// Create text input for entering the cat's message.
var input2 = CardService.newTextInput()
.setFieldName('FName')
.setTitle('First Name')
.setHint('What is the readers first name?');
var input3 = CardService.newTextInput()
.setFieldName('BookTitle')
.setTitle('Reviewed Book Title')
.setHint('What is the title of the book reviewed?');
var input4 = CardService.newTextInput()
.setFieldName('BookAuthor')
.setTitle('Reviewed Book Author')
.setHint('Who is the author of the book reviewed?');
// Create a button that inserts the cat image when pressed.
var action = CardService.newAction()
.setFunctionName('useTemplate');
var button = CardService.newTextButton()
.setText('Use Template')
.setOnClickAction(action)
.setTextButtonStyle(CardService.TextButtonStyle.FILLED);
var buttonSet = CardService.newButtonSet()
.addButton(button);
// Assemble the widgets and return the card.
var section = CardService.newCardSection()
.addWidget(input2)
.addWidget(input3)
.addWidget(input4)
.addWidget(buttonSet);
var card = CardService.newCardBuilder()
.setHeader(header)
.addSection(section);
return card.build();
}
function useTemplate(e) {
console.log(e);
var FName = e.formInput.FName;
var Title = e.formInput.BookTitle;
var Author = e.formInput.BookAuthor;
var now = new Date();
var htmlIntro = '<p>Hello, ';
var html2 = ' Thank you for writing a book review at Good Book Reviews on ';
var html3 = ' by ';
var html4 = '. You Review has been published to our site. Any personal information you included was NOT published, including first name, last name, age, and email address. Only info you wrote about the book was published. You can see it right here! If you need anything else, feel free to contact us at support#goodbookreviews.page or reply to this email to contact us. <br> Happy Reading,<br> The Book Review Team</p>';
var message = htmlIntro + FName + html2 + Title + html3 + Author + html4;
var response = CardService.newUpdateDraftActionResponseBuilder()
.setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction()
.addUpdateContent(message, CardService.ContentType.MUTABLE_HTML)
.setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT))
.build();
return response;
}
function onGmailMessage(e) {
console.log(e);
var header = CardService.newCardHeader()
.setTitle('Unavailable')
.setSubtitle('Open the compose window to use template');
var card = CardService.newCardBuilder()
.setHeader(header);
return card.build();
}
appscript.json:
{
"timeZone": "America/Chicago",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": ["https://www.googleapis.com/auth/gmail.compose"],
"runtimeVersion": "V8",
"addOns": {
"common": {
"name": "Review Published Email Template",
"logoUrl": "https://goodbookreviews.page/Logo.png",
"useLocaleFromApp": true,
"universalActions": [{
"label": "Book Review ",
"openLink": "https://www.goodbookreviews.page"
}]
},
"gmail": {
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "onGmailMessage"
}],
"composeTrigger": {
"selectActions": [{
"text": "Use Template",
"runFunction": "onGmailCompose"
}],
"draftAccess": "NONE"
}
}
}
}
The scopes that I specify in the OAuth consent screen page are here:
email
profile
openid
https://www.googleapis.com/auth/gmail.compose
The Email, profile, and openid are added by default and they are mandatory
Here are the scopes that I specify in the configuration page of the GSM SDK.
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/gmail.compose
You are very close to making this add-on works. You only need to add some scopes to your manifest file. Your final manifest should look similar to this one:
{
"timeZone":"America/Chicago",
"dependencies":{
},
"exceptionLogging":"STACKDRIVER",
"oauthScopes":[
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.addons.current.action.compose",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/script.locale"
],
"runtimeVersion":"V8",
"addOns":{
"common":{
"name":"Review Published Email Template",
"logoUrl":"https://goodbookreviews.page/Logo.png",
"useLocaleFromApp":true,
"universalActions":[
{
"label":"Book Review ",
"openLink":"https://www.goodbookreviews.page"
}
]
},
"gmail":{
"contextualTriggers":[
{
"unconditional":{
},
"onTriggerFunction":"onGmailMessage"
}
],
"composeTrigger":{
"selectActions":[
{
"text":"Use Template",
"runFunction":"onGmailCompose"
}
],
"draftAccess":"NONE"
}
}
}
}
The rest of your code is correct. I deployed your add-on with this manifest, and it worked. Don't hesitate to ask any additional doubt if you need further clarification.

How to apply a FilterView to a Gsheet via Apps Script

I have created some Google Apps Script code which creates GSheets FilterViews. I cannot see how to apply a specific FilterViews (not Filters) to the current sheet.
The code i have sets FilterSettings and then applies it to a basic filter but i cannot see in the documentation how to apply a similar approach to filterview.
if (condition!=0 && hiddenValues.length>0)
{
filterSettings['criteria'][COLUMNS.ASSIGNEE.pos] = {
'hiddenValues': hiddenValues,
'condition': condition
};
}
else if(hiddenValues.length>0)
{
filterSettings['criteria'][COLUMNS.ASSIGNEE.pos] = {
'hiddenValues': hiddenValues,
};
}
else if(condition!=0)
{
filterSettings['criteria'][COLUMNS.ASSIGNEE.pos] = {
'condition': condition
};
}
// Using BASIC FILTER not FILTER VIEW
var request = {
"setBasicFilter": {
"filter": filterSettings
}
}
Sheets.Spreadsheets.batchUpdate({'requests': [request]}, ss.getId());
Have looked at this doc:-
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/sheets#FilterView
https://developers.google.com/sheets/api/reference/rest/v4/FilterCriteria
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ConditionType
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ConditionValue
I can see that historically its not been supported but I wonder if that is still the case.
I can see if i look at the requests API there are request types for:-
addFilterView
deleteFilterView
updateFilterView
duplicateFilterView
There is no SetFilterView.
What is the right way to activate a filter view via GAS.
Thanks

(How) can I use the module pattern in Google Apps scripts?

I tried to put my menu functions inside a module like this:
var mainmenuModule = function() {
return {
menuItemX: function() {...},
menuItemY: function() {...}
};
}();
But when I create a menu item, my function is not found:
{ name: "X", functionName: "mainMenuModule.menuItemX"}
I'm doing this inside a Spreadsheet container.
You can't currently do this but I see that Issue 1355 has been logged as an enhancement to support this for libraries. You can "star" the issue to receive updates.