G-suite Forms Quiz. Random answers [duplicate] - forms

I have to activate the properties to shuffle the question of a multiple choice type questoin, but I can't find the properties. I found this code that randomizes questions, but not the answers.
form.setShuffleQuestions(true);
Image of the visual component

Issuetracker:
This isn't currently possible. Consider adding a star (on top left) to the following feature requests for Google to prioritize the issue:
https://issuetracker.google.com/issues/36764938
https://issuetracker.google.com/issues/64134484
Partial worksround:
Partial Workaround as already mentioned in this answer is to shuffle the array creating options and setback the array using setChoiceValues(). The drawback of such server side randomizing is
It can only be done whenever the server script runs and not when client opens the form
Even if you randomize each minute, it is possible that users opening the form simultaneously will see the same order of options
Sample script:
const form = FormApp.openById('/*form id*/');
const item = form.addMultipleChoiceItem();
item.setTitle('Car or truck?');
const options = ['Truck', 'Car'];
//Durstenfeld algo
for (let i = options.length - 1; i > 0; i--) {
let rand = Math.floor(Math.random() * i);
[options[i], options[rand]] = [options[rand], options[i]];
}
item.setChoiceValues(options);

I believe that you have to randomize the options yourself with something like this:
function randomizeArray(A) {
var iA=A.slice();
var oA=[];
for(var i=0;i<A.length;i++) {
var index=Math.floor(Math.random()*iA.length);
oA.push(iA[index]);
iA.splice(index,1);
}
return oA;
}

Unfortunately, in the current sage, it seems that this cannot still be achieved by Google Forms service (FormApp).
But, On March 16, 2022, Google Forms API has been officially released. Ref By this, fortunately, I confirmed that your this question can be directly achieved using Google Forms API.
In the current stage, Google Forms API cannot be used with Advanced Google services. So it is required to do the following flow.
Usage:
1. Linking Google Cloud Platform Project to Google Apps Script Project for New IDE.
In order to use Forms API, please link Google Cloud Platform Project to Google Apps Script Project for New IDE, and please enable Forms API at the API console. Ref
When Google Forms API can be used with Advanced Google services, this process can be skipped.
2. Scope.
In order to use this sample script, please use the following scopes. Ref
https://www.googleapis.com/auth/script.external_request
https://www.googleapis.com/auth/forms
https://www.googleapis.com/auth/forms.body
When Google Forms API can be used with Advanced Google services, this process can be skipped.
3. Sample script:
Please copy and paste the following script to the script editor linked to Google Cloud Platform Project and save the script.
function myFunction() {
const formTitle = "sample"; // This is a form title.
// THis is an object for creating quizzes.
const obj = [
{ "question": "sample question 1", "answers": ["answer1", "answer2", "answer3"], "correct": ["answer1"], "point": 1, "type": "RADIO" },
];
// Create new Google Form and set as quize.
const form = FormApp.create(formTitle);
form.setIsQuiz(true).setTitle("Sample");
// form.setShuffleQuestions(true); // If you want to shuffle questions, you can use this line.
// Create request body for Google Forms API.
const url = `https://forms.googleapis.com/v1/forms/${form.getId()}:batchUpdate`;
const requests = obj.map(({ question, answers, correct, point, type }, index) => ({
createItem: {
item: {
title: question,
questionItem: { question: { choiceQuestion: { options: answers.map(value => ({ value })), shuffle: true, type }, grading: { correctAnswers: { answers: correct.map(e => ({ value: e })) }, pointValue: point } } },
}, location: { index }
}
}));
// Request to Google Forms API.
const params = {
method: "post",
contentType: "application/json",
headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() },
payload: JSON.stringify({ requests }),
muteHttpExceptions: true
};
const res = UrlFetchApp.fetch(url, params);
console.log(res.getContentText())
}
When this script is run, as a sample, a new Google Form is created, and a sample question including the radio button is set. And, you can confirm that "Shuffle option order" is checked.
References:
Linking Google Cloud Platform Project to Google Apps Script Project for New IDE
Method: forms.batchUpdate

Related

Sailsjs - Cloud SDK - Blueprint API auto generated routes?

