I am developing my project on mvc4 , i have an issue with user is typing status notification on my chat module of the project.The problem with this j script is that it is showing the status to same user who is typing but i want that other user to see that i am typing in my text box
var textarea = $('#textarea');
var typingStatus = $('#typing_on');
var lastTypedTime = new Date(0); // it's 01/01/1970
var typingDelayMillis = 5000; // how long user can "think about his spelling" before we show "No one is typing -blank space." message
function refreshTypingStatus() {
if (!textarea.is(':focus') || textarea.val() == '' || new Date().getTime() - lastTypedTime.getTime() > typingDelayMillis) {
typingStatus.html('No one is typing -blank space.');
} else {
typingStatus.html('User is typing...');
}
}
function updateLastTypedTime() {
lastTypedTime = new Date();
}
setInterval(refreshTypingStatus, 100);
textarea.keypress(updateLastTypedTime);
textarea.blur(refreshTypingStatus);
<label>
<textarea name="textarea" id="textarea" cols="45" rows="5"></textarea>
</label>
<div id="typing_on"></div>
If you want users to see a different users typing status, you have to send the current users status to the server via AJAX and retrieve it from the server to display.
So basically, assuming two people are chatting, each client (browser) must:
Get the current users typing status and send to the server
Retrieve the other users typing status from the server and display it.
If you are unsure of how to use AJAX, you should look up jQuery's ajax documentation
Your client side code would have to change like so:
function refreshTypingStatus() {
if (!textarea.is(':focus') || textarea.val() == '' || new Date().getTime() - lastTypedTime.getTime() > typingDelayMillis) {
typingStatus.html('No one is typing -blank space.');
} else {
typingStatus.html('User is typing...');
}
//AJAX call to send typingStatus.html to server
//AJAX call to retrieve other users typingStatus (could be combined into one call)
}
Writing the code necessary is beyond an SO answer as it involves both server side and client side code, but start with this tutorial, and if you have more questions, just ask a new question specific to what you need.
Related
We are moving away from AD and going to Google Work space as our LDAP service. One of my tasks are to reproduce some tools that we have on AD to Google Workspace. One of those tools is the ability to warn a user 14 days before a password is about to expire then 7 days before and send us (IT admins) a warning 4 days before to catch it before they get locked out. So I have created this tool in PowerShell on windows and LDAP and I am trying to use Google App Scripts to do this. I have learned that the Directory API does not expose this metadata on the user (https://developers.google.com/admin-sdk/directory/v1/guides/manage-users) and I have to use the Admin Report API and search the logs for an eventName called CHANGE_PASSWORD and then build an array of user email address and the last time they changed their password.
I have got this successfully working to show me a HTML output of email address and how many days left till their password expires in a table that is generated on demand when you load the web app, but I noticed we have 120 users in our Org and only 78 users show up on the list. So then I realized that the reports section of Google Admin reports only stores 6 months worth of logs. To me the reports section is not a reliable source to determine when the user last changed their password. Does anyone have any other ideas as to how I can accurately get the date a Google Workspace user last changed their password? Here is what I currently have if anyone wants to build on this:
Please note you must add the Admin SDK API service to your script and the user running the script my have the role for reports on your domain. This is not polished code but just a proof of concept so be gentle with your replies and comments about my sloppy code
code.gs
const maxPasswordAge = 90;
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getListOfUsers() {
const userKey = 'all';
const applicationName = 'admin';
const optionalArgs = {
eventName: 'CHANGE_PASSWORD'
};
const logs = AdminReports.Activities.list(userKey, applicationName, optionalArgs);
const activities = logs.items;
if (activities && activities.length > 0) {
var passwordLastChanged = new Object();
for (i = 0; i < activities.length; i++) {
const activity = activities[i];
const key = activity.events[0].parameters[0]['value'];
const value = activity.id.time;
// If the key does not exist then add it
if (!passwordLastChanged.hasOwnProperty(key)) {
passwordLastChanged[key] = value;
}
}
} else {
Logger.log('No results found.');
}
// You will now have an object with emailaddress:Date last Changed
const todaysDate = new Date();
// Change the date to a number of days till it expires from today's date
for (const [key, value] of Object.entries(passwordLastChanged)) {
const dateLastChange = new Date(value);
const milliBetweenDate = todaysDate - dateLastChange;
const diffInDays = milliBetweenDate / (1000 * 3600 * 24);
passwordLastChanged[key] = (maxPasswordAge - diffInDays).toFixed(1);
}
// Change the object to a sorted array based on the days left till password expires
const entries = Object.entries(passwordLastChanged);
const sorted = entries.sort((a, b) => a[1] - b[1]);
return sorted;
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<style type="text/css">
body {background-color: gray;}
.tg {border-collapse:collapse;border-spacing:0;margin:0px auto;}
.td {border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal; color: floralwhite;}
.col1, .col2, .col3 {text-align:left;vertical-align:top}
.col4, .col5 {text-align:center;vertical-align:top}
</style>
<table id="myTable" class="tg">
<tbody>
<tr>
<td class="col3">Email</td>
<td class="col5">Days Left</td>
</tr>
</tbody>
</table>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(addUsersToTable).getListOfUsers();
});
function addUsersToTable(userArray) {
for (var i = 0; i < userArray.length; i++) {
$('#myTable > tbody:last-child').append('<tr><td class="col3">' + userArray[i][0] + '</td><td class="col5">' + userArray[i][1] + '</td></tr>');
}
}
</script>
</body>
</html>
So yes , 6 months is the maximum they keep the logs. If you are on the Enterprise SKU (which Is unlikely with 120 users) you can export logs to Bigquery indefinably and Query that. https://support.google.com/a/answer/9079365?hl=en If you have something else that is able to ingest the logs you can do that too.
However , I did something for the suspension date as that date is not set in a user field either.
You are going to need 2 processes.
Create a custom schema attribute for your password date option.
Have a process that routinely scrapes the audit logs. Say everyday you look for password changes in the past 24 hours. You then set the value on the custom schema attribute accordingly.
You second process will monitor that custom schema attribute and do your alerting to users.
To start I had to make an assumption. All users that didn't meet existing criteria would have a fixed date set. Moving forward this new process would ensure everything is inline.
This is the flow I created through Google Apps Script.
Someone writes their information in google form
The information is stored into spreadsheet
Invoice is created within spreadsheet with the newest information received
The invoice is turned into PDF format automatically
The newest invoice is attached to the auto sending email
The person receives an auto-email with the invoice attached as soon as they submit the google form
The problem is that, when someone submits the google form, they receive an invoice but what they receive is the invoice from the information one before. This then repeats. When someone submits, the information inside the invoice is from the person one before.
I am a starter at Google Script so I have no idea why this is happening.
This is the code I use to send the auto email. I have minimized the code.
function for_users2() {
var title = "【お問い合わせありがとうございます】";
var name = '名前';
var mail = 'メールアドレス';
var address = "";
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getLastRow();
var column = sheet.getLastColumn();
var range = sheet.getDataRange();
var TIMESTAMP_LABEL = 'タイムスタンプ';
for (var i = 1; i <= column; i++ ) {
var item = range.getCell(1, i).getValue();
var value = range.getCell(row, i).getValue();
if ( item === TIMESTAMP_LABEL ) {
item = 'お問い合わせ日時';
}
if ( item === 'お問い合わせ日時' ) {
value = Utilities.formatDate(value, 'Asia/Tokyo',"YYYY'年'MM'月'dd'日'HH'時'mm'分'ss'秒'");
}
body += "■"+item+"\n";
body += value + "\n\n";
if ( item === name ) {
body = value+" 様\n\n"+body;
}
if ( item === mail ) {
address = value;
}
}
body += body2;
var token = ScriptApp.getOAuthToken();
var pdf = UrlFetchApp.fetch("https://docs.google.com/spreadsheets/d/OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO/export?exportFormat=pdf&format=pdf&size=A4&portrait=true&fitw=true&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=false&fzr=false&gid=00000000000", {headers: {'Authorization': 'Bearer ' + token}}).getBlob().setName('請求書');
GmailApp.sendEmail(
address,
title,
body,
{
attachments: [pdf],
name: 'Automatic Emailer Script'
}
);
}
There is no error. It's just that the invoice attached is from one previous customer.
Thank you to the people who have answered my question. Special thanks to Tanaike who have suggested a workaround where I was able to use as a starter to GAS.
As I used Utilities.sleep(5000), whenever someone submits google form, the invoice produced (PDF format) is updated to the newest info. Since the program I created isn't aimed for very heavy processes, it may be the reason why it worked perfectly fine.
If SpreasheetApp.flush() doesn't seem to be working then you should certainly move to the onFormSubmit - Installable Trigger.
Triggers - Form Submit
This way you can process the exact values from the form and use the same function you are using now. Instead of fetching the last row values, you can fetch the values from the form submission using this.
var name = e.namedValues['Name'][0]; var email = e.namedValues['Email'][0];
I have a custom object in Salesforce called Website_Role__c. This object has a list of people associated with a store with different roles (Owner, Mentor, etc.).
Using JavaScript in a Salesforce button on Account:
The desired behavior is a user clicks the button and a dialog pops up with the list of people in the Website_Role__c for that Account. There would be a checkbox next to each person allowing the user to select them.
We are using eSign (formerly EchoSign). This button is a "Send with eSign" button that will be used to send an agreement to the list of people from Website_Role__c.
This is where I am at now:
/*My Attempt*/
{
!REQUIRESCRIPT("/soap/ajax/19.0/connection.js")
} //adds the proper code for inclusion of AJAX toolkit
var url = parent.location.href; //string for the URL of the current page
var records = {!GETRECORDIDS($ObjectType.Website_Role__c)
}; //grabs the Website Role records for the currently selected store
var updateRecords = []; //array for holding records that this code will ultimately update
if (records[0] == null) { //if the button was clicked but there was no record selected
alert("Please select at least one person to send to."); //alert the user that they didn't make a selection
} else { //otherwise, there was a person selected
for (var a = 0; a < records.length; a++) { //for all records
var update_Website_Role__c = new sforce.SObject("Website_Role__c"); //create a new sObject for storing updated record details
//This is where I get lost. Not sure if this is even the correct approach
}
//??
parent.location.href = url; //refresh the page
}
I would greatly appreciate any help you can provide.
Thank you
Try something like this:
{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
var query = sforce.connection.query("SELECT Owner__c, Mentor__c FROM Website_Role__c WHERE Account__c ='{!Account.Id}'");
var records = query.getArray("records");
alert("Owner is: " + records[0].Owner__c);
This assumes you have a reference field on your Website_Role object that points to the Account.
Check here for some more examples
https://developer.salesforce.com/docs/atlas.en-us.ajax.meta/ajax/sforce_api_ajax_more_samples.htm
I created a button in Salesforce using JavaScript which converts an enquiry (custom object) to a registration (Contact). The button works for myself and any test user I log in as on the same profiles and permissions, however one of my users is report an error when they use the button.
The error is as follows:
'unterminated string constant'
The Code I'm using in the button is as follows:
{!REQUIRESCRIPT('/soap/ajax/27.0/connection.js')}
alert('Migration in progress, this page will refresh once it is complete. Please click ok, Please DO NOT press this button again');
if ('{!Enquiry__c.Surname__c}' != ''){
if ('{!Enquiry__c.Client_if_already_on_the_system__c}' == ''){
var Reg = new sforce.SObject('Contact');
Reg.FirstName = '{!Enquiry__c.First_Name__c}';
Reg.LastName = '{!Enquiry__c.Surname__c}';
Reg.Gender__c = '{!Enquiry__c.Gender__c}';
Reg.MailingStreet = '{!Enquiry__c.Address__c}';
Reg.MailingPostalCode = '{!Enquiry__c.Post_Code__c}';
Reg.MailingCity = '{!Enquiry__c.City_Town__c}';
Reg.MailingState = '{!Enquiry__c.County__c}';
Reg.HomePhone = '{!Enquiry__c.Home_Number__c}';
Reg.MobilePhone = '{!Enquiry__c.Mobile_Number__c}';
Reg.Email = '{!Enquiry__c.E_mail__c}';
Reg.Lastest_Enquiry__c = '{!Enquiry__c.Id}';
result = sforce.connection.create([Reg]);
if (result[0].success == 'true'){
alert('A new Registration with the name - ' + Reg.FirstName + ' ' + Reg.LastName + ' was successfully created, Please DO NOT press this button again as duplication\'s will be created, Your client will be automatically connected to this enquiry');
javascript: document.location.reload(true);
}
}else{
alert('Cannot Migrate to Registration as there is already a Client connected to this Enquiry');
}
}else{
alert('Cannot Migrate to Registration as Surname is blank!');
}
The user has told me they are using IE as a browser, I've tested the button on Chrome, Edge and the most up to date IE. Anyone have any ideas of whats wrong?
what is the type for Reg.FirstName and LastName? Are you using textarea type for these two fields?
Because if user enter any of the name with a carriage return \r or \n alert will fail with the same error and it will be a random based on the input.
I have a form inside my page for user that want to register inside the site. After registration I insert user inside database create an activation key and send an email, until user doesn't click the link inside the email with the activation key he can't login inside the site.
With CasperJS I would like to test this functionality, the fillForm is ok but how can I test the activation key?
I have thought to create an input hidden with the activation key (only if is in TEST mode not i production!) and retrieve this value with getFieldValue function.
Is this the right way to do it or there is a better mode to do?
this is my casperjs test to retrieve activation key after registration (I create an input hidden with the activation code):
view = 'users/registered';
casper
.start(webroot + view)
.then(function() {
__utils__.log("Retrieving data from input activation-key");
activationKey = __utils__.getFieldValue('activation-key');
}).then(function() {
__utils__.log("Activating account with the key " + activationKey);
}).then(function(){
this.evaluate(function() {
__utils__.log("Activating account with the key " + activationKey);
window.location = webroot + 'users/activate/' + activationKey;
});
}).then(function(){
this.echo(this.getCurrentUrl());
});
casper.run(function() {
this.echo('test registeration successful!').exit();
});
casper.viewport(page.width, page.height);
casper.test.done();
I managed to do what i wanted with registration, it could help you : CasperJS- Register on a site and validate the mail sent on Gmail -for both slimer and phantom-
And before i did some scraping with an activation code too, for manual activation (pure JS, no jQuery here, i didn't want to inject JQuery on gmail DOM environment) :
this.waitForSelector("div.msg",function(){
this.test.assertSelectorHasText("a","Activation message");
//var code declared in the main scope
code = this.evaluate(function(){
var strongs = document.getElementsByTagName('strong')
,i
,l = strongs.length
;
for (i = 0; i < l; ++i) {
if(strongs[i].textContent === "activation code:"){
//get back the code in DOM context -> split to get back only what I want
return (strongs[i].parentNode.textContent.split(' ')[2]);
}
}
});
this.echo("code : " + code,"INFO");
});