I'm a little worried and in a hurry and I'm not sure if this is the right place to ask this, but I literally have no idea where else to ask.
Long story short, I wanted to clear my gmail account from spam and found the following link while searching for a way to do this:
https://www.labnol.org/internet/gmail-unsubscribe/28806/
Like a complete idiot, I followed the instructions blindly without suspecting anything. After completing the steps, nothing really happened (the spreadsheet wasn't filling) so I stopped the script and removed it from my google accounts permissions and started inspecting the code that was used. It consists of three files, the google script:
function getConfig() {
var params = {
label:doProperty_("LABEL") || "Unsubscribe"
};
return params;
}
function config_() {
var html = HtmlService.createHtmlOutputFromFile('config')
.setTitle("Gmail Unsubscriber")
.setWidth(300).setHeight(200).setSandboxMode(HtmlService.SandboxMode.IFRAME);
var ss = SpreadsheetApp.getActive();
ss.show(html);
}
function help_() {
var html = HtmlService.createHtmlOutputFromFile('help')
.setTitle("Google Scripts Support")
.setWidth(350).setHeight(120);
var ss = SpreadsheetApp.getActive();
ss.show(html);
}
function createLabel_(name) {
var label = GmailApp.getUserLabelByName(name);
if (!label) {
label = GmailApp.createLabel(name);
}
return label;
}
function log_(status, subject, view, from, link) {
var ss = SpreadsheetApp.getActive();
ss.getActiveSheet().appendRow([status, subject, view, from, link]);
}
function init_() {
Browser.msgBox("The Unsubscriber was initialized. Please select the Start option from the Gmail menu to activate.");
return;
}
function onOpen() {
var menu = [
{name: "Configure", functionName: "config_"},
null,
{name: "☎ Help & Support",functionName: "help_"},
{name: "✖ Stop (Uninstall)", functionName: "stop_"},
null
];
SpreadsheetApp.getActiveSpreadsheet().addMenu("➪ Gmail Unsubscriber", menu);
}
function stop_(e) {
var triggers = ScriptApp.getProjectTriggers();
for(var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
if (!e) {
Browser.msgBox("The Gmail Unsubscriber has been disabled. You can restart it anytime later.");
}
}
function doProperty_(key, value) {
var properties = PropertiesService.getUserProperties();
if (value) {
properties.setProperty(key, value);
} else {
return properties.getProperty(key);
}
}
function doGmail() {
try {
var label = doProperty_("LABEL") || "Unsubscribe";
var threads = GmailApp.search("label:" + label);
var gmail = createLabel_(label);
var url, urls, message, raw, body, formula, status;
var hyperlink = '=HYPERLINK("#LINK#", "View")';
var hrefs = new RegExp(/<a[^>]*href=["'](https?:\/\/[^"']+)["'][^>]*>(.*?)<\/a>/gi);
for (var t in threads) {
url = "";
status = "Could not unsubscribe";
message = threads[t].getMessages()[0];
threads[t].removeLabel(gmail);
raw = message.getRawContent();
urls = raw.match(/^list\-unsubscribe:(.|\r\n\s)+<(https?:\/\/[^>]+)>/im);
if (urls) {
url = urls[2];
status = "Unsubscribed via header";
} else {
body = message.getBody().replace(/\s/g, "");
while ( (url === "") && (urls = hrefs.exec(body)) ) {
if (urls[1].match(/unsubscribe|optout|opt\-out|remove/i) || urls[2].match(/unsubscribe|optout|opt\-out|remove/i)) {
url = urls[1];
status = "Unsubscribed via link";
}
}
}
if (url === "") {
urls = raw.match(/^list\-unsubscribe:(.|\r\n\s)+<mailto:([^>]+)>/im);
if (urls) {
url = parseEmail_(urls[2]);
var subject = "Unsubscribe";
GmailApp.sendEmail(url, subject, subject);
status = "Unsubscribed via email";
}
}
if (status.match(/unsubscribed/i)) {
UrlFetchApp.fetch(url, {muteHttpExceptions: true});
}
formula = hyperlink.replace("#LINK", threads[t].getPermalink());
log_( status, message.getSubject(), formula, message.getFrom(), url );
}
} catch (e) {Logger.log(e.toString())}
}
function saveConfig(params) {
try {
doProperty_("LABEL", params.label);
stop_(true);
ScriptApp.newTrigger('doGmail')
.timeBased().everyMinutes(15).create();
return "The Gmail unsubscriber is now active. You can apply the Gmail label " + params.label + " to any email and you'll be unsubscribed in 15 minutes. Please close this window.";
} catch (e) {
return "ERROR: " + e.toString();
}
}
function parseEmail_(email) {
var result = email.trim().split("?");
return result[0];
}
And two other .html files called config.html:
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script>
function closeWindow() {
google.script.host.close();
}
function showError(error) {
document.getElementById("error").innerHTML = error;
}
function showConfig(params) {
if (params.label !== "")
document.getElementById("label").value = params.label;
return;
}
function validate() {
var label = document.getElementById("label").value;
if (label.trim() === "") {
showError("Please enter a Gmail label name..");
return;
} else {
showError("Saving configuration, please wait..");
var params = {
label: label
};
google.script.run.withSuccessHandler(showError).saveConfig(params);
}
}
</script>
<form>
<div class="form-group block">
<p style="margin-bottom:4px;">Enter Gmail Label Name:</p>
<input type="text" id="label" name="label" placeholder="Your email address.." style="width: 250px;" />
</div>
<p>
<input class="blue" type="button" value="Save configuration" onclick="validate()" />
<input class="green" type="button" value="Close window" onclick="google.script.host.close()" />
</p>
<p class="error" id="error"></p>
</form>
<script>
google.script.run.withSuccessHandler(showConfig).getConfig();
</script>
And lastly help.html:
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<base target="_blank">
</head>
<div class="block">
<p>If you are need help with the program, please refer to the online tutorial. For support and customization, please submit your requirements at <strong>ctrlq.org</strong>.</p>
</div>
<div class="block">
<a class="button blue" href="mailto:amit#labnol.org" style="width:120px;">amit#labnol.org</a>
<a class="button green" href="https://twitter.com/labnol" style="width:120px;margin-right:10px">Tweet #labnol</a>
<input class="red" type="button" value="Close" onclick="google.script.host.close()" />
</div>
Is there any way that my account could be in any danger?
I am the author of this Google Script and it is completely safe. In fact, you have access to the full source code so you know exactly what it is doing.
Also, if you like to remove any Google Script from your account, here's how:
Go to https://security.google.com/settings/security/permissions
Click the script you wish to uninstall
Next click Remove and you are done.
Related
To preface, I'm super new to programming in general, nevermind javascript.
I'm developing a web application where a user can upload a picture by clicking on a button. This action will upload pictures into a certain directory in my google drive with a unique folder and name.
Now, I'm trying to copy and paste the google drive link of a picture any time it has been uploaded.
I am able to successfully get the ID of the picture URL in my getFileUrl() method. But when I call that method within my doStuff1() function then later insert that info into userInfo.fileUrl, I am getting https://docs.google.com/document/d/undefined/ as the output in my spreadsheet.
How can call that value?
Updated: I am realizing that when I use "google.script.run.getFileUrl("fn","i"), that is when I'm getting "undefined". When I run the getFileUrl() function locally, I do get the value that I want. Please advise how I can use .WithSuccessHandler(function) correctly so that I can return the value of "fileId0".
This is the front end, where a user uploads the picture
page.html
<html>
<head>
<body>
<form action="#" method="post" enctype="multipart/form-data">
<div class="row">
<div class="file-field input-field">
<div class="waves-effect waves-light btn-small">
<i class="material-icons right">insert_photo</i>
<span>Import Picture</span>
<input id="files" type="file" name="image">
</div>
<div class="file-path-wrapper">
<input disabled selected type="text" class="file-path
validate" placeholder="Choose an image">
</div>
</div>
</div>
</form>
<?!= include("page-js"); ?>
</div> <!-- CLOSE CONTAINER-->
</body>
</html>
This is part of the javascript to put relevant info in an array, which will later be used to append a row in the google sheet
page-js.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://gumroad.com/js/gumroad.js"></script>
<script>
document.getElementById("addAnother").addEventListener("click",doStuff1);
var i=1;
var num={};
function doStuff1(){
num.picNum2=i;
var personName=document.getElementById("fn").value;
var fileId00=google.script.run.getFileUrl("fn","i");
var userInfo ={};
userInfo.firstName= document.getElementById("fn").value;
userInfo.number=i;
userInfo.fileUrl="https://docs.google.com/document/d/"+fileId00
+"/";
i++;
google.script.run.userClicked(userInfo);
}
This is part of the javascript to upload picture file into the Google drive
(still part of page-js.html)
var file,
reader = new FileReader();
var today = new Date();
var date = today.getFullYear()+'-'+(today.getMonth()+1)+'- '+today.getDate();
reader.onloadend = function(e) {
if (e.target.error != null) {
showError("File " + file.name + " could not be read.");
return;
} else {
google.script.run
.withSuccessHandler(showSuccess)
.uploadFileToGoogleDrive(e.target.result,num.picNum,date,$('input#fn')
.val(),$('input#date').val());
}
};
function showSuccess(e) {
if (e === "OK") {
$('#forminner').hide();
$('#success').show();
} else {
showError(e);
}
}
function submitForm() {
var files = $('#files')[0].files;
if (files.length === 0) {
showError("Please select a image to upload");
return;
}
file = files[0];
if (file.size > 1024 * 1024 * 5) {
showError("The file size should be < 5 MB.");
return;
}
showMessage("Uploading file..");
reader.readAsDataURL(file);
}
function showError(e) {
$('#progress').addClass('red-text').html(e);
}
function showMessage(e) {
$('#progress').removeClass('red-text').html(e);
}
</script>
This part grabs the array "userInfo" and appends the content in a row within a designated google sheet. Any time, I click on the button in the front end, it creates a new row.
Code.gs
//google sheet web script
var url="https://docs.google.com/spreadsheets/d/XXXXX";
function getFileUrl(fn,i){
try{
var today0 = new Date();
var date0 = today0.getFullYear()+'-'+(today0.getMonth()+1)+'-'
+today0.getDate();
var dropbox0 = "OE Audit Pictures";
var folder0,folders0 = DriveApp.getFoldersByName(dropbox0);
while (folders0.hasNext())
var folder0=folders0.next();
var dropbox20=[date0,fn].join(" ");
var folder20,folders20=folder0.getFoldersByName(dropbox20);
while (folders20.hasNext())
var folder20=folders20.next();
var file0, files0= folder20.getFilesByName(i);
while (files0.hasNext())
var file0=files0.next();
var fileId0=file0.getUrl();
return fileId0;
} catch(f){
return f.toString();
}
}
function userClicked(userInfo){
var ss= SpreadsheetApp.openByUrl(url);
var ws=ss.getSheetByName("Data");
ws.appendRow([userInfo.number,new Date(),
userInfo.firstName,userInfo.fileUrl]);
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function uploadFileToGoogleDrive(data, file, fn, date) {
try {
var dropbox = "OE Audit Pictures";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var contentType = data.substring(5,data.indexOf(';')),
bytes =
Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)),
blob=Utilities.newBlob(bytes, contentType, file)
var dropbox2=[fn,date].join(" ");
var folder2, folders2=folder.getFoldersByName(dropbox2)
if (folders2.hasNext()){
folder2=folders2.next().createFile(blob);
} else {
file = folder.createFolder([fn,date].join(" ")).createFile(blob);
}
return "OK";
} catch (f) {
return f.toString();
}
}
In doStuff1() of "page-js.html", you want to give a value returned from getFileUrl() of "Code.gs" to userInfo.fileUrl.
If my understanding is correct, how about this modification?
Modification point:
google.script.run.getFileUrl() doesn't return values. When you want to use the values from getFileUrl(), you can use withSuccessHandler() as following modified script.
Modified script:
Please modify doStuff1() as follows.
function doStuff1() {
num.picNum2 = i;
var personName = document.getElementById("fn").value;
google.script.run.withSuccessHandler(doStuff2).getFileUrl("fn","i"); // Modified
}
// Added
function doStuff2(fileId00) {
var userInfo = {};
userInfo.firstName = document.getElementById("fn").value;
userInfo.number = i;
userInfo.fileUrl = "https://docs.google.com/document/d/"+fileId00 +"/";
i++;
google.script.run.userClicked(userInfo);
}
Note:
In this modification, I used doStuff2() for retrieving the values from getFileUrl(). If you want to modify the function name, please modify it.
Reference:
Class google.script.run
If I misunderstood your question and this was not the result you want, I apologize.
Details - First Visit this link - http://www.flacement.com/jobssearch/iffco-tokio-job-in-jharsuguda/
its created by WP and Plugin is Jobs for Wordpress by Blueglass
what i want -- when someone click apply , some one can apply via flacement ID but i want to validate that ID from sheetsu JS API and Insert that code in backend code.
what i need you to help me
here is sheetsu api code
<head>
<script src="//script.sheetsu.com/"></script>
</head>
<body>
<script>
function successFunc(data) {
console.log(data);
}
// Get all rows where column 'adhar_no' is '3894-8873-7149'
var searchQuery = {
status: active,
};
Sheetsu.read("https://sheetsu.com/apis/v1.0dh/dd98887de543/", {
search: searchQuery
}, successFunc);
</script>
</body>
when some one write flacement ID ( 3894-8873-7149) its search from sheestu API
if value= active then proceed else , alert > your are block.
if value= not found then , alert > register here
please make me a JS validation script with HTML
Try this one
var input = document.getElementById('input-text_flacement-id');
var is_focused = false;
input.onfocus = function () {
is_focused = true;
}
input.onblur = function () {
if (is_focused) {
is_focused = false;
check_id(input.value);
}
}
function check_id(id) {
if (id.match(/\d{4}-\d{4}-\d{4}/)) {
document.body.append("\nchecking...");
function successFunc(data) {
var row = data.filter((row)=>row['adhar_no'] == id)
if(row.length){
document.body.append("\nid found");
}
else{
document.body.append('\nid not found');
}
}
// Get all rows where column 'adhar_no' is '3894-8873-7149'
var searchQuery = {
status: 'active',
};
Sheetsu.read("https://sheetsu.com/apis/v1.0dh/dd98887de543/", {
search: searchQuery
}, successFunc);
}
else {
document.body.append('\ninvalid id');
}
}
<input id="input-text_flacement-id">
<script src="https://script.sheetsu.com/"></script>
NOTE: try not using this is_focused technique
I make a form with Google script
but I don't know how to make it's field to be REQUIRED
following is my script but my gbchk(form) didn't work
The script will add a line in my excel in my google dive
but even there is no data in the form
How to make a required area in google script?
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function uploadFiles(form) {
try {
var folderName = "Upload";
var sheetName = "ulist";
var folder;
var folders = DriveApp.getFoldersByName(folderName);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(folderName);
}
//handling uploading file
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by "+ form.myName);
var fileUrl = file.getUrl();
var FileIterator = DriveApp.getFilesByName(sheetName);
var sheetApp = "";
while (FileIterator.hasNext())
{
var sheetFile = FileIterator.next();
if (sheetFile.getName() == sheetName)
{
sheetApp = SpreadsheetApp.open(sheetFile);
}
}
if(sheetApp == "")
{
sheetApp = SpreadsheetApp.create(sheetName);
}
var sheet = sheetApp.getSheets()[0];
var lastRow = sheet.getLastRow();
var targetRange = sheet.getRange(lastRow+1, 2, 1, 1).setValues([[lastRow+1,form.myName]]);
return "Upload Success!"
} catch (error) {
return "Upload fail because:"+error.toString();
}
}
function gbchk(form)
{
if (form.myName.value == "")
{
alert("Enter your name!!");
form.myName.focus();
return (false);
}
return (true);
}
I would put a required tag on the html form input. The docs for this can be found here:
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Data_form_validation#The_required_attribute
example:
<form>
<label for="choose">Would you prefer a banana or cherry?</label>
<input id="choose" name="i_like" pattern="banana|cherry" required>
<button>Submit</button>
</form>
I'm looking for a solution too.
Putting a required tag on the input fields would work. But the user can simply remove it throught the dev tools.
A slightly better approach is to set the required tags by JS. Users can still get around it, but this time they need to modify the JS itself.
I want to run a javascript function with the pre loaded text from database. This function is about to display the image from youtube. Once a pasted link is correct. It will show the thumbnail automatically.
But I want a picture to display with the pre-text link from a database.
Here is the function :
function youtube_parser(url) {
var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;
var match = url.match(regExp);
if (match && match[1].length == 11) {
urllink = match[1];
imagelink = "<img src=\"http:\/\/img.youtube.com\/vi\/"+urllink+"\/hqdefault.jpg\">";
} else {
//urllink = "test"
}
document.getElementById("ytimagelink").value = urllink;
document.getElementById("ytimage").innerHTML = imagelink;
}
HTML
<div><strong>Insert YouTube url:</strong></div>
<input type="text" id="ytlink" onkeyup="youtube_parser(this.value)">
<hr>
<div><strong>Output: YouTube video id:</strong></div>
<input type="text" id="ytimagelink" value="">
<div><strong>Output: Thumbnail</strong></div>
<div id="ytimage"></div>
Fiddle : http://jsfiddle.net/PMrLR/7/
This function will work as I put the url in #ytlink because there is a onKeyUp property to trigger the function.
So, I expect this function to work with the pre-loaded text without doing anything to it again.
Your function will work as it is, just give it the text you loaded from the database as it's argument:
// ...get data from the database somehow, and then:
youtube_parser(url_from_database);
You'll have to wait for the document to load first, and then call the youtube_parser(yourUrl). Do it like this in VanillaJS
document.addEventListener("DOMContentLoaded", function() {
youtube_parser('https://www.youtube.com/watch?v=OnXTf8FNUrc');
});
Here is the snippet for you, show it and click run button
function youtube_parser(url) {
var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;
var match = url.match(regExp);
if (match && match[1].length == 11) {
urllink = match[1];
imagelink = "<img src=\"http:\/\/img.youtube.com\/vi\/" + urllink + "\/hqdefault.jpg\">";
} else {
//urllink = "test"
}
document.getElementById("ytimagelink").value = urllink;
document.getElementById("ytimage").innerHTML = imagelink;
}
document.addEventListener("DOMContentLoaded", function() {
youtube_parser('https://www.youtube.com/watch?v=OnXTf8FNUrc');
});
body {
font-family: arial, helvetica, sans-serif;
font-size: 18px;
}
<div><strong>Insert YouTube url:</strong>
</div>
<input type="text" id="ytlink" onkeyup="youtube_parser(this.value)">
<hr>
<div><strong>Output: YouTube video id:</strong>
</div>
<input type="text" id="ytimagelink" value="">
<div><strong>Output: Thumbnail</strong>
</div>
<div id="ytimage"></div>
I'm creating my first watchface which requires a configuration page where two strings can be stored (a title and a message).
I'm not too familiar with all the communication things because there aren't really any full on examples out there but I've tried to get as far as possible with this.
Here is the relevant code to all my spaces
main.c
static void inbox_received_callback(DictionaryIterator *iterator, void *context) {
APP_LOG(APP_LOG_LEVEL_INFO, "Message received!");
// Get the first pair
Tuple *t = dict_read_first(iterator);
//Long lived buffers
static char title_buffer[64];
static char message_buffer[124];
// Process all pairs present
while(t != NULL) {
// Process this pair's key
switch (t->key) {
case TITLE_DATA:
snprintf(title_buffer, sizeof(title_buffer), "%s", t->value->cstring);
text_layer_set_text(title_layer, title_buffer);
APP_LOG(APP_LOG_LEVEL_INFO, "TITLE_DATA received with value %d", (int)t->value->int32);
break;
case MESSAGE_DATA:
snprintf(message_buffer, sizeof(message_buffer), "%s", t->value->cstring);
text_layer_set_text(message_layer, message_buffer);
APP_LOG(APP_LOG_LEVEL_INFO, "MESSAGE_DATA received with value %d", (int)t->value->int32);
break;
}
// Get next pair, if any
t = dict_read_next(iterator);
}
}
pebbleScript.js
var title = localStorage.getItem('title') ? localStorage.getItem('title') : 'Title',
message = localStorage.getItem('message') ? localStorage.getItem('message') : "Message that can be changed in watchface 'Settings'";
Pebble.addEventListener('showConfiguration', function(e) {
console.log("Showing configuration");
// Show config page
Pebble.openURL('https://dl.dropboxusercontent.com/s/kzl44khedt5e22d/config.html?dl=0');
});
Pebble.addEventListener('webviewclosed', function(e) {
var options = JSON.parse(decodeURIComponent(e.response));
title = encodeURIComponent(options.title);
message = encodeURIComponent(options.message);
if(title == 'undefined') {
title = 'Title';
} if (message == 'undefined') {
message = "Message that can be changed in watchface 'Settings'";
}
localStorage.setItem('title', title);
localStorage.setItem('message', message);
console.log("Configuration window returned: ", JSON.stringify(options));
});
Pebble.addEventListener('ready', function(e) {
console.log("PebbleKit JS Ready!");
//Construct a dictionary
var
dict = {
'TITLE_DATA' : title,
'MESSAGE_DATA' : message
};
//Send a string to Pebble
Pebble.sendAppMessage(dict, function(e) {
console.log("Send successful.");
}, function(e) {
console.log("Send failed!");
});
});
config.html
<h3>Title:</h3>
<input type="text" name="title" id="title"></input>
<h3>Message:</h3>
<input type="text" name="message" id="message"></input>
<br>
<input type="submit" id="cancelButton" value="Cancel">
<input type="submit" id="saveButton" value="Save">
<script>
$('#cancelButton').click(function() {
location.href = 'pebblejs://close';
});
$('#saveButton').click(function() {
var options = {
title: $('title').val(),
message: $('#message').val()
}
location.href = 'pebblejs://close#' + encodeURIComponent(JSON.stringify(options));
});
function getURLVariable(name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)",
regex = new RegExp(regexS),
results = regex.exec(window.location.href);
if (results == null) return "";
else return results[1];
}
$(document).ready(function() {
var priorTitle = getURLVariable('title');
priorTitle = decodeURI(priorTitle);
if (priorTitle) {
$('#title').html(priorTitle);
}
var priorMessage = getURLVariable('message');
priorMessage = decodeURI(priorTitle);
if (priorMessage) {
$('#message').html(priorMessage);
}
});
</script>
If anyone can see why this isn't working as intended I'd much appreciate help :) Please let me know if there are any other details I should include.
I'm using CloudPebble for the development. I've done the title and message keys in settings and defined them in my main.c as well so it's not that.
A note that I should make is, in the app log it shows "TITLE_DATA received with value....." but not the "MESSAGE_DATA received...." So the problem may lie somewhere over there.
You're declaring your "long lived buffers" inside the function:
static void inbox_received_callback(DictionaryIterator *iterator, void *context) {
...
//Long lived buffers
static char title_buffer[64];
static char message_buffer[124];
...
}
If you want them to stay in scope (persist), you need to declare them up with the other globals:
static Window *s_main_window;
static char title_buffer[64];
static char message_buffer[124];