I wonder if it is possible to have the Blueprint API support in Cloud SDK.
But apparently, the generated cloud.setup.js file does not contain blueprint APIs. Just normal routes beginning with /api
It is written in the Cloud.js file :
* ### Basic Usage
*
* var user = await Cloud.findOneUser(3);
*
* var user = await Cloud.findOneUser.with({ id: 3 });
It lets think that it's possible to have auto generated routes to the blueprint APIs like actionModel -> findOneUser, createServer, addToGame, and so on...
Do you know if that is possible ? I don't find a documentation about this.
Thanks
I took original code in rebuild-cloud-sdk.js and created a rcsdk.js with the code below before the actual for (let address in sails.config.routes):
_.each(_.keys(sails.models), model => {
let action = sails.config.blueprints.prefix + sails.config.blueprints.restPrefix + '/' + model;
_.each([['GET', 'find'], ['POST', 'create']], pair => {
endpointsByMethodName[`${pair[1]}${model}`] = {
verb: pair[0],
url: action,
}
});
_.each([['GET', 'findOne'], ['PUT', 'update'], ['DELETE', 'delete']], pair => {
endpointsByMethodName[`${pair[1]}${model}`] = {
verb: pair[0],
url: action,
args: ['id'],
}
});
});
I also asked this question the other day. It is not possible. We need to be explicit here. Blueprint routes is only for quick integration testing with postman. I don't recommend this though. You should not be using postman or auto routes. You should write tests in files so they are permanent.

MongoDB Stitch REST API - Payload Signature Verification

I am working on a SANDBOX Cluster & a new app created by me in MongoDB Stitch.
I need to understand "Payload Signature Verification" in MongoDB Stitch App. Lets say, I need to make a REST GET API, which will fetch me a list of products, but this API call must be authenticated ie. only registered/authenticated users will be able to make this call. MongoDB Stitch suggests below to do that:
https://docs.mongodb.com/stitch/services/webhook-requests-and-responses/#webhook-verify-payload-signature
But, i need to understand:
(1) Where to add this BODY & SECRET ? As per my knowledge, it must be kept in the stitch app, as you must not expose any of your secret keys in client side javascript.
(2) { "message":"MESSAGE" } is this configurable? if yes, what value should we add here?
This function must be coded in MongoDB Stitch App. That is clear. This function returns "hash" based on the "body" & "secret" you pass in earlier step.
And now, you must pass this hash in your API Request:
Now, the question is:
You can easily see any request which is being passed to server in developer tools, anybody can easily copy it & pass it same through POSTMAN. So:
-> How do i secure my requests? (FYI: I have also added "RULES", saying this request must execute only if the domain name contains lets say, www.mysite.com. But i am able to execute the request successfully from localhost.)
-> If, anybody can copy & paste my request in POSTMAN & run it. SO, what is the use of generating that HASH ?
-> How do i keep my request(s) tokens alive/valid for limited period of time, lets say request is valid only for next 5 minutes ? (i mean how do i do this in Stitch APP ? Where is that Option ?)
-> How do i get the refresh token ? & even if i get it somehow, how do i re-pass it to the request ?
All such queries are UN_ANSWERED in MongoDB Stich Documentation : https://docs.mongodb.com/stitch/
Basically i want to understand the full life-cycle of any GET/POST/PUT/PATCH/DELETE request of MongoDB Stitch App / Stitch REST APIs.
If anybody have used MongoDB Stich, please explain me.
I don't know your specific use-case, though I also had issues with creating an Authenticated HTTP REST API. My idea was: I already have all security rules and schemas defined in Stitch, now I want to access the data over HTTP still using the logic defined in Stitch and not rewriting everything.
I wasn't able to create such API with Stitch functions and Webhooks, though I created an API server in (literally) 1 hour with NodeJS Koa (express or any other framework would do) and Stitch server SDK:
// app.js
const Koa = require('koa')
const app = module.exports = new Koa()
const auth = require('./auth')
const router = require('./router')
app.use(auth())
app.use(router.routes())
app.use(router.allowedMethods())
// listen
if (!module.parent) {
app.listen(3000)
}
// auth.js
const { loginWithApiKey } = require('./stitch')
function auth () {
return async function auth (ctx, next) {
const apiKey = ctx.query.api_key
try {
await loginWithApiKey(apiKey)
} catch (e) {
ctx.throw(401, 'Not Authorized')
}
await next()
}
}
module.exports = auth
// router.js
const router = require('koa-router')()
const { BSON } = require('mongodb-stitch-server-sdk')
const { db } = require('./stitch')
router.get('/', async (ctx) => {
ctx.body = { message: 'Nothing to see, but you\'re good!' }
})
const COLLECTIONS_WHITELIST = [
'activities',
'expenses',
'projects',
'resources'
]
// List
router.get('/:collection', async (ctx) => {
const collection = ctx.params.collection
isValidCollection(ctx, collection)
ctx.body = await db
.collection(collection)
.find()
.toArray()
})
function isValidCollection (ctx, collection) {
// check if the collection is allowed in the API
if (!COLLECTIONS_WHITELIST.includes(collection)) {
ctx.throw(404, `Unknown API entity ${collection}`)
}
}
module.exports = router
I hope it helps

