Telegram Bot Api : multi level Quiz - telegram

I want to develop a telegram Bot with multiple options, for example at first I show 3 buttons : button 1 , button 2 , button 3
and when user click on each, again, I show three other buttons : button 1 , button 2 , button 3
and after step 2, I want to show user first and second button he clicked, for example :
he first click on button 3 and then click on button 1, so, I want to show :
31
how can I know which button at he clicked first ? is there anyway to get chat history from bot ? or I should save his clicks on a database ? or what is your solution ?
*I am using c# and telegram.bot , but just give me a solution, language is not important.

First you can use inline keyboard that gives you the user updates with data. That means you can obtain Ids for any question and when user click you get the question Id.
Using InlineKeyboardMarkup with question key as data.
I suggest you to save a question tree to the database and save current state of each user.
Then when user clicked a button; you get the question key and find it in the tree and ask the next question or find where it comes from (previous questions).
If you want to run any method related to each question you can simply store each question method name in tree and when user arrives fire that method with Reflection.

You should save the chat_id and buttons clicked in a database. Chat history for bots is short lived and may not be reliable for your purpose.

You can use inline buttons. Solution with JavaScript:
var options = {
reply_markup: JSON.stringify({
inline_keyboard: [
[
{text: 'button 1', callback_data: '1'},
{text: 'button 2', callback_data: '2'},
{text: 'button 3', callback_data: '3'},
],
]
})
};
bot.sendMessage(chatId, 'Pick action:', options);
See, you can pass any callback data. So I would save current path in this callback_data property. Format is not important, can be array, string, whatever. But it will represent the stack.
For example, path a2.a1.a3 means that you clicked on button number 2, then on number 1, and then on number 3. And data structure can be similar to this:
{
q: 'Which path you wanna go?',
a1: { ... },
a2: {
value: 'right',
q: 'You're going right. You see the wall, what will you do?',
a1: {
a1: { ... },
a2: { ... }
a3: {
value: 'go back',
q: 'You\'re going back and you see the tiger, what will you do?',
a1: { ... },
a2: { ... }
}
},
a2: { ... },
a3: { ... }
},
a3: { ... }
}
And it's also easy to go pack. Just pop one value from the stack and you're on previous menu.

Related

SAPUI5 OPA5 How to trigger a select event

Below a typical action to test if a sap.m.Select contains an item with the name xyz and then select it.
success: function(oSelect) {
var oItems = oSelect.getItems();
$.each(oItems, function(i,v) {
if(oItems[i].getText() === "TestItemNameILikeToSelect") {
oTestOpa5TestItem = oItems[i];
}
});
if(oTestOpa5TestItem !== null) {
oSelect.setSelectedKey(oTestOpa5TestItem.getKey());
oTestOpa5TestItem.$().trigger("tap");
}
},
When I start the test run it does correctly select the proper item from the list and sets it visibly in the browser, but it does not trigger the attached event that is behind (e.g. change="onListItemChanged").
My application works fine, but I don't find a way to create a working test for it.
Thanks in advance
OPA5 has an 'Action' interface and two default implementations e.g. 'EnterText' and 'Press'. The recommended usage is to define an action block on the waitFor() options like this:
When.waitFor({
id: "myButton",
actions: new Press()
});
What you use is the 'old way' but it has some shortcomings:
success block is not synchronized with XHR requests but action is.
Sending a click/tap event to a control could require selecting some internal element. Imagine a click to nav container - there are several places you could click actually. Actions handle those details and define a standard behavior you could depend on.
It is better to encapsulate your selection logic inside a matchers block and even abstract it to a custom matcher. This way your success block will be cleaner and you could reuse the matcher in several places in your test.
OPA5 Actions
Have a look at the official UI5 Demo Kit, under samples > OPA5 > Code: Simulating user interactions on UI5 controls with OPA5, You will be able to find numerous examples of OPA 5 testing regarding general user interactions. In your case for the select:
opaTest("Should select an item in a sap.m.Select", function(Given, When, Then) {
When.waitFor({
id: "mySelect",
actions: new Press(),
success: function(oSelect) {
this.waitFor({
controlType: "sap.ui.core.Item",
matchers: [
new Ancestor(oSelect),
new Properties({ key: "Germany"})
],
actions: new Press(),
success: function() {
Opa5.assert.strictEqual(oSelect.getSelectedKey(), "Germany", "Selected Germany");
},
errorMessage: "Cannot select Germany from mySelect"
});
},
errorMessage: "Could not find mySelect"
});
});
https://sapui5.hana.ondemand.com/#/entity/sap.ui.test.Opa5/sample/sap.ui.core.sample.OpaAction/code/Opa.js

