using a telegraph button I coded with nodejs, I want it to send the names available in the json randomly to the user whenever I press the button. How can I do that?
You could shuffle your json object whenever your button is pressed. And the previous message gets deleted.
This would be done like this:
bot.action('callback_data', (ctx) => {
ctx.deleteMessage()
var json
// Shuffle json
ctx.telegram.sendMessage(ctx.chat.id, `${json}`, {
reply_markup: {
inline_keyboard: [
[{text: "Settle", callback_data: "callback_data"}]
]
}
})
})
Related
A Meteor web app being used by a logged in user "merchant" who needs to create a link and sms/email it to his customer. The link opens a form. The customer fills up the form and submits it so that the data gets inserted with a property merchantId, since many merchants can send to many customers.
This single page app is not using a Router but able to sms/email. How can linking a form between a merchant and a customer be accomplished elegantly so that the data from the correct customer gets "linked" to the correct merchant? Thanks
Merchant Part
You can trigger after a successful send of the email/sms a meteor method, that stores a record of the sent email/sms in a collection (in this example named Record). This could be the schema for it:
Record Collection Schema (Server/Client)
{
merchantId:String, // the id of the sender
customer:String, //id or name or address or phone num of receiver
opened:Boolean, //when the link is opened can be set to true
link:String, // the link to be send,
type:Number, //0=sms, 1=email,
expires:Date, //in case the link is not opened
}
You can for example create a Meteor method to insert the record after send:
Insert Record (Server)
Meteor.methods({
insertRecord:function(recordData) {
//... check recordData by schmema and permissions here
return Records.insert(recordData);
}
})
Sending the Email/SMS
So the merchant part of the app sends the link via sms/email and calls the insertRecord method to store the record of the saved .
Save Record (Client or Server)
const callback=function(err, res) {
if (res) { // assume your sent was successful here
Meteor.call("insertRecord", {
//... your record credentials
});
}
}
// a little bit of pseudocode
if (sms)
sms.send(form, callback);
else
email.send(form, callback);
Customer Part
When the customer opens the link it triggers a templatethat will render your form. You can initially run a meteor method to check the Record collection for a document that matches the link url.
Get Record by Url Method (Server)
Meteor.methods({
getRecordByUrl:function(url) {
//... do your input checks here
return Records.findOne({link:url});
},
});
Template for Form (Client)
Template.customerForm.onCreated(function(){
const instance = this;
instance.state = new ReactiveDict();
instance.state.set("record", null);
instance.autorun(function(){
// if no record loaded yet
if (!instance.state.get("record")) {
Meteor.call("getRecordByUrl", window.location.href, function(err, res) {
if (err || !res) {
//...handle err
}
this.state.set("record", res);
}.bind(instance));
}
});
});
Template.customerForm.helpers({
getRecord() {
return Template.instance().state.get("record");
},
getMerchantId() {
const record = Template.instance().state.get("record");
return record.merchantId;
}
});
You can then use this document to add the merchantId to the form either as a hidden input or via html data attribute.
{{#if getRecord}}
<form id="...">
<input type="hidden" name="merchantId" value="{{getMerchantId}}" />
<!-- other inputs here -->
</form>
{{/if}}
The examples can of course be optimized but I think this way it clearer to understand.
I use a Cloud Function to generate a short unique URL on a record on the 'onWrite' event, and save it. This works well, but when I save a record from my Ember app using EmberFire, I do get a model back as an argument to a callback, but the URL of this model is undefined. Is there a way to return this back to the client? Or do I need to query the record to get the generated URL?
This is how my Cloud Function code looks:
exports.generateUrl = functions.database.ref('/tournaments/{tid}')
.onWrite(event => {
if (event.data.previous.exists()) {
return;
}
if (!event.data.exists()) {
return;
}
const url = shortid.generate();
return event.data.ref.update({ url });
});
Here is my component that saves data through form submission. I'm using an add-on called ember-changeset to handle some validations, but this shouldn't be related to the issue.
export default Ember.Component.extend({
submit(e) {
e.preventDefault();
let snapshot = this.changeset.snapshot();
return this.changeset
.cast(Object.keys(this.get('schema')))
.validate()
.then(() => {
if (this.changeset.get('isValid')) {
return this.changeset
.save()
.then((result) => {
// Here, result.get('url') is undefined.
})
}
})
}
});
If you have a function that writes new data back to a location in the database after a write, you'll have to keep listening to that location on the client in order to get that data back. Don't use a one-time read (once()), use a persistent listener (on()), and in that listener, make sure you're getting the URL or whatever you expect to be generated by the function. Then remove that listener if you don't need it any more.
(Sorry, I don't know Ember or what abstractions it provides around Realtime Database - I'm giving you the plain JavaScript API methods you'd use on a reference.)
This Meteor client public method needs to re run when the Meteor.user().profile.propA changes which is does fine, but it also runs when profile.propB changes or added. How can I stop it from re running when any other child property of profile has changed or added but only for profile.propA? Thanks
myListener: () => {
Tracker.autorun(() => {
if (Meteor.userId()) {
const indexes = Meteor.user().profile.propA;
if (!indexes || indexes.length <= 0) return;
dict.set('myStuff', indexes);
console.log('auto has run');
}
});
},
on the mongodb terminal:
db.users.update({'_id':'123abc'}, {$set: {'profile.propB':'B'}})
triggers the autorun. even though the reactive data source is Meteor.user().profile.propA;
Mongo.Collection.findOne allows you to specify which fields are retrieved from the local database using the fields option. Only changes to the fields specified there will trigger the autorun again.
Since Meteor.user() is just a shorthand for Meteor.users.findOne(Meteor.userId()), you can do the following to get updates for propA only:
const indexes = Meteor.users.findOne(Meteor.userId(), {
fields: {
'profile.propA': 1
}
});
Note that indexes will only contain profile.propA and the document's _id. If you need more data from the user document but still want to receive reactive updates separately, you have to fetch that data in a second autorun.
I have global array that works just fine and stores the URL's of the chosen images from the user after i click submit in the form.
the problem is when i want to submit another form, the global array will still have the URL's of the previous submission.
what i want to do is to create an array for every user to store his URL's, one he click submit, the array will be dropped or deleted. so if there were multiple users using the same function, every one of them will have his own array to store his URL's
How do i do this?
this is what i have tried but when i click on submit on the form page, nothing happens
first, this is the method that returns the url of the chosen image by the user, the method exists in both folder (both/file.js)
storeUrlInDatabaseSS: function( url ) {
check( url, String );
Modules.both.checkUrlValidity( url );
try {
return url;
} catch( exception ) {
return exception;
}
}
then i created the session variables in the client side (client/file.js)
Session.set("screenshots", []);
Session.set("i", 0);
var screenshots = Session.get("screenshots");
var i = Session.get("i");
and here i store the url in the array
let _addUrlToDatabaseSS = ( url ) => {
screenshots[i++] = url;
Session.set("screenshots", screenshots);
};
and am using Meteor Collection Hook Package
and i added these two lines of code which should be excited after the user press submit, they exist inside "client/files.js" directory
Products.before.insert(function (userId, doc) {
doc.screenShots = Session.get("screenshots");
});
now whenever i click submit nothing happens, i think the problem is because nothing is actually stored inside the screenShots attribute in the collection here
screenShots: {
type: [String]
},
when i set the screenShots attribute to an empty array by default like the code below, the submit button works
screenShots: {
type: [String],
autoValue: function() {
return [];
}
},
I tried to use the other way of using AutoForm.hooks
AutoForm.hooks({
submitPostForm: {
before: {
insert: function(doc) {
doc.$set.screenShots = Session.get("screenshots");
}
}
}
});
the is my form in the .html file
{{> quickForm collection="Products" id="submitPostForm"
type="method" meteormethod="submitPost" omitFields="createdAt, previewImage, screenShots, sourceCode, userID"}}
and this is the method triggered once the user submit the form, it exist in the server side.
submitPost: function (app) {
// Console.log('new App:', app);
check(app, {
title: String,
description: String,
category: String,
price: Number
});
Products.insert(app);
}
for some reason my before hook isn't working and i can't see why!
what am i doing wrong here?
One of the ways to create a global array per user is to use Session. This way it is also possible to persist the data across the app (only client-side).
Simple way to use Session is thus:
Create an array in Session called url_list:
Session.set("url_list", []);
Retrieve the array from Session:
var url_list = Session.get("url_list");
Make changes to url_list:
url_list.push(someData);
Store url_list in the Session again:
Session.set("url_list", url_list);
Note: Session can only be used on client-side and all related code should be on the client-side.
More about Session.
PERSISTING DATA TO SERVER-SIDE:
The best way to persist the url_list to the server, would be to insert a new document into the database collection containing the Session data.
insertToDB = function() {
var url_list = Session.get('url_list');
Products.insert({
'url_list': url_list
});
Session.set('url_list', []); // To empty the client-side list
}
Is there a way to update a part of the URL reactively without using FlowRouter.go() while using React and react-layout?
I want to change the value in the document that is used to get the document from the DB. For example, if I have a route like ~/users/:username and update the username field in the document, I then have to user FlowRouter.go('profile', {data}) to direct the user to that new URL. The "old" route is gone.
Below is the working version I have, but there are two issues:
I have to use FlowRouter.go(), which is actually a full page refresh (and going back would be a 404).
I still get errors in the console because for a brief moment the reactive data for the component is actually wrong.
Relevant parts of the component are like this:
...
mixins: [ReactMeteorData],
getMeteorData() {
let data = {};
let users = Meteor.subscribe('user', {this.props.username});
if (user.ready())
data.user = user;
return data;
}
...
updateName(username) {
Users.update({_id:this.data.user._id}, {$set:{username}}, null, (e,r) => {
if (!e)
FlowRouter.go('profile', {username});
});
},
...
The route is like this:
FlowRouter.route('/users/:username', {
name: 'profile',
action(params) {
ReactLayout.render(Main, {content: <UserProfile {...params} />});
}
});
The errors I get in the console are:
Exception from Tracker recompute function:
and
TypeError: Cannot read property '_id' of undefined