HttpClient append parameter object to GET request

I'm quite the noob using Ionic or Angular for that matter. So as a cheat sheet I'm using the ionic-super-starter template (link below).
I am trying to make a get request to my API and it works just find if I'm doing it like this:
this.api.get('user/'+this.user.userId+'/entries?include=stuff&access_token=TOKEN');
but when I put the url params into an object it stops working:
let options = {
'include':'stuff',
'access_token':'TOKEN'
}
this.api.get('user/'+this.user.userId+'/entries', options);
The only error I get is "Unauthorized Request" since the options object including the access token was not appended to the url.
In the ionic-super-starter template the providers/api/api.ts calls .set() for each key in my params object:
if (params) {
reqOpts.params = new HttpParams();
for (let k in params) {
reqOpts.params.set(k, params[k]);
}
}
but according to Angular University this is not possible since "HTTPParams is immutable".
If it really was wrong to do this, I don't believe it would be in the ionic template. Nor would I believe that I would be the first person to come across this issue.
However, I am stuck here so any help would be appreciated.
Link to Angular University:
https://blog.angular-university.io/angular-http/#httprequestparameters
Link to ionic-super-starter:
https://github.com/ionic-team/starters/tree/master/ionic-angular/official/super
I think I figured it out myself:
if I write (in my src/providers/api/api.ts)
reqOpts.params = reqOpts.params.append(k, params[k]);
instead of
reqOpts.params.set(k, params[k]);
it works.
if you are using a loopback API as I am you might have nested objects like:
let options = {
"filter": {
"order": "date DESC"
},
"access_token":this.user._accessToken
};
this won’t work. try instead:
let options = {
"filter": '{"order":"date DESC"}',
"access_token":this.user._accessToken
};

slack doesn't recognize github webhook payload format