Protractor e2e test fullcalendar drag & drop

I need to simulate a drag & drop on fullcalendar in the week view with protractor. I found something with coordinates but I'd like a "no browser window dependent solution"... ther's also no way out on finding the exact starting cell in the week view by class or id ...or at least, I couldn't figure how to select a single cell of a row of a day because, using the Chrome's item selector, it seems every row has the same class fc-widget-content and cells are not "selectable" elements.
Are there any other chances?
maybe this is a little bit helpful (also very later ;). I also want to test my app with FullCalendar, but I'm using Cypress (similar to Protractor).
We plan items from an external list and assign it to a resource on a certain day/time in the FullCalendar (we use the scheduler plugin).
I found out that the drag and drop event is somehow intercepted by code, enriching it with for example properties of the event (like date, title and others). How I enriched this data is in the Cypress trigger('drop', data) command. Data is the evenData that is set by the Draggable class:
// Executed on the external list items, where every item we want to plan has class `.fc-event`.
this.draggableContainer = new Draggable(this.containerEl.nativeElement, {
itemSelector: '.fc-event',
eventData(eventEl) {
const id = eventEl.dataset.id;
return {
duration,
id: currentWorkItem.id,
title: currentWorkItem.description,
extendedProps: {
duration,
customRender: true,
data: currentWorkItem,
},
};
}
Then, in your test file (Cypress)
const eventData = {
date: new Date(),
dateStr: new Date().toISOString(),
draggedEl: {
dataset: {
notificationId: '123',
priority: '0',
title: 'Test',
},
},
jsEvent: null,
resource: {
id: '123',
},
event: null,
oldEvent: null,
};
cy.get('.fc-event') // selector for the external event I want to drag in the calendar
.trigger('dragstart')
.get('.fc-time-grid table tr[data-time="07:00:00"] td.fc-widget-content:nth-child(2)') // selector for where I want to drop the event.
.trigger('drop', eventData) // this will fire the eventDrop event
So, .trigger('drop', eventData) will fill the eventDrop info. It is not exactly the same as doing it manually, but works for me.
Caveats:
I haven't found a way to plan it on another resource (we use the resource scheduling plugin of FullCalendar.io). It does not matter that much, because you can specify it in the evenData (resource: { id: 'my-resource-id' } }.
No visual feedback because the drag mirror is not shown. Not a big problem during e2e testing, but it is a bit of a blackbox now. Maybe this is fixable

How to invoke search field in OPA5 tests

My view contains a sap.m.SearchField.
How can I invoke the search in that field? The usual trigger("tap") approach does not seem to work.
After some debugging I found out that a combination of the pseudo events saptouchstart and saptouchend triggered in the magnifying glass icon within the search field works.
return this.waitFor({
id: "mySearchField",
viewName: sViewName,
success: function (control) {
var event, searchIcon;
event = jQuery.Event( "saptouchend" );
event.originalEvent = event; // would otherwise cause NPE at some point in SAP code
searchIcon = control.$().find("div[id*=mySearchField-search]");
searchIcon.trigger("saptouchstart").trigger(event);
},
errorMessage: "Search field not found"
});
This can also be done with the following one-liner (source):
$(theSearchField).trigger("onSearch");
But maybe this is only possible with a more recent version of UI5 than the one used by you.
Another solution approach would be to use an EnterText action, which not only enters the search term ("foobar" in the following example), but also triggers the search afterwards:
this.waitFor({
id: "mySearchField",
actions: [ new sap.ui.test.actions.EnterText({ text: "foobar" }) ]
});

Knockout js how to find a checked radio button in a radio button list

I'm having a list of contact details. User can select, add and remove those contact details.(Please see the fiddle JSfiddle ) whenever the user click an add button, a new contact model item will be add to the DOM.
var ContactModel = {
ContactData : [
{ 'ContactKey': 12323, 'Ref': 'Reference-Marsh', 'ContactName': 'Marsh Global' },
{ 'ContactKey': 44234, 'Ref': 'Reference-AON', 'ContactName': 'AON Co' },
{ 'ContactKey': 65343, 'Ref': 'Reference-Europ', 'ContactName': 'Europ Ltd' },
{ 'ContactKey': 78555, 'Ref': 'Reference-ECB', 'ContactName': 'ECB Tradings' },
{ 'ContactKey': 24242, 'Ref': 'Reference-Jersey', 'ContactName': 'New Jersey Inc' }
],
Items: ko.observableArray(),
MainContacts : ko.observable(),
AddItem: function () {
ContactModel.Items.push(new Contact([]));
},
Remove: function (line) {
ContactModel.Items.remove(line);
}
}
please see the rest of the code in the fiddle
when the user click a radio button, that selected radio button line data considered as main contact.I have to save all of the line items data. this is because when the user revisited the page,I'll bring all the line item with selected main contact.
when the user change the select list, the selected item object having the properties of ContactKey,Ref and ContactName according to that the other observable are updated.
but if the radio button is selected only the main contact will be updated. I've achieved that using pure jquery. but the value radio button value binding bit confusing for me. can any one help me to sort that issue.
If i understood your intentions right, my modifications to the fiddle shall present you a solution, basically:
I gave names to the radio buttons so that they are exclusive.
I moved logic from the view to the ischecked observable that is now a computed.
I changed the binding logic for the main contact.
Some small tweeks that can be seen in the fiddle.
Here's the fiddle: http://jsfiddle.net/QmQy9/4/
If theres something different from what you intended, just let me know.
Regards.

How to add a row hyperlink for an extJS Grid?

Can someone please throw some light on how to go about rendering an hyperlink in the cells of a particular column in ExtJS?
I have tried binding the column to a render function in my JS, from which I send back the html:
SELECT
However, with this, the problem is that, once I hit the controller through the link, the navigation is successful, but subsequent navigations to the data-grid show up only empty records.
The records get fetched from the DB successfully through the Spring MVC controller, I have checked.
Please note that this happens only once I use the row hyperlink in the extJS grid to navigate away from the grid. If I come to the grid, and navigate elsewhere and again come back to the grid, the data is displayed fine.
The problem only occurs in case of navigating away from the grid, using the hyperlink rendered in one/any of the cells.
Thanks for your help!
This is for ExtJS 4 and 5.
Use a renderer to make the contents look like a link:
renderer: function (value) {
return ''+value+'';
}
Then use the undocumented, dynamically generated View event cellclick to process the click:
viewConfig: {
listeners: {
cellclick: function (view, cell, cellIndex, record, row, rowIndex, e) {
var linkClicked = (e.target.tagName == 'A');
var clickedDataIndex =
view.panel.headerCt.getHeaderAtIndex(cellIndex).dataIndex;
if (linkClicked && clickedDataIndex == '...') {
alert(record.get('id'));
}
}
}
}
Try something like this:
Ext.define('Names', {
extend: 'Ext.data.Model',
fields: [
{ type: 'string', name: 'Id' },
{ type: 'string', name: 'Link' },
{ type: 'string', name: 'Name' }
]
});
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columns: [
{
text: 'Id',
dataIndex: 'Id'
},
{
text: 'Name',
dataIndex: 'Name',
renderer: function (val, meta, record) {
return '' + val + '';
}
}
...
...
...
However my thanks to - ExtJS Data Grid Column renderer to have multiple values
Instead of using an anchor tag, I would probably use plain cell content styled to look like an anchor (using basic CSS) and handle the cellclick event of the GridPanel to handle the action. This avoids dealing with the anchor's default click behavior reloading the page (which is what I'm assuming is happening).
I created a renderer so it looked like you were clicking on it.
aRenderer: function (val, metaData, record, rowIndex, colIndex, store){
// Using CellClick to invoke
return "<a>View</a>";
},
But I used a cell event to manage the click.
cellclick: {
fn: function (o, idx, column, e) {
if (column == 1) // Doesn't prevent the user from moving the column
{
var store = o.getStore();
var record = store.getAt(idx);
// Do work
}
}
}
For these purposes I use CellActions or RowActions plugin depending on what I actually need and handle cell click through it.
If you want something that looks like an anchor, use <span> instead and do what #bmoeskau suggested.
You can use 'renderer' function to include any HTML you want into cell.
Thanks guys for your response.
AFter debugging the extJS-all.js script, I found the issue to be on the server side.
In my Spring MVC controller, I was setting the model to the session, which in the use-case I mentioned earlier, used to reset the "totalProperty" of Ext.data.XmlStore to 0, and hence subsequent hits to the grid, used to display empty records.
This is because, ext-JS grid, checks the "totalProperty" value, before it even iterates through the records from the dataStore. In my case, the dataStore had data, but the size was reset to null, and hence the issue showed up.
Thanks to all again for your inputs!

Resources