I'm trying to create a slack app that uses incoming webhooks. I want my github repository to post to slack whenever the wiki is updated. I believe I've set up the webhook on github just fine, because I can see that it is attempting a delivery whenever I update the wiki. However, there's always the error, "no_text". I think this error means slack is expecting an item named "text," but the payload from github provides none. I verified this by trying two curl commands from the command prompt (I'm on windows):
curl -X POST -H "Content-type: application/json" --data "{\"text\":\"Hello, World!\"}" [MY_WEBHOOK_URL]
curl -X POST -H "Content-type: application/json" --data "{\"foobar\":\"Hello, World!\"}" [MY_WEBHOOK_URL]
This first one works as expected; the message "Hello, World!" gets posted to the slack channel I wanted, and I got back the "ok" message from curl. The second one did not work; the message was not posted, and I got back the message "no_text" from curl.
I can think of two possible solutions to this problem:
Change the format of the payload coming from github to include an item called "text" and other properties slack actually recognizes.
Get slack to recognize the format the payload is already in, perhaps by telling it to post the contents of a property other than "text."
I don't know how to accomplish either of these, or if they're even possible. Or perhaps there's another solution I haven't thought of?
Note: I already tried to use the github slack app, but couldn't figure out how to get it to post updates to the wiki. (See my other question if you'd like: slack github integration doesn't find wiki repository)
I'm actually looking to do the same thing as you right now. Because the github and slack hooks are fundamentally different, you will need to have something in the middle to process the github webhooks into a Slack message to be posted via an incoming webhook.
You're going to need to do a couple different things (in no particular order):
Set up Github to send out hooks for the specific events you wish to be notified of.
Configure a middle man (I am currently using AWS SNS and Lambda)
Set up slack for the webhook.
For the github webhooks, you will need to leverage the more powerful github API to create the hook. You could do this with curl, but that's kind of a pain so I am using a JS script to take care of it. You will need to npm install github bluebird in the same directory before running something like this:
var GitHubApi = require("github");
var github = new GitHubApi({
// optional
debug: true,
protocol: "https",
host: "api.github.com", // should be api.github.com for GitHub
pathPrefix: "", // for some GHEs; none for GitHub
headers: {
"user-agent": "ocelotsloth-conf" // GitHub is happy with a unique user agent
},
Promise: require('bluebird'),
followRedirects: false, // default: true; there's currently an issue with non-get redirects, so allow ability to disable follow-redirects
timeout: 5000
});
// user token
github.authenticate({
type: "token",
token: "GITHUB_TOKEN_HERE",
});
// https://mikedeboer.github.io/node-github/#api-repos-createHook
github.repos.createHook({
owner: "ocelotsloth",
repo: "lib-ical",
name: "amazonsns",
events: [
//"commit_comment",
//"create",
//"delete",
//"gollum",
//"issue_comment",
"issues"
//"label",
//"milestone",
//"pull_request",
//"pull_request_review",
//"pull_request_review_comment",
//"push",
//"release"
],
config: {
aws_key: "AWS_KEY",
aws_secret: "AWS_SECRET",
sns_region: "us-east-1",
sns_topic: "SNS_TOPIC_ARN"
},
}, function(err, res) {
console.log(JSON.stringify(res, null, '\t'));
});
I remember following a blog post a while ago about setting up the SNS topic to work properly, but I don't remember exactly where it is anymore. Some googling should help. Also, you should be able to set up your own server for github to send these to and avoid having to set up AWS at all if you want to avoid the complexity. See https://mikedeboer.github.io/node-github/#api-repos-createHook for specific instructions on that method. You will need to use editHook after you create the hook, so either get it right the first time or use edit it. You just need to change the method call to editHook and add the id to the call as well.
Something important to see, you can define all of the different Events that you want github to send to you. For all of these, along with their formats, look at https://developer.github.com/v3/activity/events/types/.
To actually post these events to slack, I have a lambda script that currently looks like this (I literally just started writing this today, and haven't implemented more than just posting issue events, but it should do well as a starting point). For this script, you will need to npm install identify-github-event slack-webhook and have your incoming webhook set up as well.
var identifyGithubEvent = require('identify-github-event');
var SlackWebhook = require('slack-webhook')
// slack's link syntax
function link(url, txt) {
return "<" + url + "|" + txt + ">";
}
exports.handler = function(event, context) {
// 1. extract GitHub event from SNS message
var ghEvent = JSON.parse(event.Records[0].Sns.Message);
var eventType, eventName, numb;
console.log(ghEvent);
var ghEventType = identifyGithubEvent(ghEvent);
if (!ghEventType) {
return;
}
var text = "Event! " + ghEventType;
if (ghEventType === 'IssueCommentEvent') {
var who = link(ghEvent.comment.user.html_url, ghEvent.comment.user.login);
var what = link(ghEvent.issue.html_url, "Issue " + ghEvent.issue.number + ": \"" + ghEvent.issue.title + "\"");
text = who + " commented on " + what;
}
else if (ghEventType === 'IssuesEvent') {
var who = link(ghEvent.sender.html_url, ghEvent.sender.login);
var action = ghEvent.action;
var issueNumber = ghEvent.issue.number;
var issueName = link(ghEvent.issue.html_url, ghEvent.issue.title + "\"");
if (action === "opened" | action === "closed") {
text = {
attachments: [{
"fallback": who + " opened Issue" + issueNumber + ": " + issueName,
"color": "#36a64f",
"pretext": "New issue " + action + ":",
"author_name": ghEvent.sender.login,
"author_link": ghEvent.sender.html_url,
"thumb_url": ghEvent.sender.avatar_url,
"title": "#" + issueNumber + ": " + ghEvent.issue.title,
"title_link": ghEvent.issue.html_url,
"text": ghEvent.issue.body,
"fields": [
{
"title": "Status",
"value": ghEvent.issue.state,
"short": true
},
{
"title": "Labels",
"value": ghEvent.issue.labels.map(label => label.name).join("\n"),
"short": true
}
],
"footer": "lib-ical",
"footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
"mrkdwn_in": ["text"]
}]
};
} else return;
}
// 'commit_comment':
// 'create':
// 'delete':
// 'issues':
// 'label':
// 'member':
// 'milestone':
// 'pull_request':
// 'pull_request_review':
// 'pull_request_review_comment':
// 'push':
// 'release':
var slack = new SlackWebhook('https://hooks.slack.com/services/SLACK-WEBHOOK-URL', {
defaults: {
username: 'GitHub -- user/project',
channel: '#CHANNEL-NAME',
icon_emoji: ':github:'
}
})
slack.send(text);
};
It's far from perfect, but it gives a really nice result:
For that specific example it's an issue close, but currently that script will also work on open. The script also does limited markdown processing, so if the issue contains any source blocks, it will be rendered properly inside of slack.
I hope this helps you with your approach, feel free to ask me to elaborate on anything else.

How to construct a REST API that takes an array of id's for the resources

I am building a REST API for my project. The API for getting a given user's INFO is:
api.com/users/[USER-ID]
I would like to also allow the client to pass in a list of user IDs. How can I construct the API so that it is RESTful and takes in a list of user ID's?
If you are passing all your parameters on the URL, then probably comma separated values would be the best choice. Then you would have an URL template like the following:
api.com/users?id=id1,id2,id3,id4,id5
api.com/users?id=id1,id2,id3,id4,id5
api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5
IMO, above calls does not looks RESTful, however these are quick and efficient workaround (y). But length of the URL is limited by webserver, eg tomcat.
RESTful attempt:
POST http://example.com/api/batchtask
[
{
method : "GET",
headers : [..],
url : "/users/id1"
},
{
method : "GET",
headers : [..],
url : "/users/id2"
}
]
Server will reply URI of newly created batchtask resource.
201 Created
Location: "http://example.com/api/batchtask/1254"
Now client can fetch batch response or task progress by polling
GET http://example.com/api/batchtask/1254
This is how others attempted to solve this issue:
Google Drive
Facebook
Microsoft
Subbu Allamaraju
I find another way of doing the same thing by using #PathParam. Here is the code sample.
#GET
#Path("data/xml/{Ids}")
#Produces("application/xml")
public Object getData(#PathParam("zrssIds") String Ids)
{
System.out.println("zrssIds = " + Ids);
//Here you need to use String tokenizer to make the array from the string.
}
Call the service by using following url.
http://localhost:8080/MyServices/resources/cm/data/xml/12,13,56,76
where
http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76
As much as I prefer this approach:-
api.com/users?id=id1,id2,id3,id4,id5
The correct way is
api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5
or
api.com/users?ids=id1&ids=id2&ids=id3&ids=id4&ids=id5
This is how rack does it. This is how php does it. This is how node does it as well...
There seems to be a few ways to achieve this. I'd like to offer how I solve it:
GET /users/<id>[,id,...]
It does have limitation on the amount of ids that can be specified because of URI-length limits - which I find a good thing as to avoid abuse of the endpoint.
I prefer to use path parameters for IDs and keep querystring params dedicated to filters. It maintains RESTful-ness by ensuring the document responding at the URI can still be considered a resource and could still be cached (although there are some hoops to jump to cache it effectively).
I'm interested in comments in my hunt for the ideal solution to this form :)
You can build a Rest API or a restful project using ASP.NET MVC and return data as a JSON.
An example controller function would be:
public JsonpResult GetUsers(string userIds)
{
var values = JsonConvert.DeserializeObject<List<int>>(userIds);
var users = _userRepository.GetAllUsersByIds(userIds);
var collection = users.Select(user => new { id = user.Id, fullname = user.FirstName +" "+ user.LastName });
var result = new { users = collection };
return this.Jsonp(result);
}
public IQueryable<User> GetAllUsersByIds(List<int> ids)
{
return _db.Users.Where(c=> ids.Contains(c.Id));
}
Then you just call the GetUsers function via a regular AJAX function supplying the array of Ids(in this case I am using jQuery stringify to send the array as string and dematerialize it back in the controller but you can just send the array of ints and receive it as an array of int's in the controller). I've build an entire Restful API using ASP.NET MVC that returns the data as cross domain json and that can be used from any app. That of course if you can use ASP.NET MVC.
function GetUsers()
{
var link = '<%= ResolveUrl("~")%>users?callback=?';
var userIds = [];
$('#multiselect :selected').each(function (i, selected) {
userIds[i] = $(selected).val();
});
$.ajax({
url: link,
traditional: true,
data: { 'userIds': JSON.stringify(userIds) },
dataType: "jsonp",
jsonpCallback: "refreshUsers"
});
}