Refactored jail loading + commands/responses
This commit is contained in:
parent
91a0d40ceb
commit
e50d56a4d0
|
@ -12,8 +12,8 @@
|
|||
(def root-el (r/as-element [reloader]))
|
||||
|
||||
(figwheel/watch-and-reload
|
||||
:websocket-url "ws://10.0.1.15:3449/figwheel-ws"
|
||||
:websocket-url "ws://localhost:3449/figwheel-ws"
|
||||
:heads-up-display false
|
||||
:jsload-callback #(swap! cnt inc))
|
||||
|
||||
(rr/enable-re-frisk-remote! {:host "localhost:4567" :on-init core/init :pre-send (fn [db] (update db :chats #(into {} %)))})
|
||||
(rr/enable-re-frisk-remote! {:host "localhost:4567" :on-init core/init :pre-send (fn [db] (update db :chats #(into {} %)))})
|
||||
|
|
|
@ -6,21 +6,8 @@
|
|||
"en": "Browse"
|
||||
},
|
||||
"dapp?": true,
|
||||
"bot-url": "local://browse-bot",
|
||||
"global-command": {
|
||||
"description":"Launch the browser",
|
||||
"color": "#ffa500",
|
||||
"name": "global",
|
||||
"params": [{
|
||||
"name": "url",
|
||||
"placeholder":"URL",
|
||||
"type":"text"
|
||||
}],
|
||||
"title":"Browser",
|
||||
"registered-only":true,
|
||||
"has-handler": false,
|
||||
"fullscreen":true
|
||||
},
|
||||
"hide-contact?": true,
|
||||
"bot-url": "local://browse-bot",
|
||||
"unremovable?": true
|
||||
},
|
||||
|
||||
|
@ -32,30 +19,19 @@
|
|||
"ru": "Печкин"
|
||||
},
|
||||
"dapp?": true,
|
||||
"mixable?": true,
|
||||
"hide-contact?": true,
|
||||
"bot-url": "local://mailman-bot"
|
||||
},
|
||||
|
||||
"transactor-group":
|
||||
"transactor":
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"en": "Transactor"
|
||||
},
|
||||
"dapp?": true,
|
||||
"mixable?": true,
|
||||
"bot-url": "local://transactor-group-bot"
|
||||
},
|
||||
|
||||
"transactor-personal":
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"en": "Transactor"
|
||||
},
|
||||
"dapp?": true,
|
||||
"mixable?": true,
|
||||
"bot-url": "local://transactor-personal-bot"
|
||||
"hide-contact?": true,
|
||||
"bot-url": "local://transactor-bot"
|
||||
},
|
||||
|
||||
"demo-bot":
|
||||
|
|
|
@ -36,7 +36,7 @@ function browse(params, context) {
|
|||
status.command({
|
||||
name: "browse",
|
||||
title: I18n.t('browse_title'),
|
||||
scope: ["global", "registered-only", "group-chats", "personal-chats", "can-use-for-dapps"],
|
||||
scope: ["global", "personal-chats", "group-chats", "public-chats", "registered", "dapps", "humans"],
|
||||
description: I18n.t('browse_description'),
|
||||
color: "#ffa500",
|
||||
fullscreen: true,
|
||||
|
|
|
@ -458,6 +458,7 @@ var phoneConfig = {
|
|||
icon: "phone_white",
|
||||
color: "#5bb2a2",
|
||||
title: I18n.t('phone_title'),
|
||||
scope: ["personal-chats", "registered", "dapps"],
|
||||
description: I18n.t('phone_description'),
|
||||
sequentialParams: true,
|
||||
validator: function (params) {
|
||||
|
@ -489,6 +490,7 @@ var phoneConfig = {
|
|||
};
|
||||
}
|
||||
};
|
||||
status.command(phoneConfig);
|
||||
status.response(phoneConfig);
|
||||
|
||||
var ropstenNetworkId = 3;
|
||||
|
@ -556,7 +558,7 @@ var faucetCommandConfig ={
|
|||
title: I18n.t('faucet_title'),
|
||||
description: I18n.t('faucet_description'),
|
||||
color: "#7099e6",
|
||||
scope: ["registered-only", "group-chats", "personal-chats", "can-use-for-dapps"],
|
||||
scope: ["personal-chats", "registered", "dapps"],
|
||||
params: [{
|
||||
name: "url",
|
||||
type: status.types.TEXT,
|
||||
|
@ -632,7 +634,7 @@ status.command({
|
|||
title: I18n.t('debug_mode_title'),
|
||||
description: I18n.t('debug_mode_description'),
|
||||
color: "#7099e6",
|
||||
scope: ["registered-only", "group-chats", "personal-chats", "can-use-for-dapps"],
|
||||
scope: ["personal-chats", "registered", "dapps"],
|
||||
params: [{
|
||||
name: "mode",
|
||||
suggestions: debugSuggestions,
|
||||
|
@ -659,6 +661,7 @@ status.command({
|
|||
status.response({
|
||||
name: "confirmation-code",
|
||||
color: "#7099e6",
|
||||
scope: ["personal-chats", "registered", "dapps"],
|
||||
description: I18n.t('confirm_description'),
|
||||
sequentialParams: true,
|
||||
params: [{
|
||||
|
@ -696,6 +699,7 @@ status.response({
|
|||
status.response({
|
||||
name: "password",
|
||||
color: "#7099e6",
|
||||
scope: ["personal-chats", "anonymous", "dapps"],
|
||||
description: I18n.t('password_description'),
|
||||
icon: "lock_white",
|
||||
sequentialParams: true,
|
||||
|
@ -754,6 +758,7 @@ status.response({
|
|||
|
||||
status.response({
|
||||
name: "grant-permissions",
|
||||
scope: ["personal-chats", "anonymous", "registered", "dapps"],
|
||||
color: "#7099e6",
|
||||
description: "Grant permissions",
|
||||
icon: "lock_white",
|
||||
|
|
|
@ -32,7 +32,7 @@ function locationsSuggestions (params) {
|
|||
status.command({
|
||||
name: "location",
|
||||
title: I18n.t('location_title'),
|
||||
scope: ["registered-only", "group-chats", "personal-chats"],
|
||||
scope: ["global", "personal-chats", "group-chats", "public-chats", "registered", "humans"],
|
||||
description: I18n.t('location_description'),
|
||||
sequentialParams: true,
|
||||
hideSendButton: true,
|
||||
|
@ -96,4 +96,4 @@ status.command({
|
|||
)
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// Send command/response
|
||||
|
||||
function calculateFee(n, tx) {
|
||||
var estimatedGas = 21000;
|
||||
if (tx !== null) {
|
||||
|
@ -52,26 +54,30 @@ status.defineSubscription(
|
|||
function(params) {
|
||||
return getFeeExplanation(params.value);
|
||||
}
|
||||
)
|
||||
|
||||
function amountParameterBox(params, context) {
|
||||
);
|
||||
|
||||
function amountParameterBox(groupChat, params, context) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
|
||||
var contactAddress;
|
||||
if (params["bot-db"]["public"] && params["bot-db"]["public"]["recipient"]) {
|
||||
contactAddress = params["bot-db"]["public"]["recipient"]["address"];
|
||||
if (groupChat) {
|
||||
if (params["bot-db"]["public"] && params["bot-db"]["public"]["recipient"]) {
|
||||
contactAddress = params["bot-db"]["public"]["recipient"]["address"];
|
||||
} else {
|
||||
contactAddress = null;
|
||||
}
|
||||
} else {
|
||||
contactAddress = null;
|
||||
contactAddress = context.to;
|
||||
}
|
||||
|
||||
|
||||
var txData;
|
||||
var amount;
|
||||
|
||||
var amountIndex = groupChat ? 1 : 0;
|
||||
|
||||
try {
|
||||
amount = params.args[1] || "0";
|
||||
amount = params.args[amountIndex];
|
||||
txData = {
|
||||
to: contactAddress,
|
||||
value: web3.toWei(amount) || 0
|
||||
|
@ -82,7 +88,7 @@ function amountParameterBox(params, context) {
|
|||
to: contactAddress,
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var sliderValue = params["bot-db"]["sliderValue"] || 0;
|
||||
|
||||
|
@ -104,7 +110,7 @@ function amountParameterBox(params, context) {
|
|||
sliderValue: sliderValue
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
title: I18n.t('send_title'),
|
||||
showBack: true,
|
||||
|
@ -275,43 +281,48 @@ function amountParameterBox(params, context) {
|
|||
)]
|
||||
)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var paramsSend = [
|
||||
{
|
||||
name: "recipient",
|
||||
type: status.types.TEXT,
|
||||
suggestions: function (params) {
|
||||
return {
|
||||
title: I18n.t('send_title'),
|
||||
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
var recipientSendParam = {
|
||||
name: "recipient",
|
||||
type: status.types.TEXT,
|
||||
suggestions: function (params) {
|
||||
return {
|
||||
title: I18n.t('send_title'),
|
||||
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function amountSendParam(groupChat) {
|
||||
return {
|
||||
name: "amount",
|
||||
type: status.types.NUMBER,
|
||||
suggestions: amountParameterBox
|
||||
}
|
||||
];
|
||||
suggestions: amountParameterBox.bind(this, groupChat)
|
||||
};
|
||||
}
|
||||
|
||||
function validateSend(params, context) {
|
||||
var paramsPersonalSend = [amountSendParam(false)];
|
||||
var paramsGroupSend = [recipientSendParam, amountSendParam(true)];
|
||||
|
||||
function validateSend(validateRecipient, params, context) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
|
||||
if (!params["bot-db"]["public"]
|
||||
|| !params["bot-db"]["public"]["recipient"]
|
||||
|| !params["bot-db"]["public"]["recipient"]["address"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
"Wrong address",
|
||||
"Recipient address must be specified"
|
||||
)
|
||||
};
|
||||
if (validateRecipient) {
|
||||
if (!params["bot-db"]["public"]
|
||||
|| !params["bot-db"]["public"]["recipient"]
|
||||
|| !params["bot-db"]["public"]["recipient"]["address"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
"Wrong address",
|
||||
"Recipient address must be specified"
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!params["amount"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
|
@ -369,10 +380,11 @@ function validateSend(params, context) {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
var fee = calculateFee(
|
||||
params["bot-db"]["sliderValue"],
|
||||
{
|
||||
to: params["bot-db"]["public"]["recipient"]["address"],
|
||||
to: context.to,
|
||||
value: val
|
||||
}
|
||||
);
|
||||
|
@ -389,16 +401,21 @@ function validateSend(params, context) {
|
|||
}
|
||||
}
|
||||
|
||||
function handleSend(params, context) {
|
||||
function handleSend(groupChat, params, context) {
|
||||
var val = web3.toWei(params["amount"].replace(",", "."), "ether");
|
||||
|
||||
var gasPrice = calculateGasPrice(params["bot-db"]["sliderValue"]);
|
||||
var data = {
|
||||
from: context.from,
|
||||
to: params["bot-db"]["public"]["recipient"]["address"],
|
||||
from: context.from,
|
||||
value: val
|
||||
};
|
||||
|
||||
if (groupChat) {
|
||||
data.to = params["bot-db"]["public"]["recipient"]["address"];
|
||||
} else {
|
||||
data.to = context.to;
|
||||
}
|
||||
|
||||
if (gasPrice) {
|
||||
data.gasPrice = gasPrice;
|
||||
}
|
||||
|
@ -417,7 +434,7 @@ function handleSend(params, context) {
|
|||
// async handler, so we don't return anything immediately
|
||||
}
|
||||
|
||||
function previewSend(params, context) {
|
||||
function previewSend(showRecipient, params, context) {
|
||||
var amountStyle = {
|
||||
fontSize: 36,
|
||||
color: "#000000",
|
||||
|
@ -461,7 +478,7 @@ function previewSend(params, context) {
|
|||
)]
|
||||
);
|
||||
|
||||
var firstRow = status.components.view(
|
||||
var amountRow = status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "row",
|
||||
|
@ -473,12 +490,14 @@ function previewSend(params, context) {
|
|||
[amount, currency]
|
||||
);
|
||||
|
||||
var markup;
|
||||
if (params["bot-db"]
|
||||
var markup = [amountRow];
|
||||
|
||||
if (showRecipient
|
||||
&& params["bot-db"]
|
||||
&& params["bot-db"]["public"]
|
||||
&& params["bot-db"]["public"]["recipient"]
|
||||
&& context["chat"]["group-chat"] === true) {
|
||||
var secondRow = status.components.text(
|
||||
var recipientRow = status.components.text(
|
||||
{
|
||||
style: {
|
||||
color: "#9199a0",
|
||||
|
@ -488,11 +507,9 @@ function previewSend(params, context) {
|
|||
},
|
||||
I18n.t('send_sending_to') + " " + params["bot-db"]["public"]["recipient"]["name"]
|
||||
);
|
||||
markup = [firstRow, secondRow];
|
||||
} else {
|
||||
markup = [firstRow];
|
||||
markup.push(recipientRow);
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
markup: status.components.view(
|
||||
{
|
||||
|
@ -516,124 +533,157 @@ function shortPreviewSend(params, context) {
|
|||
};
|
||||
}
|
||||
|
||||
var send = {
|
||||
var personalSend = {
|
||||
name: "send",
|
||||
scope: ["group-chats"],
|
||||
scope: ["global", "personal-chats", "registered", "humans"],
|
||||
icon: "money_white",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('send_title'),
|
||||
description: I18n.t('send_description'),
|
||||
params: paramsSend,
|
||||
validator: validateSend,
|
||||
handler: handleSend,
|
||||
params: paramsPersonalSend,
|
||||
validator: validateSend.bind(this, false),
|
||||
handler: handleSend.bind(this, false),
|
||||
asyncHandler: true,
|
||||
preview: previewSend,
|
||||
preview: previewSend.bind(this, false),
|
||||
shortPreview: shortPreviewSend
|
||||
};
|
||||
|
||||
status.command(send);
|
||||
status.response(send);
|
||||
|
||||
var paramsRequest = [
|
||||
{
|
||||
name: "recipient",
|
||||
type: status.types.TEXT,
|
||||
suggestions: function (params) {
|
||||
return {
|
||||
title: I18n.t('request_title'),
|
||||
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "amount",
|
||||
type: status.types.NUMBER
|
||||
}
|
||||
];
|
||||
|
||||
status.command({
|
||||
name: "request",
|
||||
scope: ["group-chats"],
|
||||
var groupSend = {
|
||||
name: "send",
|
||||
scope: ["global", "group-chats", "registered", "humans"],
|
||||
icon: "money_white",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('request_title'),
|
||||
description: I18n.t('request_description'),
|
||||
params: paramsRequest,
|
||||
handler: function (params, context) {
|
||||
var val = params["amount"].replace(",", ".");
|
||||
title: I18n.t('send_title'),
|
||||
description: I18n.t('send_description'),
|
||||
params: paramsGroupSend,
|
||||
validator: validateSend.bind(this, true),
|
||||
handler: handleSend.bind(this, true),
|
||||
asyncHandler: true,
|
||||
preview: previewSend.bind(this, true),
|
||||
shortPreview: shortPreviewSend
|
||||
};
|
||||
|
||||
status.command(personalSend);
|
||||
status.response(personalSend);
|
||||
|
||||
status.command(groupSend);
|
||||
status.response(groupSend);
|
||||
|
||||
// Request command
|
||||
|
||||
var recipientRequestParam = {
|
||||
name: "recipient",
|
||||
type: status.types.TEXT,
|
||||
suggestions: function (params) {
|
||||
return {
|
||||
event: "request",
|
||||
request: {
|
||||
command: "send",
|
||||
params: {
|
||||
recipient: context["current-account"]["name"],
|
||||
amount: val
|
||||
},
|
||||
prefill: [context["current-account"]["name"], val],
|
||||
prefillBotDb: {
|
||||
public: {
|
||||
recipient: context["current-account"]
|
||||
}
|
||||
title: I18n.t('request_title'),
|
||||
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var amountRequestParam = {
|
||||
name: "amount",
|
||||
type: status.types.NUMBER
|
||||
};
|
||||
|
||||
var paramsPersonalRequest = [amountRequestParam];
|
||||
var paramsGroupRequest = [recipientRequestParam, amountRequestParam];
|
||||
|
||||
function handlePersonalRequest(params, context) {
|
||||
var val = params["amount"].replace(",", ".");
|
||||
|
||||
return {
|
||||
event: "request",
|
||||
request: {
|
||||
command: "send",
|
||||
params: {
|
||||
amount: val
|
||||
},
|
||||
prefill: [val]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function handleGroupRequest(params, context) {
|
||||
var val = params["amount"].replace(",", ".");
|
||||
|
||||
return {
|
||||
event: "request",
|
||||
request: {
|
||||
command: "send",
|
||||
params: {
|
||||
recipient: context["current-account"]["name"],
|
||||
amount: val
|
||||
},
|
||||
prefill: [context["current-account"]["name"], val],
|
||||
prefillBotDb: {
|
||||
public: {
|
||||
recipient: context["current-account"]
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
preview: function (params, context) {
|
||||
var firstRow = status.components.text(
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function previewRequest(showRecipient, params, context) {
|
||||
var amountRow = status.components.text(
|
||||
{},
|
||||
I18n.t('request_requesting') + " "
|
||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
+ " ETH"
|
||||
);
|
||||
|
||||
var markup = [amountRow];
|
||||
|
||||
if (showRecipient
|
||||
&& params["bot-db"]
|
||||
&& params["bot-db"]["public"]
|
||||
&& params["bot-db"]["public"]["recipient"]
|
||||
&& context["chat"]["group-chat"] === true) {
|
||||
|
||||
var recipientRow = status.components.text(
|
||||
{
|
||||
style: {
|
||||
color: "#9199a0",
|
||||
fontSize: 14,
|
||||
lineHeight: 18
|
||||
}
|
||||
},
|
||||
I18n.t('request_requesting_from') + " " + params["bot-db"]["public"]["recipient"]["name"]
|
||||
);
|
||||
markup.push(recipientRow);
|
||||
}
|
||||
|
||||
return {
|
||||
markup: status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "column"
|
||||
}
|
||||
},
|
||||
markup
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
function shortPreviewRequest(params, context) {
|
||||
return {
|
||||
markup: status.components.text(
|
||||
{},
|
||||
I18n.t('request_requesting') + " "
|
||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
+ " ETH"
|
||||
);
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var markup;
|
||||
|
||||
if (params["bot-db"]
|
||||
&& params["bot-db"]["public"]
|
||||
&& params["bot-db"]["public"]["recipient"]
|
||||
&& context["chat"]["group-chat"] === true) {
|
||||
|
||||
var secondRow = status.components.text(
|
||||
{
|
||||
style: {
|
||||
color: "#9199a0",
|
||||
fontSize: 14,
|
||||
lineHeight: 18
|
||||
}
|
||||
},
|
||||
I18n.t('request_requesting_from') + " " + params["bot-db"]["public"]["recipient"]["name"]
|
||||
);
|
||||
markup = [firstRow, secondRow];
|
||||
} else {
|
||||
markup = [firstRow];
|
||||
}
|
||||
|
||||
return {
|
||||
markup: status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "column"
|
||||
}
|
||||
},
|
||||
markup
|
||||
)
|
||||
};
|
||||
},
|
||||
shortPreview: function (params, context) {
|
||||
return {
|
||||
markup: status.components.text(
|
||||
{},
|
||||
I18n.t('request_requesting') + " "
|
||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
+ " ETH"
|
||||
)
|
||||
};
|
||||
},
|
||||
validator: function (params) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
function validateRequest(validateRecipient, params) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
|
||||
if (validateRecipient) {
|
||||
if (!params["bot-db"]["public"] || !params["bot-db"]["public"]["recipient"] || !params["bot-db"]["public"]["recipient"]["address"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
|
@ -642,47 +692,76 @@ status.command({
|
|||
)
|
||||
};
|
||||
}
|
||||
if (!params["amount"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_specified')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var amount = params.amount.replace(",", ".");
|
||||
var amountSplitted = amount.split(".");
|
||||
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_is_too_small')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
var val = web3.toWei(amount, "ether");
|
||||
if (val < 0) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch (err) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!params["amount"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_specified')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var amount = params.amount.replace(",", ".");
|
||||
var amountSplitted = amount.split(".");
|
||||
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_is_too_small')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
var val = web3.toWei(amount, "ether");
|
||||
if (val < 0) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch (err) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
status.command({
|
||||
name: "request",
|
||||
scope: ["global", "personal-chats", "registered", "humans"],
|
||||
icon: "money_white",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('request_title'),
|
||||
description: I18n.t('request_description'),
|
||||
params: paramsPersonalRequest,
|
||||
handler: handlePersonalRequest,
|
||||
preview: previewRequest.bind(null, false),
|
||||
shortPreview: shortPreviewRequest,
|
||||
validator: validateRequest.bind(null, false)
|
||||
});
|
||||
|
||||
status.command({
|
||||
name: "request",
|
||||
scope: ["global", "group-chats", "registered", "humans"],
|
||||
icon: "money_white",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('request_title'),
|
||||
description: I18n.t('request_description'),
|
||||
params: paramsGroupRequest,
|
||||
handler: handleGroupRequest,
|
||||
preview: previewRequest.bind(null, true),
|
||||
shortPreview: shortPreviewRequest,
|
||||
validator: validateRequest.bind(null, true)
|
||||
});
|
|
@ -1,562 +0,0 @@
|
|||
function calculateFee(n, tx) {
|
||||
var estimatedGas = 21000;
|
||||
if (tx !== null) {
|
||||
estimatedGas = web3.eth.estimateGas(tx);
|
||||
}
|
||||
|
||||
var gasMultiplicator = Math.pow(1.4, n).toFixed(3);
|
||||
var weiFee = web3.eth.gasPrice * gasMultiplicator * estimatedGas;
|
||||
// force fee in eth to be of BigNumber type
|
||||
var ethFee = web3.toBigNumber(web3.fromWei(weiFee, "ether"));
|
||||
// always display 7 decimal places
|
||||
return ethFee.toFixed(7);
|
||||
}
|
||||
|
||||
function calculateGasPrice(n) {
|
||||
var gasMultiplicator = Math.pow(1.4, n).toFixed(3);
|
||||
return web3.eth.gasPrice * gasMultiplicator;
|
||||
}
|
||||
|
||||
status.defineSubscription(
|
||||
"calculatedFee",
|
||||
{value: ["sliderValue"], tx: ["transaction"]},
|
||||
function (params) {
|
||||
return calculateFee(params.value, params.tx);
|
||||
}
|
||||
);
|
||||
|
||||
function getFeeExplanation(n) {
|
||||
return I18n.t('send_explanation') + I18n.t('send_explanation_' + (n + 2));
|
||||
}
|
||||
|
||||
status.defineSubscription(
|
||||
"feeExplanation",
|
||||
{value: ["sliderValue"]},
|
||||
function(params) {
|
||||
return getFeeExplanation(params.value);
|
||||
}
|
||||
);
|
||||
|
||||
function amountParameterBox(params, context) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
|
||||
var contactAddress = context.to;
|
||||
|
||||
var txData;
|
||||
var amount;
|
||||
try {
|
||||
amount = params.args[0];
|
||||
txData = {
|
||||
to: contactAddress,
|
||||
value: web3.toWei(amount) || 0
|
||||
};
|
||||
} catch (err) {
|
||||
amount = null;
|
||||
txData = {
|
||||
to: contactAddress,
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
|
||||
var sliderValue = params["bot-db"]["sliderValue"] || 0;
|
||||
|
||||
try {
|
||||
|
||||
status.setDefaultDb({
|
||||
transaction: txData,
|
||||
calculatedFee: calculateFee(sliderValue, txData),
|
||||
feeExplanation: getFeeExplanation(sliderValue),
|
||||
sliderValue: sliderValue
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
|
||||
status.setDefaultDb({
|
||||
transaction: txData,
|
||||
calculatedFee: "0",
|
||||
feeExplanation: "",
|
||||
sliderValue: sliderValue
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
title: I18n.t('send_title'),
|
||||
showBack: true,
|
||||
markup: status.components.scrollView(
|
||||
{
|
||||
keyboardShouldPersistTaps: "always"
|
||||
},
|
||||
[status.components.view(
|
||||
{
|
||||
flex: 1
|
||||
},
|
||||
[
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
fontSize: 14,
|
||||
color: "rgb(147, 155, 161)",
|
||||
paddingTop: 12,
|
||||
paddingLeft: 16,
|
||||
paddingRight: 16,
|
||||
paddingBottom: 20
|
||||
}
|
||||
},
|
||||
I18n.t('send_specify_amount')
|
||||
),
|
||||
status.components.touchable(
|
||||
{
|
||||
onPress: status.components.dispatch([status.events.FOCUS_INPUT, []])
|
||||
},
|
||||
status.components.view(
|
||||
{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
justifyContent: "center"
|
||||
},
|
||||
[
|
||||
status.components.text(
|
||||
{
|
||||
font: "light",
|
||||
numberOfLines: 1,
|
||||
ellipsizeMode: "tail",
|
||||
style: {
|
||||
maxWidth: 250,
|
||||
fontSize: 38,
|
||||
marginLeft: 8,
|
||||
color: "black"
|
||||
}
|
||||
},
|
||||
amount || "0.00"
|
||||
),
|
||||
status.components.text(
|
||||
{
|
||||
font: "light",
|
||||
style: {
|
||||
fontSize: 38,
|
||||
marginLeft: 8,
|
||||
color: "rgb(147, 155, 161)"
|
||||
}
|
||||
},
|
||||
I18n.t('eth')
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
fontSize: 14,
|
||||
color: "rgb(147, 155, 161)",
|
||||
paddingTop: 14,
|
||||
paddingLeft: 16,
|
||||
paddingRight: 16,
|
||||
paddingBottom: 5
|
||||
}
|
||||
},
|
||||
I18n.t('send_fee')
|
||||
),
|
||||
status.components.view(
|
||||
{
|
||||
flexDirection: "row"
|
||||
},
|
||||
[
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
fontSize: 17,
|
||||
color: "black",
|
||||
paddingLeft: 16
|
||||
}
|
||||
},
|
||||
[status.components.subscribe(["calculatedFee"])]
|
||||
),
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
fontSize: 17,
|
||||
color: "rgb(147, 155, 161)",
|
||||
paddingLeft: 4,
|
||||
paddingRight: 4
|
||||
}
|
||||
},
|
||||
I18n.t('eth')
|
||||
)
|
||||
]
|
||||
),
|
||||
status.components.slider(
|
||||
{
|
||||
maximumValue: 2,
|
||||
minimumValue: -2,
|
||||
onSlidingComplete: status.components.dispatch(
|
||||
[status.events.UPDATE_DB, "sliderValue"]
|
||||
),
|
||||
step: 1,
|
||||
style: {
|
||||
marginLeft: 16,
|
||||
marginRight: 16
|
||||
}
|
||||
}
|
||||
),
|
||||
status.components.view(
|
||||
{
|
||||
flexDirection: "row"
|
||||
},
|
||||
[
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: "rgb(147, 155, 161)",
|
||||
paddingLeft: 16,
|
||||
alignSelf: "flex-start"
|
||||
}
|
||||
},
|
||||
I18n.t('send_cheaper')
|
||||
),
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: "rgb(147, 155, 161)",
|
||||
paddingRight: 16,
|
||||
alignSelf: "flex-end",
|
||||
textAlign: "right"
|
||||
}
|
||||
},
|
||||
I18n.t('send_faster')
|
||||
)
|
||||
]
|
||||
),
|
||||
status.components.text(
|
||||
{
|
||||
style: {
|
||||
fontSize: 14,
|
||||
color: "black",
|
||||
paddingTop: 16,
|
||||
paddingLeft: 16,
|
||||
paddingRight: 16,
|
||||
paddingBottom: 16,
|
||||
lineHeight: 24
|
||||
}
|
||||
},
|
||||
[status.components.subscribe(["feeExplanation"])]
|
||||
)
|
||||
]
|
||||
)]
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var paramsSend = [
|
||||
{
|
||||
name: "amount",
|
||||
type: status.types.NUMBER,
|
||||
suggestions: amountParameterBox
|
||||
}
|
||||
];
|
||||
|
||||
function validateSend(params, context) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
|
||||
if (!params["amount"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_specified')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var amount = params["amount"].replace(",", ".");
|
||||
var amountSplitted = amount.split(".");
|
||||
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_is_too_small')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
var val = web3.toWei(amount, "ether");
|
||||
if (val < 0) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch (err) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var balance = web3.eth.getBalance(context.from);
|
||||
var fee = calculateFee(
|
||||
params["bot-db"]["sliderValue"],
|
||||
{
|
||||
to: context.to,
|
||||
value: val
|
||||
}
|
||||
);
|
||||
|
||||
if (bn(val).plus(bn(web3.toWei(fee, "ether"))).greaterThan(bn(balance))) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_insufficient_amount')
|
||||
+ web3.fromWei(balance, "ether")
|
||||
+ " ETH)"
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function handleSend(params, context) {
|
||||
var val = web3.toWei(params["amount"].replace(",", "."), "ether");
|
||||
|
||||
var gasPrice = calculateGasPrice(params["bot-db"]["sliderValue"]);
|
||||
var data = {
|
||||
from: context.from,
|
||||
to: context.to,
|
||||
value: val
|
||||
};
|
||||
|
||||
if (gasPrice) {
|
||||
data.gasPrice = gasPrice;
|
||||
}
|
||||
|
||||
web3.eth.sendTransaction(data, function(error, hash) {
|
||||
if (error) {
|
||||
// Do nothing, as error handling will be done as response to transaction.failed event from go
|
||||
} else {
|
||||
status.sendSignal("handler-result", {
|
||||
status: "success",
|
||||
hash: hash,
|
||||
origParams: context["orig-params"]
|
||||
});
|
||||
}
|
||||
});
|
||||
// async handler, so we don't return anything immediately
|
||||
}
|
||||
|
||||
function previewSend(params, context) {
|
||||
var amountStyle = {
|
||||
fontSize: 36,
|
||||
color: "#000000",
|
||||
height: 40
|
||||
};
|
||||
|
||||
var amount = status.components.view(
|
||||
{
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-end",
|
||||
maxWidth: 250
|
||||
},
|
||||
[status.components.text(
|
||||
{
|
||||
style: amountStyle,
|
||||
numberOfLines: 1,
|
||||
ellipsizeMode: "tail",
|
||||
font: "light"
|
||||
},
|
||||
status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
)]);
|
||||
|
||||
var currency = status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "column",
|
||||
justifyContent: "flex-end",
|
||||
paddingBottom: 0
|
||||
}
|
||||
},
|
||||
[status.components.text(
|
||||
{
|
||||
style: {
|
||||
color: "#9199a0",
|
||||
fontSize: 16,
|
||||
lineHeight: 18,
|
||||
marginLeft: 7.5
|
||||
}
|
||||
},
|
||||
I18n.t('eth')
|
||||
)]
|
||||
);
|
||||
|
||||
var row = status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: 8,
|
||||
marginBottom: 8
|
||||
}
|
||||
},
|
||||
[amount, currency]
|
||||
);
|
||||
|
||||
return {
|
||||
markup: status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "column"
|
||||
}
|
||||
},
|
||||
[row]
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
function shortPreviewSend(params, context) {
|
||||
return {
|
||||
markup: status.components.text(
|
||||
{},
|
||||
I18n.t('send_title') + ": "
|
||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
+ " ETH"
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var send = {
|
||||
name: "send",
|
||||
scope: ["personal-chats"],
|
||||
icon: "money_white",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('send_title'),
|
||||
description: I18n.t('send_description'),
|
||||
params: paramsSend,
|
||||
validator: validateSend,
|
||||
handler: handleSend,
|
||||
asyncHandler: true,
|
||||
preview: previewSend,
|
||||
shortPreview: shortPreviewSend
|
||||
};
|
||||
|
||||
status.command(send);
|
||||
status.response(send);
|
||||
|
||||
var paramsRequest = [
|
||||
{
|
||||
name: "amount",
|
||||
type: status.types.NUMBER
|
||||
}
|
||||
];
|
||||
|
||||
status.command({
|
||||
name: "request",
|
||||
scope: ["personal-chats"],
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('request_title'),
|
||||
description: I18n.t('request_description'),
|
||||
params: paramsRequest,
|
||||
handler: function (params, context) {
|
||||
var val = params["amount"].replace(",", ".");
|
||||
|
||||
return {
|
||||
event: "request",
|
||||
request: {
|
||||
command: "send",
|
||||
params: {
|
||||
amount: val
|
||||
},
|
||||
prefill: [val]
|
||||
}
|
||||
};
|
||||
},
|
||||
preview: function (params, context) {
|
||||
var row = status.components.text(
|
||||
{},
|
||||
I18n.t('request_requesting') + " "
|
||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
+ " ETH"
|
||||
);
|
||||
return {
|
||||
markup: status.components.view(
|
||||
{
|
||||
style: {
|
||||
flexDirection: "column"
|
||||
}
|
||||
},
|
||||
[row]
|
||||
)
|
||||
};
|
||||
},
|
||||
shortPreview: function (params, context) {
|
||||
return {
|
||||
markup: status.components.text(
|
||||
{},
|
||||
I18n.t('request_requesting') + " "
|
||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||
+ " ETH"
|
||||
)
|
||||
};
|
||||
},
|
||||
validator: function (params) {
|
||||
if (!params["bot-db"]) {
|
||||
params["bot-db"] = {};
|
||||
}
|
||||
|
||||
if (!params["amount"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_specified')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
var amount = params.amount.replace(",", ".");
|
||||
var amountSplitted = amount.split(".");
|
||||
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_amount_is_too_small')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
var val = web3.toWei(amount, "ether");
|
||||
if (val < 0) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch (err) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
I18n.t('validation_title'),
|
||||
I18n.t('validation_invalid_number')
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,448 +0,0 @@
|
|||
I18n.translations = {
|
||||
en: {
|
||||
send_title: 'Send transaction',
|
||||
send_description: 'Send a payment',
|
||||
send_choose_recipient: 'Choose recipient',
|
||||
send_specify_amount: 'Specify amount',
|
||||
send_fee: 'Fee',
|
||||
send_cheaper: 'Cheaper',
|
||||
send_faster: 'Faster',
|
||||
send_explanation: 'This is the most amount of money that might be used to process this transaction. Your transaction will be mined ',
|
||||
send_explanation_0: 'in a few minutes or more.',
|
||||
send_explanation_1: 'likely within a few minutes.',
|
||||
send_explanation_2: 'usually within a minute.',
|
||||
send_explanation_3: 'probably within 30 seconds.',
|
||||
send_explanation_4: 'probably within a few seconds.',
|
||||
send_sending_to: 'to ',
|
||||
|
||||
eth: 'ETH',
|
||||
|
||||
request_title: 'Request ETH',
|
||||
request_description: 'Request a payment',
|
||||
request_requesting: 'Requesting ',
|
||||
request_requesting_from: 'from ',
|
||||
|
||||
validation_title: 'Amount',
|
||||
validation_amount_specified: 'Amount must be specified',
|
||||
validation_invalid_number: 'Amount is not valid number',
|
||||
validation_amount_is_too_small: 'Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)',
|
||||
validation_insufficient_amount: 'Insufficient funds for gas * price + value (balance '
|
||||
},
|
||||
ru: {
|
||||
send_title: 'Отправить транзакцию',
|
||||
send_description: 'Отправить платеж',
|
||||
|
||||
request_title: 'Запросить ETH',
|
||||
request_description: 'Запросить платеж',
|
||||
request_requesting: 'Запрос ',
|
||||
|
||||
validation_title: 'Сумма',
|
||||
validation_amount_specified: 'Необходимо указать сумму',
|
||||
validation_invalid_number: 'Сумма не является действительным числом',
|
||||
validation_amount_is_too_small: 'Сумма излишне точная. Минимальная единица, которую можно отправить — 1 Wei (1x10^-18 ETH)',
|
||||
validation_insufficient_amount: 'Недостаточно ETH на балансе ('
|
||||
},
|
||||
af: {
|
||||
send_title: 'Stuur ETH',
|
||||
send_description: 'Stuur \'n betaling',
|
||||
|
||||
request_title: 'Versoek ETH',
|
||||
request_description: 'Versoek \'n betaling',
|
||||
request_requesting: 'Besig met versoek ',
|
||||
|
||||
validation_title: 'Bedrag',
|
||||
validation_amount_specified: 'Bedrag moet gespesifiseer word',
|
||||
validation_invalid_number: 'Bedrag is nie \'n geldige syfer nie',
|
||||
validation_insufficient_amount: 'Nie genoeg ETH in rekening nie ('
|
||||
},
|
||||
ar: {
|
||||
send_title: 'إرسال ETH',
|
||||
send_description: 'إرسال مدفوعات',
|
||||
|
||||
request_title: 'طلب ETH',
|
||||
request_description: 'طلب مدفوعات',
|
||||
request_requesting: 'مُطَالَبَة ',
|
||||
|
||||
validation_title: 'المبلغ',
|
||||
validation_amount_specified: 'يجب تحديد المبلغ',
|
||||
validation_invalid_number: 'المبلغ المحدد غير صحيح',
|
||||
validation_insufficient_amount: 'لا يوجد ETH كافي بالحساب ('
|
||||
},
|
||||
'zh-hant': {
|
||||
send_title: '發送 ETH',
|
||||
send_description: '發送一筆付款',
|
||||
|
||||
request_title: '請求 ETH',
|
||||
request_description: '請求一筆付款',
|
||||
request_requesting: '正在請求 ',
|
||||
|
||||
validation_title: '金額',
|
||||
validation_amount_specified: 'ي未指定金額',
|
||||
validation_invalid_number: '金額數字無效',
|
||||
validation_insufficient_amount: '餘額中 ETH 不足 ('
|
||||
},
|
||||
'zh-hans': {
|
||||
send_title: '发送ETH',
|
||||
send_description: '付款',
|
||||
|
||||
request_title: '请求ETH',
|
||||
request_description: '要求付款',
|
||||
request_requesting: '正在请求 ',
|
||||
|
||||
validation_title: '金額',
|
||||
validation_amount_specified: '必须指定金额',
|
||||
validation_invalid_number: '金额不是有效数字',
|
||||
validation_insufficient_amount: 'ETH余额不足 ('
|
||||
},
|
||||
'zh-yue': {
|
||||
send_title: '發送ETH',
|
||||
send_description: '發送付款',
|
||||
|
||||
request_title: '徵求ETH',
|
||||
request_description: '徵求付款',
|
||||
request_requesting: '徵求中 ',
|
||||
|
||||
validation_title: '金額',
|
||||
validation_amount_specified: '必須指定金額',
|
||||
validation_invalid_number: '指定金額並非有效數字',
|
||||
validation_insufficient_amount: '沒有足夠ETH餘額 ('
|
||||
},
|
||||
'zh-wuu': {
|
||||
send_title: '发送ETH',
|
||||
send_description: '发送付款',
|
||||
|
||||
request_title: '请求ETH',
|
||||
request_description: '请求付款',
|
||||
request_requesting: '请求中 ',
|
||||
|
||||
validation_title: '金额',
|
||||
validation_amount_specified: '金额必须明确',
|
||||
validation_invalid_number: '金额不是一个有效数字',
|
||||
validation_insufficient_amount: 'ETH余额不足 ('
|
||||
},
|
||||
nl: {
|
||||
send_title: 'Stuur ETH',
|
||||
send_description: 'Stuur een betaling',
|
||||
|
||||
request_title: 'Vraag ETH aan',
|
||||
request_description: 'Vraag om een betaling',
|
||||
request_requesting: 'Wordt aangevraagd ',
|
||||
|
||||
validation_title: 'Bedrag',
|
||||
validation_amount_specified: 'Bedrag moet worden opgegeven',
|
||||
validation_invalid_number: 'Bedrag is geen geldig nummer',
|
||||
validation_insufficient_amount: 'Niet genoeg ETH op saldo ('
|
||||
},
|
||||
fr: {
|
||||
send_title: 'Envoyer l\'ETH',
|
||||
send_description: 'Envoyer un paiement',
|
||||
|
||||
request_title: 'Demander l\'ETH',
|
||||
request_description: 'Demander un paiement',
|
||||
request_requesting: 'Demande en cours: ',
|
||||
|
||||
validation_title: 'Montant',
|
||||
validation_amount_specified: 'Le montant doit être spécifié',
|
||||
validation_invalid_number: 'Le montant n\'est pas un nombre valide',
|
||||
validation_insufficient_amount: 'Pas assez d\'ETH sur le solde ('
|
||||
},
|
||||
de: {
|
||||
send_title: 'ETH abschicken',
|
||||
send_description: 'Zahlung senden',
|
||||
|
||||
request_title: 'ETH anfragen',
|
||||
request_description: 'Zahlung anfragen',
|
||||
request_requesting: 'Anfrage: ',
|
||||
|
||||
validation_title: 'Betrag',
|
||||
validation_amount_specified: 'Betrag muss angegeben werden',
|
||||
validation_invalid_number: 'Betrag ist keine gültige Zahl',
|
||||
validation_insufficient_amount: 'Nicht genügend ETH auf dem Konto ('
|
||||
},
|
||||
hi: {
|
||||
send_title: 'ETH भेजें',
|
||||
send_description: 'भुगतान भेजें',
|
||||
|
||||
request_title: 'ETH का अनुरोध करें',
|
||||
request_description: 'भुगतान का अनुरोध करें',
|
||||
request_requesting: 'अनुरोध किया जा रहा है ',
|
||||
|
||||
validation_title: 'राशि',
|
||||
validation_amount_specified: 'राशि निर्दिष्ट की जानी चाहिए',
|
||||
validation_invalid_number: 'राशि वैध संख्या नहीं है',
|
||||
validation_insufficient_amount: 'बैलेंस पर पर्याप्त ETH नहीं है ('
|
||||
},
|
||||
hu: {
|
||||
send_title: 'ETH küldése',
|
||||
send_description: 'Kifizetés küldése',
|
||||
|
||||
request_title: 'ETH igénylése',
|
||||
request_description: 'Fizetés igénylése',
|
||||
request_requesting: 'Igénylés ',
|
||||
|
||||
validation_title: 'Összeg',
|
||||
validation_amount_specified: 'Az összeget meg kell határozni',
|
||||
validation_invalid_number: 'Az összeg nem egy elfogadott szám',
|
||||
validation_insufficient_amount: 'Nincs elég ETH a számlán ('
|
||||
},
|
||||
it: {
|
||||
send_title: 'Invia ETH',
|
||||
send_description: 'Invia un pagamento',
|
||||
|
||||
request_title: 'Richiedi ETH',
|
||||
request_description: 'Richiedi un pagamento',
|
||||
request_requesting: 'Richiesta in corso: ',
|
||||
|
||||
validation_title: 'Ammontare',
|
||||
validation_amount_specified: 'L\'ammontare deve essere specificato',
|
||||
validation_invalid_number: 'L\'ammontare non è un numero valido',
|
||||
validation_insufficient_amount: 'ETH insufficiente sul bilancio ('
|
||||
},
|
||||
ja: {
|
||||
send_title: 'ETHを送信',
|
||||
send_description: '支払いを送信',
|
||||
|
||||
request_title: 'ETHをリクエスト',
|
||||
request_description: '支払いをリクエスト',
|
||||
request_requesting: 'リクエスト中 ',
|
||||
|
||||
validation_title: '金額',
|
||||
validation_amount_specified: '金額を特定する必要があります',
|
||||
validation_invalid_number: '金額は有効な数字ではありません',
|
||||
validation_insufficient_amount: '残高に十分なETHがありません('
|
||||
},
|
||||
ko: {
|
||||
send_title: 'ETH 보내기',
|
||||
send_description: '지불금 보내기',
|
||||
|
||||
request_title: 'ETH 요청',
|
||||
request_description: '지불금 요청',
|
||||
request_requesting: '요청 중 ',
|
||||
|
||||
validation_title: '금액',
|
||||
validation_amount_specified: '금액을 지정해야 합니다',
|
||||
validation_invalid_number: '금액이 유효한 숫자가 아닙니다',
|
||||
validation_insufficient_amount: 'ETH 잔고가 부족합니다 ('
|
||||
},
|
||||
pl: {
|
||||
send_title: 'Wyślij ETH',
|
||||
send_description: 'Wyślij płatność',
|
||||
|
||||
request_title: 'Poproś o ETH',
|
||||
request_description: 'Poproś o płatność',
|
||||
request_requesting: 'Przesyłanie prośby ',
|
||||
|
||||
validation_title: 'Kwota',
|
||||
validation_amount_specified: 'Należy określić kwotę',
|
||||
validation_invalid_number: 'Kwota nie jest prawidłową liczbą',
|
||||
validation_insufficient_amount: 'Brak wystarczającej liczby ETH na koncie ('
|
||||
},
|
||||
'pt-br': {
|
||||
send_title: 'Enviar ETH',
|
||||
send_description: 'Enviar um pagamento',
|
||||
|
||||
request_title: 'Solicitar ETH',
|
||||
request_description: 'Solicitar um pagamento',
|
||||
request_requesting: 'Solicitando ',
|
||||
|
||||
validation_title: 'Quantia',
|
||||
validation_amount_specified: 'É necessário especificar a quantia',
|
||||
validation_invalid_number: 'A quantia não é um número válido',
|
||||
validation_insufficient_amount: 'ETH insuficiente no saldo ('
|
||||
},
|
||||
'pt-pt': {
|
||||
send_title: 'Enviar ETH',
|
||||
send_description: 'Enviar um pagamento',
|
||||
|
||||
request_title: 'Solicitar ETH',
|
||||
request_description: 'Solicitar um pagamento',
|
||||
request_requesting: 'A solicitar ',
|
||||
|
||||
validation_title: 'Montante',
|
||||
validation_amount_specified: 'O montante deve ser especificado',
|
||||
validation_invalid_number: 'O montante não é um número válido',
|
||||
validation_insufficient_amount: 'Não há ETH suficiente no saldo ('
|
||||
},
|
||||
ro: {
|
||||
send_title: 'Trimite ETH',
|
||||
send_description: 'Trimite o plată',
|
||||
|
||||
request_title: 'Solicită ETH',
|
||||
request_description: 'Solicită o plată',
|
||||
request_requesting: 'Se solicită ',
|
||||
|
||||
validation_title: 'Sumă',
|
||||
validation_amount_specified: 'Trebuie menționată o sumă',
|
||||
validation_invalid_number: 'Suma nu are forma unui număr valid',
|
||||
validation_insufficient_amount: 'Sold ETH insuficient ('
|
||||
},
|
||||
sl: {
|
||||
send_title: 'Pošlji ETH',
|
||||
send_description: 'Pošlji plačilo',
|
||||
|
||||
request_title: 'Zahtevaj ETH',
|
||||
request_description: 'Zahtevaj plačilo',
|
||||
request_requesting: 'Zahtevam ',
|
||||
|
||||
validation_title: 'Vsota',
|
||||
validation_amount_specified: 'Vsota mora biti izrecno navedena',
|
||||
validation_invalid_number: 'Vsota ni veljavna številka',
|
||||
validation_insufficient_amount: 'Stanje ETH na računu je prenizko ('
|
||||
},
|
||||
es: {
|
||||
send_title: 'Enviar ETH ',
|
||||
send_description: 'Enviar un pago',
|
||||
|
||||
request_title: 'Solicitar ETH',
|
||||
request_description: 'Solicitar un pago',
|
||||
request_requesting: 'Solicitando ',
|
||||
|
||||
validation_title: 'Cantidad',
|
||||
validation_amount_specified: 'Hay que especificar la cantidad',
|
||||
validation_invalid_number: 'La cantidad no es un número válido',
|
||||
validation_insufficient_amount: 'No hay suficiente ETH en conjunto ('
|
||||
},
|
||||
'es-ar': {
|
||||
send_title: 'Enviar ETH',
|
||||
send_description: 'Enviar un pago',
|
||||
|
||||
request_title: 'Solicitar ETH',
|
||||
request_description: 'Solicitar un pago',
|
||||
request_requesting: 'Solicitando ',
|
||||
|
||||
validation_title: 'Monto',
|
||||
validation_amount_specified: 'Debes especificar el monto',
|
||||
validation_invalid_number: 'El monto no es un número válido',
|
||||
validation_insufficient_amount: 'No tienes suficiente ETH en tu saldo ('
|
||||
},
|
||||
sw: {
|
||||
send_title: 'Tuma ETH',
|
||||
send_description: 'Tuma malipo',
|
||||
|
||||
request_title: 'Omba ETH',
|
||||
request_description: 'Omba malipo',
|
||||
request_requesting: 'Kuomba ',
|
||||
|
||||
validation_title: 'Kiasi',
|
||||
validation_amount_specified: 'Kiasi lazima kifafanuliwe',
|
||||
validation_invalid_number: 'Kiasi si nambari halali',
|
||||
validation_insufficient_amount: 'ETH haitoshi kwenye salio ('
|
||||
},
|
||||
sv: {
|
||||
send_title: 'Skicka ETH',
|
||||
send_description: 'Skicka en betalning',
|
||||
|
||||
request_title: 'Begär ETH',
|
||||
request_description: 'Begär en betalning',
|
||||
request_requesting: 'Begär ',
|
||||
|
||||
validation_title: 'Belopp',
|
||||
validation_amount_specified: 'Beloppet måste anges',
|
||||
validation_invalid_number: 'Beloppet är inte ett giltigt nummer',
|
||||
validation_insufficient_amount: 'Inte tillräcklig ETH på balansen ('
|
||||
},
|
||||
'fr-ch': {
|
||||
send_title: 'Envoyer des ETH',
|
||||
send_description: 'Envoyer un paiement',
|
||||
|
||||
request_title: 'Demander des ETH',
|
||||
request_description: 'Demander un paiement',
|
||||
request_requesting: 'Demande ',
|
||||
|
||||
validation_title: 'Montant',
|
||||
validation_amount_specified: 'Le montant doit être spécifié',
|
||||
validation_invalid_number: 'Le montant n\'est pas un nombre valable',
|
||||
validation_insufficient_amount: 'Pas assez d\'ETH sur le solde ('
|
||||
},
|
||||
'de-ch': {
|
||||
send_title: 'Sende ETH',
|
||||
send_description: 'Sende eine Zahlung',
|
||||
|
||||
request_title: 'Fordere ETH an',
|
||||
request_description: 'Eine Zahlung anfordern',
|
||||
request_requesting: 'Anfordern ',
|
||||
|
||||
validation_title: 'Betrag',
|
||||
validation_amount_specified: 'Der Betrag muss angegeben werden',
|
||||
validation_invalid_number: 'Der Betrag ist nicht gültig',
|
||||
validation_insufficient_amount: 'Nicht genug ETH vorhanden ('
|
||||
},
|
||||
'it-ch': {
|
||||
send_title: 'Invia ETH',
|
||||
send_description: 'Invia un pagamento',
|
||||
|
||||
request_title: 'Richiedi ETH',
|
||||
request_description: 'Richiedi un pagamento',
|
||||
request_requesting: 'Richiesta in corso: ',
|
||||
|
||||
validation_title: 'Importo',
|
||||
validation_amount_specified: 'Specificare l\'importo',
|
||||
validation_invalid_number: 'Importo inserito non valido',
|
||||
validation_insufficient_amount: 'Saldo ETH non sufficiente ('
|
||||
},
|
||||
th: {
|
||||
send_title: 'ส่ง ETH',
|
||||
send_description: 'ส่งการชำระเงิน',
|
||||
|
||||
request_title: 'ร้องขอ ETH',
|
||||
request_description: 'ร้องขอการชำระเงิน',
|
||||
request_requesting: 'กำลังร้องขอ ',
|
||||
|
||||
validation_title: 'จำนวน',
|
||||
validation_amount_specified: 'จำเป็นต้องระบุจำนวน',
|
||||
validation_invalid_number: 'จำนวนไม่ใช่หมายเลขที่ถูกต้อง',
|
||||
validation_insufficient_amount: 'มี ETH ไม่เพียงพอในยอดคงเหลือ ('
|
||||
},
|
||||
tr: {
|
||||
send_title: 'ETH gönder',
|
||||
send_description: 'Bir ödeme gönder',
|
||||
|
||||
request_title: 'ETH iste',
|
||||
request_description: 'Bir ödeme iste',
|
||||
request_requesting: 'İsteniyor ',
|
||||
|
||||
validation_title: 'Miktar',
|
||||
validation_amount_specified: 'Miktar belirtilmelidir',
|
||||
validation_invalid_number: 'Miktar geçerli bir sayı değil',
|
||||
validation_insufficient_amount: 'Yeterli ETH bakiyesi yok ('
|
||||
},
|
||||
uk: {
|
||||
send_title: 'Надіслати ETH',
|
||||
send_description: 'Надіслати платіж',
|
||||
|
||||
request_title: 'Запит ETH',
|
||||
request_description: 'Запит платежу',
|
||||
request_requesting: 'Запит ',
|
||||
|
||||
validation_title: 'Сума',
|
||||
validation_amount_specified: 'Сума повинна бути вказана',
|
||||
validation_invalid_number: 'Сума не дійсне число',
|
||||
validation_insufficient_amount: 'Не вистачає ETH на балансі ('
|
||||
},
|
||||
ur: {
|
||||
send_title: 'ETH بھیجیں',
|
||||
send_description: 'ادائیگی کریں',
|
||||
|
||||
request_title: 'ETH کی درخواست دیں',
|
||||
request_description: 'ادائیگی کی درخواست دیں',
|
||||
request_requesting: 'درخواست کی جارہی ہے ',
|
||||
|
||||
validation_title: 'رقم',
|
||||
validation_amount_specified: 'رقم درج کی جانی چاہیے۔ ',
|
||||
validation_invalid_number: 'رقیم درست ہندسے نہیں ہیں',
|
||||
validation_insufficient_amount: 'ETH میں کافی بیلنس نہیں ہے ('
|
||||
},
|
||||
vi: {
|
||||
send_title: 'Gửi ETH',
|
||||
send_description: 'Gửi một khoản thanh toán',
|
||||
|
||||
request_title: 'Yêu cầu ETH',
|
||||
request_description: 'Yêu cầu một khoản thanh toán',
|
||||
request_requesting: 'Đang yêu cầu ',
|
||||
|
||||
validation_title: 'Số tiền',
|
||||
validation_amount_specified: 'Số tiền phải được xác định',
|
||||
validation_invalid_number: 'Số tiền không phải là một số hợp lệ',
|
||||
validation_insufficient_amount: 'Không đủ ETH trong số dư ('
|
||||
}
|
||||
};
|
|
@ -7,13 +7,15 @@ var _status_catalog = {
|
|||
status = {};
|
||||
|
||||
function scopeToBitMask(scope) {
|
||||
// this function transforms scopes map to a single integer by generating a bit mask
|
||||
// this similar method also exists on clojure side: status-im.chat.models.commands/scope->bit-mask
|
||||
return (scope["global?"] ? 1 : 0) |
|
||||
(scope["registered-only?"] ? 2 : 0) |
|
||||
(scope["personal-chats?"] ? 4 : 0) |
|
||||
(scope["group-chats?"] ? 8 : 0) |
|
||||
(scope["can-use-for-dapps?"] ? 16 : 0);
|
||||
// this function transforms scopes array to a single integer by generating a bit mask
|
||||
return ((scope != null && scope.indexOf("global") > -1) ? 1 : 0) |
|
||||
((scope != null && scope.indexOf("personal-chats") > -1) ? 2 : 0) |
|
||||
((scope != null && scope.indexOf("group-chats") > -1) ? 4 : 0) |
|
||||
((scope != null && scope.indexOf("anonymous") > -1) ? 8 : 0) |
|
||||
((scope != null && scope.indexOf("registered") > -1) ? 16 : 0) |
|
||||
((scope != null && scope.indexOf("dapps") > -1) ? 32 : 0) |
|
||||
((scope != null && scope.indexOf("humans") > -1) ? 64 : 0) |
|
||||
((scope != null && scope.indexOf("public-chats") > -1) ? 128 : 0);
|
||||
}
|
||||
|
||||
function Command() {
|
||||
|
@ -22,7 +24,7 @@ function Response() {
|
|||
}
|
||||
|
||||
Command.prototype.addToCatalog = function () {
|
||||
_status_catalog.commands[[this.name, this.scope.bitmask]] = this;
|
||||
_status_catalog.commands[[this.name, this["scope-bitmask"]]] = this;
|
||||
};
|
||||
|
||||
Command.prototype.param = function (parameter) {
|
||||
|
@ -53,13 +55,8 @@ Command.prototype.create = function (com) {
|
|||
this["hide-send-button"] = com.hideSendButton;
|
||||
|
||||
// scopes
|
||||
this["scope"] = {};
|
||||
this["scope"]["global?"] = com["scope"] != null && com["scope"].indexOf("global") > -1;
|
||||
this["scope"]["registered-only?"] = com["scope"] != null && com["scope"].indexOf("registered-only") > -1;
|
||||
this["scope"]["personal-chats?"] = com["scope"] == null || com["scope"].indexOf("personal-chats") > -1;
|
||||
this["scope"]["group-chats?"] = com["scope"] == null || com["scope"].indexOf("group-chats") > -1;
|
||||
this["scope"]["can-use-for-dapps?"] = com["scope"] == null || com["scope"].indexOf("can-use-for-dapps") > -1;
|
||||
this["scope"]["bitmask"] = scopeToBitMask(this["scope"]);
|
||||
this.scope = com.scope;
|
||||
this["scope-bitmask"] = scopeToBitMask(this["scope"]);
|
||||
|
||||
this.addToCatalog();
|
||||
|
||||
|
@ -69,7 +66,7 @@ Command.prototype.create = function (com) {
|
|||
|
||||
Response.prototype = Object.create(Command.prototype);
|
||||
Response.prototype.addToCatalog = function () {
|
||||
_status_catalog.responses[[this.name, 0]] = this;
|
||||
_status_catalog.responses[[this.name, this["scope-bitmask"]]] = this;
|
||||
};
|
||||
Response.prototype.onReceiveResponse = function (handler) {
|
||||
this.onReceive = handler;
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
sub-params))
|
||||
|
||||
(defn- check-subscriptions-fx
|
||||
[{:keys [bot-db bot-subscriptions] :as app-db} {:keys [bot path]}]
|
||||
(when-let [subscriptions (and bot (get-in bot-subscriptions (concat [bot] [path])))]
|
||||
[{:keys [bot-db] :contacts/keys [contacts] :as app-db} {:keys [bot path]}]
|
||||
(when-let [subscriptions (and bot (get-in contacts (concat [bot :subscriptions] [path])))]
|
||||
{:call-jail-function-n
|
||||
(for [[sub-name sub-params] subscriptions]
|
||||
{:chat-id bot
|
||||
|
@ -47,7 +47,7 @@
|
|||
|
||||
(def ^:private keywordize-vector (partial mapv keyword))
|
||||
|
||||
(defn- transform-bot-subscriptions
|
||||
(defn transform-bot-subscriptions
|
||||
"Transforms bot subscriptions as returned from jail in the following format:
|
||||
|
||||
`{:calculatedFee {:subscriptions {:value [\"sliderValue\"]
|
||||
|
@ -78,14 +78,6 @@
|
|||
{}
|
||||
bot-subscriptions))
|
||||
|
||||
(defn add-active-bot-subscriptions
|
||||
"Add subscriptions for selected bot identities into app-db"
|
||||
[app-db bot-identities]
|
||||
(assoc app-db :bot-subscriptions (-> app-db
|
||||
:contacts/contacts
|
||||
(select-keys bot-identities)
|
||||
(utils/map-values (comp transform-bot-subscriptions :subscriptions)))))
|
||||
|
||||
(defn calculated-subscription
|
||||
[db {:keys [bot path]
|
||||
{:keys [error result]} :result}]
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
[status-im.chat.models.input :as input-model]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:current-bot-db
|
||||
:bot-db
|
||||
(fn [db]
|
||||
(let [current-chat-id (re-frame/subscribe [:get-current-chat-id])
|
||||
command-owner (-> db
|
||||
(input-model/selected-chat-command @current-chat-id)
|
||||
:command
|
||||
:owner-id)]
|
||||
[command-owner (get-in db [:bot-db command-owner])])))
|
||||
(:bot-db db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:current-bot-db
|
||||
:<- [:bot-db]
|
||||
:<- [:selected-chat-command]
|
||||
(fn [[bot-db command]]
|
||||
(let [command-owner (get-in command [:command :owner-id])]
|
||||
[command-owner (get bot-db command-owner)])))
|
||||
|
|
|
@ -15,3 +15,9 @@
|
|||
(def signing-phrase-message-id "signing-phrase-message")
|
||||
(def intro-status-message-id "intro-status")
|
||||
(def intro-message1-id "intro-message1")
|
||||
|
||||
;; TODO(janherich): figure out something better then this
|
||||
(def browse-command-ref ["browse" :command 247 "browse"])
|
||||
(def send-command-ref ["transactor" :command 83 "send"])
|
||||
(def request-command-ref ["transactor" :command 83 "request"])
|
||||
(def phone-command-ref ["console" :command 50 "phone"])
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
[status-im.protocol.core :as protocol]
|
||||
[status-im.constants :as const]
|
||||
[status-im.ui.components.list-selection :as list-selection]
|
||||
status-im.chat.events.input
|
||||
[status-im.chat.events.input :as input-events]
|
||||
status-im.chat.events.commands
|
||||
status-im.chat.events.requests
|
||||
status-im.chat.events.animation
|
||||
status-im.chat.events.receive-message
|
||||
status-im.chat.events.sign-up
|
||||
|
@ -157,8 +158,8 @@
|
|||
message))
|
||||
messages)))))
|
||||
|
||||
(defn- init-console-chat
|
||||
[{:keys [chats] :accounts/keys [current-account-id] :as db} existing-account?]
|
||||
(defn init-console-chat
|
||||
[{:keys [chats] :accounts/keys [current-account-id] :as db}]
|
||||
(if (chats const/console-chat-id)
|
||||
{:db db}
|
||||
(cond-> {:db (-> db
|
||||
|
@ -169,53 +170,49 @@
|
|||
:save-all-contacts [sign-up/console-contact]}
|
||||
|
||||
(not current-account-id)
|
||||
(update :dispatch-n concat sign-up/intro-events)
|
||||
|
||||
existing-account?
|
||||
(update :dispatch-n concat sign-up/start-signup-events))))
|
||||
(update :dispatch-n concat sign-up/intro-events))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:init-console-chat
|
||||
(fn [{:keys [db]} _]
|
||||
(init-console-chat db false)))
|
||||
(init-console-chat db)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:initialize-chats
|
||||
[(re-frame/inject-cofx :all-stored-chats)
|
||||
(re-frame/inject-cofx :stored-unviewed-messages)
|
||||
(re-frame/inject-cofx :get-stored-unanswered-requests)
|
||||
(re-frame/inject-cofx :get-last-stored-message)
|
||||
(re-frame/inject-cofx :get-message-previews)]
|
||||
(fn [{:keys [db all-stored-chats stored-unviewed-messages get-last-stored-message message-previews]} _]
|
||||
(let [{:accounts/keys [account-creation?]} db
|
||||
(fn [{:keys [db
|
||||
all-stored-chats
|
||||
stored-unanswered-requests
|
||||
stored-unviewed-messages
|
||||
get-last-stored-message
|
||||
message-previews]} _]
|
||||
(let [{:accounts/keys [account-creation?] :contacts/keys [contacts]} db
|
||||
new-db (unviewed-messages-model/load-unviewed-messages db stored-unviewed-messages)
|
||||
event [:load-default-contacts!]]
|
||||
(if account-creation?
|
||||
{:db new-db
|
||||
:dispatch-n [event]}
|
||||
(let [chats (->> all-stored-chats
|
||||
:dispatch event}
|
||||
(let [chat->message-id->request (reduce (fn [acc {:keys [chat-id message-id] :as request}]
|
||||
(assoc-in acc [chat-id message-id] request))
|
||||
{}
|
||||
stored-unanswered-requests)
|
||||
chats (->> all-stored-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
[chat-id (assoc chat :last-message (get-last-stored-message chat-id))]))
|
||||
[chat-id (assoc chat
|
||||
:last-message (get-last-stored-message chat-id)
|
||||
:requests (get chat->message-id->request chat-id))]))
|
||||
(into {}))]
|
||||
(-> new-db
|
||||
(assoc-in [:message-data :preview] message-previews)
|
||||
(assoc :handler-data (handler-data/get-all))
|
||||
(assoc :chats chats)
|
||||
(init-console-chat true)
|
||||
init-console-chat
|
||||
(update :dispatch-n conj event)))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:reload-chats
|
||||
[(re-frame/inject-cofx :all-stored-chats) (re-frame/inject-cofx :get-last-stored-message)]
|
||||
(fn [{:keys [db all-stored-chats get-last-stored-message]} _]
|
||||
(let [updated-chats (->> all-stored-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
(let [prev-chat (get (:chats db) chat-id)
|
||||
updated-chat (assoc chat :last-message (get-last-stored-message chat-id))]
|
||||
[chat-id (merge prev-chat updated-chat)])))
|
||||
(into {}))]
|
||||
(-> (assoc db :chats updated-chats)
|
||||
(init-console-chat true)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:send-seen!
|
||||
[re-frame/trim-v]
|
||||
|
@ -260,64 +257,35 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:browse-link-from-message
|
||||
(fn [{{:keys [global-commands]} :db} [_ link]]
|
||||
{:browse [(:browse global-commands) link]}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:init-chat
|
||||
[(re-frame/inject-cofx :get-stored-messages)]
|
||||
(fn [{:keys [db get-stored-messages]} _]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
{:db (assoc-in db [:chats current-chat-id :messages] (get-stored-messages current-chat-id))
|
||||
;; TODO(janherich): make this dispatch into fn call once commands loading is refactored
|
||||
:dispatch [:load-commands! current-chat-id]})))
|
||||
|
||||
(defn- jail-init-callback
|
||||
[{:keys [db] :as fx} chat-id]
|
||||
(let [bot-url (get-in db [:contacts/contacts chat-id :bot-url])
|
||||
was-opened? (get-in db [:chats chat-id :was-opened?])]
|
||||
(if (and (not was-opened?) bot-url)
|
||||
(assoc fx :call-jail-function {:chat-id chat-id
|
||||
:function :init
|
||||
:context {:from (:accounts/current-account-id db)}})
|
||||
fx)))
|
||||
(fn [{{:contacts/keys [contacts]} :db} [_ link]]
|
||||
{:browse [(get-in contacts chat-const/browse-command-ref) link]}))
|
||||
|
||||
(defn preload-chat-data
|
||||
"Takes coeffects map and chat-id, returns effects necessary when navigating to chat"
|
||||
[{:keys [db get-stored-messages]} chat-id]
|
||||
(let [messages (get-in db [:chats chat-id :messages])
|
||||
chat-loaded-event (get-in db [:chats chat-id :chat-loaded-event])
|
||||
commands-loaded? (get-in db [:contacts/contacts chat-id :commands-loaded?])]
|
||||
jail-loaded? (get-in db [:contacts/contacts chat-id :jail-loaded?])]
|
||||
(cond-> {:db (-> db
|
||||
(assoc :current-chat-id chat-id)
|
||||
(assoc-in [:chats chat-id :was-opened?] true)
|
||||
(model/set-chat-ui-props {:validation-messages nil})
|
||||
(update-in [:chats chat-id] dissoc :chat-loaded-event))
|
||||
:dispatch-n [[:load-requests! chat-id]]}
|
||||
(not commands-loaded?)
|
||||
(update :dispatch-n conj [:load-commands! chat-id #(re-frame/dispatch [::jail-init-callback chat-id])])
|
||||
(update-in [:chats chat-id] dissoc :chat-loaded-event))}
|
||||
|
||||
commands-loaded?
|
||||
(jail-init-callback chat-id)
|
||||
;; TODO(janherich): what's the purpose of the second term in AND ?
|
||||
(and (seq messages)
|
||||
(not= (count messages) 1))
|
||||
(empty? messages)
|
||||
(assoc-in [:db :chats chat-id :messages] (get-stored-messages chat-id))
|
||||
|
||||
chat-loaded-event
|
||||
(update :dispatch-n conj chat-loaded-event))))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:add-chat-loaded-event
|
||||
[re-frame/trim-v]
|
||||
(fn [db [chat-id event]]
|
||||
(assoc-in db [:chats chat-id :chat-loaded-event] event)))
|
||||
(assoc :dispatch chat-loaded-event))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::jail-init-callback
|
||||
:add-chat-loaded-event
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [chat-id]]
|
||||
(jail-init-callback {:db db} chat-id)))
|
||||
(fn [{:keys [db] :as cofx} [chat-id event]]
|
||||
(if (get (:chats db) chat-id)
|
||||
{:db (assoc-in db [:chats chat-id :chat-loaded-event] event)}
|
||||
(-> (model/add-chat cofx chat-id) ; chat not created yet, we have to create it
|
||||
(assoc-in [:db :chats chat-id :chat-loaded-event] event)))))
|
||||
|
||||
;; TODO(janherich): remove this unnecessary event in the future (only model function `add-chat` will stay)
|
||||
(handlers/register-handler-fx
|
||||
|
@ -326,14 +294,16 @@
|
|||
(fn [cofx [chat-id chat-props]]
|
||||
(model/add-chat cofx chat-id chat-props)))
|
||||
|
||||
(defn- navigate-to-chat
|
||||
[cofx chat-id navigation-replace?]
|
||||
(let [nav-fn (if navigation-replace?
|
||||
#(navigation/navigate-to % :chat)
|
||||
#(navigation/replace-view % :chat))]
|
||||
(-> cofx
|
||||
(preload-chat-data chat-id)
|
||||
(update :db nav-fn))))
|
||||
(defn navigate-to-chat
|
||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||
([cofx chat-id]
|
||||
(navigate-to-chat cofx chat-id false))
|
||||
([cofx chat-id navigation-replace?]
|
||||
(let [nav-fn (if navigation-replace?
|
||||
#(navigation/navigate-to % :chat)
|
||||
#(navigation/replace-view % :chat))]
|
||||
(-> (preload-chat-data cofx chat-id)
|
||||
(update :db nav-fn)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:navigate-to-chat
|
||||
|
@ -370,3 +340,12 @@
|
|||
(fn [cofx [chat]]
|
||||
(model/upsert-chat cofx chat)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:check-and-open-dapp!
|
||||
(fn [{{:keys [current-chat-id]
|
||||
:contacts/keys [contacts] :as db} :db} _]
|
||||
(when-let [dapp-url (get-in contacts [current-chat-id :dapp-url])]
|
||||
(-> db
|
||||
(input-events/select-chat-input-command
|
||||
(assoc (get-in contacts chat-const/browse-command-ref) :prefill [dapp-url]) nil true)
|
||||
(assoc :dispatch [:send-current-message])))))
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
[taoensso.timbre :as log]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.chat.models.commands :as commands-model]))
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
|
@ -26,24 +25,18 @@
|
|||
[db
|
||||
{{command-name :command
|
||||
content-command-name :content-command
|
||||
:keys [content-command-scope scope params type bot]} :content
|
||||
:keys [content-command-scope-bitmask scope-bitmask params type bot]} :content
|
||||
:keys [chat-id jail-id group-id] :as message}
|
||||
data-type]
|
||||
(let [{:keys [chats]
|
||||
:accounts/keys [current-account-id]
|
||||
:contacts/keys [contacts]} db
|
||||
jail-id (or bot jail-id chat-id)
|
||||
jail-command-name (or content-command-name command-name)
|
||||
;; here we're trying to use the default scope if there is no other scope provided
|
||||
default-command-scope (-> (get-in contacts [jail-id :commands (keyword jail-command-name)])
|
||||
first
|
||||
:scope)]
|
||||
(if (get-in contacts [jail-id :commands-loaded?])
|
||||
jail-command-name (or content-command-name command-name)]
|
||||
(if (get-in contacts [jail-id :jail-loaded?])
|
||||
(let [path [(if (= :response (keyword type)) :responses :commands)
|
||||
[jail-command-name
|
||||
(commands-model/scope->bit-mask (or scope
|
||||
content-command-scope
|
||||
default-command-scope))]
|
||||
(or scope-bitmask content-command-scope-bitmask)]
|
||||
data-type]
|
||||
to (get-in contacts [chat-id :address])
|
||||
jail-params {:parameters params
|
||||
|
@ -54,9 +47,8 @@
|
|||
:callback-events-creator (fn [jail-response]
|
||||
[[::jail-command-data-response
|
||||
jail-response message data-type]])}})
|
||||
{:dispatch-n [[:add-commands-loading-callback jail-id
|
||||
#(re-frame/dispatch [:request-command-message-data message data-type])]
|
||||
[:load-commands! jail-id]]})))
|
||||
{:db (update-in db [:contacts/contacts jail-id :jail-loaded-events]
|
||||
conj [:request-command-message-data message data-type])})))
|
||||
|
||||
;;;; Handlers
|
||||
|
||||
|
@ -76,7 +68,7 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:request-command-message-data
|
||||
[re-frame/trim-v]
|
||||
[re-frame/trim-v (re-frame/inject-cofx :get-local-storage-data)]
|
||||
(fn [{:keys [db]} [message data-type]]
|
||||
(request-command-message-data db message data-type)))
|
||||
|
||||
|
|
|
@ -60,12 +60,8 @@
|
|||
(accounts-events/create-account db (:password params)))
|
||||
|
||||
"phone"
|
||||
(fn [{:keys [db]} {:keys [params id]}]
|
||||
(-> db
|
||||
(sign-up-events/sign-up (:phone params) id)
|
||||
(as-> fx
|
||||
(assoc fx :dispatch-n [(:dispatch fx)]))
|
||||
(dissoc :dispatch)))
|
||||
(fn [{:keys [db]} {:keys [params id]}]
|
||||
(sign-up-events/sign-up db (:phone params) id))
|
||||
|
||||
"confirmation-code"
|
||||
(fn [{:keys [db]} {:keys [params id]}]
|
||||
|
|
|
@ -46,33 +46,6 @@
|
|||
|
||||
;;;; Helper functions
|
||||
|
||||
(defn- extract-command-request-owners [commands requests]
|
||||
[commands requests]
|
||||
(into #{} (keep :owner-id) (concat commands requests)))
|
||||
|
||||
(defn update-suggestions
|
||||
"Update suggestions for current chat input, takes db as the only argument
|
||||
and returns new db with up-to date suggestions"
|
||||
[{:keys [chats current-chat-id] :as db}]
|
||||
(let [chat-text (str/trim (or (get-in chats [current-chat-id :input-text]) ""))
|
||||
requests (->> (commands-model/get-possible-requests db)
|
||||
(remove (fn [{:keys [type]}]
|
||||
(= type :grant-permissions))))
|
||||
commands (commands-model/commands-for-chat db current-chat-id)
|
||||
{:keys [dapp?]} (get-in db [:contacts/contacts current-chat-id])
|
||||
;; TODO(janherich) surely there is a better place to merge in possible commands/request/subscriptions into current chat
|
||||
;; then in `:update-suggestions` which is called whenever commands for chat are loaded, chat view is opened
|
||||
;; or new message is received from network - it's unnecessary to call it as a response to last two events
|
||||
new-db (cond-> (-> db
|
||||
(update-in [:chats current-chat-id] merge {:possible-commands commands
|
||||
:possible-requests requests})
|
||||
(bots-events/add-active-bot-subscriptions (extract-command-request-owners
|
||||
commands requests)))
|
||||
(and dapp?
|
||||
(str/blank? chat-text))
|
||||
(assoc-in [:chats current-chat-id :parameter-boxes :message] nil))]
|
||||
new-db))
|
||||
|
||||
(defn set-chat-input-text
|
||||
"Set input text for current-chat and updates suggestions relevant to current input.
|
||||
Takes db, input text and `:append?` flag as arguments and returns new db.
|
||||
|
@ -141,24 +114,19 @@
|
|||
(input-model/join-command-args command-args)
|
||||
(when (and move-to-next?
|
||||
(= index (dec (count command-args))))
|
||||
const/spacing-char))]
|
||||
(-> db
|
||||
(set-chat-input-text input-text)
|
||||
update-suggestions)))))
|
||||
const/spacing-char))]
|
||||
(set-chat-input-text db input-text)))))
|
||||
|
||||
(defn load-chat-parameter-box
|
||||
"Returns fx for loading chat parameter box for active chat"
|
||||
[{:keys [current-chat-id bot-db] :accounts/keys [current-account-id] :as db}
|
||||
{:keys [name scope type bot owner-id] :as command}]
|
||||
{:keys [name scope-bitmask type bot owner-id] :as command}]
|
||||
(let [parameter-index (input-model/argument-position db)]
|
||||
(when (and command (> parameter-index -1))
|
||||
(let [data (get-in db [:local-storage current-chat-id])
|
||||
bot-db (get bot-db owner-id)
|
||||
path [(if (= :command type) :commands :responses)
|
||||
[name
|
||||
(if (= :command type)
|
||||
(commands-model/scope->bit-mask scope)
|
||||
0)]
|
||||
[name scope-bitmask]
|
||||
:params
|
||||
parameter-index
|
||||
:suggestions]
|
||||
|
@ -301,11 +269,10 @@
|
|||
request-data {:message-id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id (or owner-id jail-id)
|
||||
:content {:command (:name command)
|
||||
:scope (when-not (:to-message-id metadata)
|
||||
(:scope command))
|
||||
:params params
|
||||
:type (:type command)}
|
||||
:content {:command (:name command)
|
||||
:scope-bitmask (:scope-bitmask command)
|
||||
:params params
|
||||
:type (:type command)}
|
||||
:on-requested (fn [jail-response]
|
||||
(event-after-creator command-message jail-response))}]
|
||||
(commands-events/request-command-message-data db request-data data-type)))
|
||||
|
@ -395,11 +362,6 @@
|
|||
(when-let [cmp-ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
{::blur-rn-component cmp-ref})))
|
||||
|
||||
(handlers/register-handler-db
|
||||
:update-suggestions
|
||||
(fn [db _]
|
||||
(update-suggestions db)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:load-chat-parameter-box
|
||||
[re-frame/trim-v]
|
||||
|
@ -449,8 +411,7 @@
|
|||
clear-seq-arguments
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
(model/set-chat-ui-props {:sending-in-progress? false})
|
||||
update-suggestions)
|
||||
(model/set-chat-ui-props {:sending-in-progress? false}))
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
:dispatch [:check-commands-handlers! {:message (get-in db [:chats current-chat-id :input-text])
|
||||
:command command-message
|
||||
|
@ -504,8 +465,7 @@
|
|||
{:db db}
|
||||
{:db (-> db
|
||||
(set-chat-input-metadata nil)
|
||||
(set-chat-input-text nil)
|
||||
update-suggestions)
|
||||
(set-chat-input-text nil))
|
||||
;; TODO: refactor send-message.cljs to use atomic pure handlers and get rid of this dispatch
|
||||
:dispatch [:prepare-message {:message input-text
|
||||
:chat-id current-chat-id
|
||||
|
@ -592,5 +552,4 @@
|
|||
(fn [db _]
|
||||
(-> db
|
||||
(model/toggle-chat-ui-prop :show-suggestions?)
|
||||
(model/set-chat-ui-props {:validation-messages nil})
|
||||
update-suggestions)))
|
||||
(model/set-chat-ui-props {:validation-messages nil}))))
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
[status-im.constants :as const]
|
||||
[status-im.chat.utils :as chat-utils]
|
||||
[status-im.chat.models :as model]
|
||||
[status-im.chat.models.commands :as commands-model]
|
||||
[status-im.chat.models.unviewed-messages :as unviewed-messages-model]
|
||||
[status-im.chat.events.requests :as requests-events]
|
||||
[status-im.data-store.chats :as chat-store]
|
||||
[status-im.data-store.messages :as msg-store]))
|
||||
|
||||
|
@ -28,53 +30,69 @@
|
|||
(fn [cofx]
|
||||
(assoc cofx :get-last-clock-value msg-store/get-last-clock-value)))
|
||||
|
||||
(defn- get-current-identity
|
||||
(defn- get-current-account
|
||||
[{:accounts/keys [accounts current-account-id]}]
|
||||
(get-in accounts [current-account-id :public-key]))
|
||||
(get accounts current-account-id))
|
||||
|
||||
(defn- lookup-response-ref
|
||||
[access-scope->commands-responses account chat contacts response-name]
|
||||
(let [available-commands-responses (commands-model/commands-responses :response
|
||||
access-scope->commands-responses
|
||||
account
|
||||
chat
|
||||
contacts)]
|
||||
(:ref (get available-commands-responses response-name))))
|
||||
|
||||
(defn add-message
|
||||
[{:keys [db message-exists? get-last-stored-message pop-up-chat?
|
||||
get-last-clock-value now random-id] :as cofx}
|
||||
{:keys [from group-id chat-id content-type
|
||||
{:keys [from group-id chat-id content-type content
|
||||
message-id timestamp clock-value]
|
||||
:as message
|
||||
:or {clock-value 0}}]
|
||||
(let [chat-identifier (or group-id chat-id from)
|
||||
current-identity (get-current-identity db)]
|
||||
(let [{:keys [access-scope->commands-responses] :contacts/keys [contacts]} db
|
||||
chat-identifier (or group-id chat-id from)
|
||||
current-account (get-current-account db)]
|
||||
;; proceed with adding message if message is not already stored in realm,
|
||||
;; it's not from current user (outgoing message) and it's for relevant chat
|
||||
;; (either current active chat or new chat not existing yet)
|
||||
(if (and (not (message-exists? message-id))
|
||||
(not= from current-identity)
|
||||
(not= from (:public-key current-account))
|
||||
(pop-up-chat? chat-identifier))
|
||||
(let [group-chat? (not (nil? group-id))
|
||||
enriched-message (assoc (chat-utils/check-author-direction
|
||||
(get-last-stored-message chat-identifier)
|
||||
message)
|
||||
:chat-id chat-identifier
|
||||
:timestamp (or timestamp now)
|
||||
:clock-value (clocks/receive
|
||||
clock-value
|
||||
(get-last-clock-value chat-identifier)))
|
||||
command-request? (= content-type const/content-type-command-request)
|
||||
command (:command content)
|
||||
fx (model/upsert-chat cofx {:chat-id chat-identifier
|
||||
:group-chat group-chat?})]
|
||||
:group-chat group-chat?})
|
||||
enriched-message (cond-> (assoc (chat-utils/check-author-direction
|
||||
(get-last-stored-message chat-identifier)
|
||||
message)
|
||||
:chat-id chat-identifier
|
||||
:timestamp (or timestamp now)
|
||||
:clock-value (clocks/receive
|
||||
clock-value
|
||||
(get-last-clock-value chat-identifier)))
|
||||
(and command command-request?)
|
||||
(assoc-in [:content :content-command-ref]
|
||||
(lookup-response-ref access-scope->commands-responses
|
||||
current-account
|
||||
(get-in fx [:db :chats chat-identifier])
|
||||
contacts
|
||||
command)))]
|
||||
(cond-> (-> fx
|
||||
(update :db #(-> %
|
||||
(chat-utils/add-message-to-db chat-identifier chat-identifier enriched-message
|
||||
(:new? enriched-message))
|
||||
(unviewed-messages-model/add-unviewed-message chat-identifier message-id)
|
||||
(assoc-in [:chats chat-identifier :last-message] message)))
|
||||
(assoc :dispatch-n [[:request-command-message-data enriched-message :short-preview]]
|
||||
:save-message (dissoc enriched-message :new?)))
|
||||
(assoc-in [:chats chat-identifier :last-message] enriched-message)))
|
||||
(assoc :save-message (dissoc enriched-message :new?)))
|
||||
|
||||
(get-in enriched-message [:content :command])
|
||||
(update :dispatch-n conj [:request-command-preview enriched-message])
|
||||
command
|
||||
(update :dispatch-n concat [[:request-command-message-data enriched-message :short-preview]
|
||||
[:request-command-preview enriched-message]])
|
||||
|
||||
(= (:content-type enriched-message) const/content-type-command-request)
|
||||
(update :dispatch-n conj [:add-request chat-identifier enriched-message])
|
||||
;; TODO(janherich) this shouldn't be dispatch, but plain function call, refactor after adding requests is refactored
|
||||
true
|
||||
(update :dispatch-n conj [:update-suggestions])))
|
||||
command-request?
|
||||
(requests-events/add-request chat-identifier enriched-message)))
|
||||
{:db db})))
|
||||
|
||||
(def ^:private receive-interceptors
|
||||
|
@ -102,6 +120,6 @@
|
|||
receive-interceptors
|
||||
(fn [{:keys [db] :as cofx} [chat-id message]]
|
||||
(if (and (:status-node-started? db)
|
||||
(get-in db [:contacts/contacts chat-id :commands-loaded?]))
|
||||
(get-in db [:contacts/contacts chat-id :jail-loaded?]))
|
||||
(add-message cofx message)
|
||||
{:dispatch-later [{:ms 400 :dispatch [:received-message-when-commands-loaded chat-id message]}]})))
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
(ns status-im.chat.events.requests
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.data-store.requests :as requests-store]))
|
||||
|
||||
;; Coeffects
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:get-stored-unanswered-requests
|
||||
(fn [cofx _]
|
||||
(assoc cofx :stored-unanswered-requests (requests-store/get-all-unanswered))))
|
||||
|
||||
;; Effects
|
||||
(re-frame/reg-fx
|
||||
::request-answered
|
||||
(fn [{:keys [chat-id message-id]}]
|
||||
(requests-store/mark-as-answered chat-id message-id)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::save-request
|
||||
(fn [request]
|
||||
(requests-store/save request)))
|
||||
|
||||
;; Handlers
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:request-answered
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [chat-id message-id]]
|
||||
{:db (update-in db [:chats chat-id :requests] dissoc message-id)
|
||||
::request-answered {:chat-id chat-id
|
||||
:message-id message-id}}))
|
||||
|
||||
(defn add-request
|
||||
"Takes fx, chat-id and message, updates fx with necessary data for adding new request"
|
||||
[fx chat-id {:keys [message-id content]}]
|
||||
(let [request {:chat-id chat-id
|
||||
:message-id message-id
|
||||
:response (:command content)
|
||||
:status "open"}]
|
||||
(-> fx
|
||||
(assoc-in [:db :chats chat-id :requests message-id] request)
|
||||
(assoc ::save-request request))))
|
|
@ -140,8 +140,7 @@
|
|||
[re-frame/trim-v (re-frame/inject-cofx :random-id)]
|
||||
(fn [{:keys [db random-id now] :as cofx} [contacts]]
|
||||
(-> {:db db}
|
||||
(accounts-events/account-update {:signed-up? true
|
||||
:last-updated now})
|
||||
(accounts-events/account-update {:signed-up? true :last-updated now})
|
||||
(assoc :dispatch (sign-up/contacts-synchronised-event random-id)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
console-chat-id]]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
||||
status-im.chat.events
|
||||
status-im.chat.handlers.requests
|
||||
status-im.chat.events
|
||||
status-im.chat.handlers.send-message
|
||||
status-im.chat.handlers.webview-bridge))
|
||||
|
||||
|
@ -73,21 +72,6 @@
|
|||
remove-pending-messages!
|
||||
delete-chat!))
|
||||
|
||||
(register-handler
|
||||
:check-and-open-dapp!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-chat-id global-commands]
|
||||
:contacts/keys [contacts]}]
|
||||
(let [dapp-url (get-in contacts [current-chat-id :dapp-url])]
|
||||
(when dapp-url
|
||||
(am/go
|
||||
(dispatch [:select-chat-input-command
|
||||
(assoc (first (:browse global-commands)) :prefill [dapp-url])
|
||||
nil
|
||||
true])
|
||||
(a/<! (a/timeout 100))
|
||||
(dispatch [:send-current-message])))))))
|
||||
|
||||
(register-handler :update-group-message
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-public-key web3 chats]}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
(ns status-im.chat.handlers.requests
|
||||
(:require [re-frame.core :refer [after dispatch enrich]]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[status-im.data-store.requests :as requests]
|
||||
[status-im.utils.handlers :refer [register-handler] :as u]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn store-request!
|
||||
[{:keys [new-request]}]
|
||||
(requests/save new-request))
|
||||
|
||||
(defn add-request
|
||||
[db [_ chat-id {:keys [message-id content] :as r}]]
|
||||
(let [request {:chat-id chat-id
|
||||
:message-id message-id
|
||||
:bot (:bot content)
|
||||
:type (:command content)
|
||||
:added (js/Date.)}
|
||||
request' (update request :type keyword)]
|
||||
(log/debug "Adding request: " request')
|
||||
(-> db
|
||||
(update-in [:chats chat-id :requests] conj request')
|
||||
(assoc :new-request request))))
|
||||
|
||||
(defn load-requests!
|
||||
[{:keys [current-chat-id] :as db} [_ chat-id]]
|
||||
(let [chat-id' (or chat-id current-chat-id)
|
||||
;; todo maybe limit is needed
|
||||
requests (requests/get-available-by-chat-id chat-id')
|
||||
requests' (map #(update % :type keyword) requests)]
|
||||
(assoc-in db [:chats chat-id' :requests] requests')))
|
||||
|
||||
(defn mark-request-as-answered!
|
||||
[_ [_ chat-id message-id]]
|
||||
(requests/mark-as-answered chat-id message-id))
|
||||
|
||||
(register-handler :add-request
|
||||
(after store-request!)
|
||||
add-request)
|
||||
|
||||
(register-handler :load-requests! load-requests!)
|
||||
|
||||
(register-handler :request-answered!
|
||||
(after (fn [_ [_ chat-id]]
|
||||
(dispatch [:load-requests! chat-id])))
|
||||
(u/side-effect! mark-request-as-answered!))
|
|
@ -38,7 +38,8 @@
|
|||
content' (assoc content :handler-data handler-data
|
||||
:type (name (:type command))
|
||||
:content-command (:name command)
|
||||
:content-command-scope (:scope command)
|
||||
:content-command-scope-bitmask (:scope-bitmask command)
|
||||
:content-command-ref (:ref command)
|
||||
:bot (or (:bot command)
|
||||
(:owner-id command)))]
|
||||
{:message-id id
|
||||
|
@ -126,7 +127,7 @@
|
|||
(u/side-effect!
|
||||
(fn [_ [_ {{:keys [to-message]} :command :keys [chat-id]}]]
|
||||
(when to-message
|
||||
(dispatch [:request-answered! chat-id to-message])))))
|
||||
(dispatch [:request-answered chat-id to-message])))))
|
||||
|
||||
(register-handler ::invoke-command-handlers!
|
||||
(u/side-effect!
|
||||
|
@ -138,7 +139,7 @@
|
|||
id]} :command
|
||||
:keys [chat-id address]
|
||||
:as orig-params}]]
|
||||
(let [{:keys [type name scope bot owner-id]} command
|
||||
(let [{:keys [type name scope-bitmask bot owner-id]} command
|
||||
handler-type (if (= :command type) :commands :responses)
|
||||
to (get-in contacts [chat-id :address])
|
||||
identity (or owner-id bot chat-id)
|
||||
|
@ -151,19 +152,16 @@
|
|||
:current-account (get accounts current-account-id)
|
||||
:message-id id}
|
||||
(:async-handler command)
|
||||
(assoc :orig-params orig-params))}]
|
||||
(dispatch
|
||||
[:check-and-load-commands!
|
||||
identity
|
||||
#(status/call-jail
|
||||
{:jail-id identity
|
||||
:path [handler-type [name (commands-model/scope->bit-mask scope)] :handler]
|
||||
:params jail-params
|
||||
:callback (if (:async-handler command) ; async handler, we ignore return value
|
||||
(fn [_]
|
||||
(log/debug "Async command handler called"))
|
||||
(fn [res]
|
||||
(dispatch [:command-handler! chat-id orig-params res])))})])))))
|
||||
(assoc :orig-params orig-params))}]
|
||||
(status/call-jail
|
||||
{:jail-id identity
|
||||
:path [handler-type [name scope-bitmask] :handler]
|
||||
:params jail-params
|
||||
:callback (if (:async-handler command) ; async handler, we ignore return value
|
||||
(fn [_]
|
||||
(log/debug "Async command handler called"))
|
||||
(fn [res]
|
||||
(dispatch [:command-handler! chat-id orig-params res])))})))))
|
||||
|
||||
(register-handler :prepare-message
|
||||
(u/side-effect!
|
||||
|
|
|
@ -4,111 +4,41 @@
|
|||
[clojure.string :as str]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn scope->bit-mask
|
||||
"Transforms scope map to a single integer value by generating a bit mask."
|
||||
[{:keys [global? registered-only? personal-chats? group-chats? can-use-for-dapps?]}]
|
||||
(bit-or (when global? 1)
|
||||
(when registered-only? 2)
|
||||
(when personal-chats? 4)
|
||||
(when group-chats? 8)
|
||||
(when can-use-for-dapps? 16)))
|
||||
(defn- resolve-references
|
||||
[contacts name->ref]
|
||||
(reduce-kv (fn [acc name ref]
|
||||
(assoc acc name (get-in contacts ref)))
|
||||
{}
|
||||
name->ref))
|
||||
|
||||
(defn get-mixable-commands
|
||||
"Returns all commands of mixable contacts."
|
||||
[{:contacts/keys [contacts]}]
|
||||
(->> contacts
|
||||
(vals)
|
||||
(filter :mixable?)
|
||||
(mapv :commands)
|
||||
(mapcat #(into [] %))
|
||||
(reduce (fn [acc [k v]] (update acc k #(into % v))) {})))
|
||||
(defn- is-dapp? [all-contacts {:keys [identity]}]
|
||||
(get-in all-contacts [identity :dapp?]))
|
||||
|
||||
(defn get-mixable-identities
|
||||
"Returns a lazy-seq of all mixable contacts. Each contact contains only one key `:identity`."
|
||||
[{:contacts/keys [contacts]}]
|
||||
(->> contacts
|
||||
(vals)
|
||||
(filter :mixable?)
|
||||
(map (fn [{:keys [whisper-identity]}]
|
||||
{:identity whisper-identity}))))
|
||||
(defn commands-responses
|
||||
"Returns map of commands/responses eligible for current chat."
|
||||
[type access-scope->commands-responses {:keys [address]} {:keys [contacts group-chat public?]} all-contacts]
|
||||
(let [dapps? (some (partial is-dapp? all-contacts) contacts)
|
||||
humans? (some (comp not (partial is-dapp? all-contacts)) contacts)
|
||||
basic-access-scope (cond-> #{}
|
||||
group-chat (conj :group-chats)
|
||||
(not group-chat) (conj :personal-chats)
|
||||
address (conj :registered)
|
||||
(not address) (conj :anonymous)
|
||||
dapps? (conj :dapps)
|
||||
humans? (conj :humans)
|
||||
public? (conj :public-chats))
|
||||
global-access-scope (conj basic-access-scope :global)
|
||||
member-access-scopes (into #{} (map (comp (partial conj basic-access-scope) :identity))
|
||||
contacts)]
|
||||
(reduce (fn [acc access-scope]
|
||||
(merge acc (resolve-references all-contacts
|
||||
(get-in access-scope->commands-responses [access-scope type]))))
|
||||
{}
|
||||
(cons global-access-scope member-access-scopes))))
|
||||
|
||||
(defn- transform-commands-map
|
||||
"Transforms a map of commands to a flat list."
|
||||
[commands]
|
||||
(->> commands
|
||||
(map val)
|
||||
(remove empty?)
|
||||
(flatten)))
|
||||
|
||||
(defn get-possible-requests
|
||||
"Returns a list of all possible requests for current chat."
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(let [requests (->> (get-in db [:chats current-chat-id :requests])
|
||||
(map (fn [{:keys [type chat-id bot] :as req}]
|
||||
[type (map (fn [resp]
|
||||
(assoc resp :request req))
|
||||
(get-in db [:contacts/contacts (or bot chat-id) :responses type]))]))
|
||||
(remove (fn [[_ items]] (empty? items)))
|
||||
(into {}))]
|
||||
(transform-commands-map requests)))
|
||||
|
||||
(defn get-possible-commands
|
||||
"Returns a list of all possible commands for current chat."
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(->> (get-in db [:chats current-chat-id :contacts])
|
||||
(into (get-mixable-identities db))
|
||||
(map (fn [{:keys [identity]}]
|
||||
(let [commands (get-in db [:contacts/contacts identity :commands])]
|
||||
(transform-commands-map commands))))
|
||||
(flatten)))
|
||||
|
||||
(defn get-possible-global-commands
|
||||
"Returns a list of all possible global commands for current chat."
|
||||
[{:keys [global-commands] :as db}]
|
||||
(transform-commands-map global-commands))
|
||||
|
||||
(defn commands-for-chat
|
||||
"Returns a list of filtered commands for current chat.
|
||||
Uses scopes to filter commands."
|
||||
[{:keys [global-commands chats]
|
||||
:contacts/keys [contacts]
|
||||
:accounts/keys [accounts current-account-id]
|
||||
:as db} chat-id]
|
||||
(let [global-commands (get-possible-global-commands db)
|
||||
commands (get-possible-commands db)
|
||||
account (get accounts current-account-id)
|
||||
commands (-> (into [] global-commands)
|
||||
(into commands))
|
||||
{chat-contacts :contacts
|
||||
group-chat :group-chat} (get chats chat-id)]
|
||||
(remove (fn [{:keys [scope]}]
|
||||
(or
|
||||
(and (:registered-only? scope)
|
||||
(not (:address account)))
|
||||
(and (not (:personal-chats? scope))
|
||||
(not group-chat))
|
||||
(and (not (:group-chats? scope))
|
||||
group-chat)
|
||||
(and (not (:can-use-for-dapps? scope))
|
||||
(every? (fn [{:keys [identity]}]
|
||||
(get-in contacts [identity :dapp?]))
|
||||
chat-contacts))))
|
||||
commands)))
|
||||
|
||||
(defn- commands-list->map [commands]
|
||||
(->> commands
|
||||
(map #(vector (:name %) %))
|
||||
(into {})))
|
||||
|
||||
(defn replace-name-with-request
|
||||
"Sets the information about command for a specified request."
|
||||
([{:keys [content] :as message} commands requests]
|
||||
(if (map? content)
|
||||
(let [{:keys [command content-command]} content
|
||||
commands (commands-list->map commands)
|
||||
requests (commands-list->map requests)]
|
||||
(assoc content :command (or (get requests (or content-command command))
|
||||
(get commands command))))
|
||||
content))
|
||||
([message commands]
|
||||
(replace-name-with-request message commands [])))
|
||||
(defn requested-responses
|
||||
"Returns map of requested command responses eligible for current chat."
|
||||
[access-scope->commands-responses account chat contacts requests]
|
||||
(let [requested-responses (map :response requests)
|
||||
responses-map (commands-responses :response access-scope->commands-responses account chat contacts)]
|
||||
(select-keys responses-map requested-responses)))
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
(str/replace (str/trim command-text) #" +" " ")
|
||||
command-text)
|
||||
splitted (cond-> (str/split command-text-normalized const/spacing-char)
|
||||
space? (drop-last))]
|
||||
space? (drop-last))]
|
||||
(->> splitted
|
||||
(reduce (fn [[list command-started?] arg]
|
||||
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
|
||||
|
@ -104,28 +104,35 @@
|
|||
For instance, we can add a `:to-message-id` key to this map, and this key will allow us to identity
|
||||
the request we're responding to.
|
||||
* `:args` contains all arguments provided by user."
|
||||
([{:keys [current-chat-id] :as db} chat-id input-text]
|
||||
([{:keys [current-chat-id access-scope->commands-responses]
|
||||
:contacts/keys [contacts]
|
||||
:accounts/keys [accounts current-account-id] :as db} chat-id input-text]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
{:keys [input-metadata
|
||||
seq-arguments
|
||||
possible-requests
|
||||
possible-commands]} (get-in db [:chats chat-id])
|
||||
chat (get-in db [:chats chat-id])
|
||||
{:keys [input-metadata seq-arguments requests]} chat
|
||||
command-args (split-command-args input-text)
|
||||
command-name (first command-args)]
|
||||
(when (starts-as-command? (or command-name ""))
|
||||
(when-let [{{:keys [message-id]} :request :as command}
|
||||
(->> (into possible-requests possible-commands)
|
||||
(filter (fn [{:keys [name]}]
|
||||
(= name (subs command-name 1))))
|
||||
(first))]
|
||||
{:command command
|
||||
:metadata (if (and (nil? (:to-message-id input-metadata)) message-id)
|
||||
(assoc input-metadata :to-message-id message-id)
|
||||
input-metadata)
|
||||
:args (->> (if (empty? seq-arguments)
|
||||
(rest command-args)
|
||||
seq-arguments)
|
||||
(into []))}))))
|
||||
(let [account (get accounts current-account-id)
|
||||
available-commands-responses (merge (commands-model/commands-responses :command
|
||||
access-scope->commands-responses
|
||||
account
|
||||
chat
|
||||
contacts)
|
||||
(commands-model/requested-responses access-scope->commands-responses
|
||||
account
|
||||
chat
|
||||
contacts
|
||||
(vals requests)))]
|
||||
(when-let [{{:keys [message-id]} :request :as command} (get available-commands-responses (subs command-name 1))]
|
||||
{:command command
|
||||
:metadata (if (and (nil? (:to-message-id input-metadata)) message-id)
|
||||
(assoc input-metadata :to-message-id message-id)
|
||||
input-metadata)
|
||||
:args (->> (if (empty? seq-arguments)
|
||||
(rest command-args)
|
||||
seq-arguments)
|
||||
(into []))})))))
|
||||
([{:keys [current-chat-id] :as db} chat-id]
|
||||
(selected-chat-command db chat-id (get-in db [:chats chat-id :input-text]))))
|
||||
|
||||
|
@ -226,12 +233,12 @@
|
|||
prev-command (get-in db [:chat-ui-props current-chat-id :prev-command])]
|
||||
(if command
|
||||
(cond-> db
|
||||
;; clear the bot db
|
||||
(not= prev-command (-> command :command :name))
|
||||
(assoc-in [:bot-db (or (:bot command) current-chat-id)] nil)
|
||||
;; clear the chat's validation messages
|
||||
true
|
||||
(assoc-in [:chat-ui-props current-chat-id :validation-messages] nil))
|
||||
;; clear the bot db
|
||||
(not= prev-command (-> command :command :name))
|
||||
(assoc-in [:bot-db (or (:bot command) current-chat-id)] nil)
|
||||
;; clear the chat's validation messages
|
||||
true
|
||||
(assoc-in [:chat-ui-props current-chat-id :validation-messages] nil))
|
||||
(-> db
|
||||
;; clear input metadata
|
||||
(assoc-in [:chats current-chat-id :input-metadata] nil)
|
||||
|
|
|
@ -180,8 +180,7 @@
|
|||
show-emoji? [:chat-ui-props :show-emoji?]
|
||||
layout-height [:get :layout-height]
|
||||
input-text [:chat :input-text]]
|
||||
{:component-did-mount #(do (dispatch [:check-and-open-dapp!])
|
||||
(dispatch [:update-suggestions]))
|
||||
{:component-did-mount #(dispatch [:check-and-open-dapp!])
|
||||
:component-will-unmount #(dispatch [:set-chat-ui-props {:show-emoji? false}])}
|
||||
[view {:style st/chat-view
|
||||
:on-layout (fn [event]
|
||||
|
|
|
@ -85,41 +85,40 @@
|
|||
:to "me"}])
|
||||
|
||||
(defn passphrase-messages-events [mnemonic signing-phrase crazy-math-message?]
|
||||
(into [[:received-message
|
||||
{:message-id chat-const/passphrase-message-id
|
||||
:content (if crazy-math-message?
|
||||
(label :t/phew-here-is-your-passphrase)
|
||||
(label :t/here-is-your-passphrase))
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content mnemonic
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id chat-const/signing-phrase-message-id
|
||||
:content (label :t/here-is-your-signing-phrase)
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content signing-phrase
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]]
|
||||
start-signup-events))
|
||||
[[:received-message
|
||||
{:message-id chat-const/passphrase-message-id
|
||||
:content (if crazy-math-message?
|
||||
(label :t/phew-here-is-your-passphrase)
|
||||
(label :t/here-is-your-passphrase))
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content mnemonic
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id chat-const/signing-phrase-message-id
|
||||
:content (label :t/here-is-your-signing-phrase)
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]
|
||||
[:received-message
|
||||
{:message-id (random/id)
|
||||
:content signing-phrase
|
||||
:content-type const/text-content-type
|
||||
:outgoing false
|
||||
:chat-id const/console-chat-id
|
||||
:from const/console-chat-id
|
||||
:to "me"}]])
|
||||
|
||||
(def intro-status
|
||||
{:message-id chat-const/intro-status-message-id
|
||||
|
@ -162,5 +161,4 @@
|
|||
:photo-path const/console-chat-id
|
||||
:dapp? true
|
||||
:unremovable? true
|
||||
:bot-url "local://console-bot"
|
||||
:dapp-hash 858845357})
|
||||
:bot-url "local://console-bot"})
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
(s/def :chat/chat-list-ui-props (s/nilable map?))
|
||||
(s/def :chat/layout-height (s/nilable number?)) ;;height of chat's view layout
|
||||
(s/def :chat/expandable-view-height-to-value (s/nilable number?))
|
||||
(s/def :chat/global-commands (s/nilable map?)) ; {key (keyword) command (map)} atm used for browse command
|
||||
(s/def :chat/loading-allowed (s/nilable boolean?)) ;;allow to load more messages
|
||||
(s/def :chat/handler-data (s/nilable map?))
|
||||
(s/def :chat/message-data (s/nilable map?))
|
||||
|
@ -18,15 +17,12 @@
|
|||
(s/def :chat/message-status (s/nilable map?))
|
||||
(s/def :chat/unviewed-messages (s/nilable map?))
|
||||
(s/def :chat/selected-participants (s/nilable set?))
|
||||
(s/def :chat/chat-loaded-callbacks (s/nilable map?))
|
||||
(s/def :chat/commands-callbacks (s/nilable map?))
|
||||
(s/def :chat/chat-loaded-callbacks (s/nilable map?))
|
||||
(s/def :chat/command-hash-valid? (s/nilable boolean?))
|
||||
(s/def :chat/public-group-topic (s/nilable string?))
|
||||
(s/def :chat/confirmation-code-sms-listener (s/nilable any?)) ; .addListener result object
|
||||
(s/def :chat/messages (s/nilable seq?))
|
||||
(s/def :chat/loaded-chats (s/nilable seq?))
|
||||
(s/def :chat/bot-subscriptions (s/nilable map?))
|
||||
(s/def :chat/new-request (s/nilable map?))
|
||||
(s/def :chat/loaded-chats (s/nilable seq?))
|
||||
(s/def :chat/raw-unviewed-messages (s/nilable vector?))
|
||||
(s/def :chat/bot-db (s/nilable map?))
|
||||
(s/def :chat/geolocation (s/nilable map?))
|
||||
|
|
|
@ -38,13 +38,11 @@
|
|||
(:chats db)))
|
||||
|
||||
(reg-sub
|
||||
:chat-actions
|
||||
:get-current-chat
|
||||
:<- [:chats]
|
||||
:<- [:get-current-chat-id]
|
||||
:<- [:chat :input-text]
|
||||
(fn [[chats current-chat-id text] [_ type chat-id]]
|
||||
(->> (get-in chats [(or chat-id current-chat-id) type])
|
||||
(filter #(or (str/includes? (chat-utils/command-name %) (or text "")))))))
|
||||
(fn [[chats id]]
|
||||
(get chats id)))
|
||||
|
||||
(reg-sub
|
||||
:chat
|
||||
|
@ -53,18 +51,50 @@
|
|||
(fn [[chats id] [_ k chat-id]]
|
||||
(get-in chats [(or chat-id id) k])))
|
||||
|
||||
(defn get-suggested-commands
|
||||
[[commands requests]]
|
||||
(let [vec->map-by-name #(into {} (map vector (map :name %) %))
|
||||
commands-map (vec->map-by-name commands)
|
||||
requests-map (vec->map-by-name requests)]
|
||||
(vals (merge commands-map requests-map))))
|
||||
(reg-sub
|
||||
:get-commands-for-chat
|
||||
:<- [:get-commands-responses-by-access-scope]
|
||||
:<- [:get-current-account]
|
||||
:<- [:get-current-chat]
|
||||
:<- [:get-contacts]
|
||||
(fn [[commands-responses account chat contacts]]
|
||||
(commands-model/commands-responses :command commands-responses account chat contacts)))
|
||||
|
||||
(reg-sub
|
||||
:get-suggested-commands
|
||||
:<- [:chat :possible-commands]
|
||||
:<- [:chat :possible-requests]
|
||||
get-suggested-commands)
|
||||
:get-responses-for-chat
|
||||
:<- [:get-commands-responses-by-access-scope]
|
||||
:<- [:get-current-account]
|
||||
:<- [:get-current-chat]
|
||||
:<- [:get-contacts]
|
||||
:<- [:chat :requests]
|
||||
(fn [[commands-responses account chat contacts requests]]
|
||||
(commands-model/requested-responses commands-responses account chat contacts (vals requests))))
|
||||
|
||||
(def ^:private map->sorted-seq (comp (partial map second) (partial sort-by first)))
|
||||
|
||||
(defn- available-commands-responses [[commands-responses input-text]]
|
||||
(->> commands-responses
|
||||
map->sorted-seq
|
||||
(filter #(str/includes? (chat-utils/command-name %) (or input-text "")))))
|
||||
|
||||
(reg-sub
|
||||
:get-available-commands
|
||||
:<- [:get-commands-for-chat]
|
||||
:<- [:chat :input-text]
|
||||
available-commands-responses)
|
||||
|
||||
(reg-sub
|
||||
:get-available-responses
|
||||
:<- [:get-responses-for-chat]
|
||||
:<- [:chat :input-text]
|
||||
available-commands-responses)
|
||||
|
||||
(reg-sub
|
||||
:get-available-commands-responses
|
||||
:<- [:get-commands-for-chat]
|
||||
:<- [:get-responses-for-chat]
|
||||
(fn [[commands responses]]
|
||||
(map->sorted-seq (merge commands responses))))
|
||||
|
||||
(reg-sub
|
||||
:get-current-chat-id
|
||||
|
@ -76,10 +106,6 @@
|
|||
(fn [_ [_ chat-id]]
|
||||
(chats/get-by-id chat-id)))
|
||||
|
||||
(reg-sub :get-commands-for-chat
|
||||
(fn [db [_ chat-id]]
|
||||
(commands-model/commands-for-chat db chat-id)))
|
||||
|
||||
(reg-sub
|
||||
:selected-chat-command
|
||||
(fn [db [_ chat-id]]
|
||||
|
@ -89,12 +115,12 @@
|
|||
|
||||
(reg-sub
|
||||
:current-chat-argument-position
|
||||
(fn [db]
|
||||
(let [command (subscribe [:selected-chat-command])
|
||||
input-text (subscribe [:chat :input-text])
|
||||
seq-arguments (subscribe [:chat :seq-arguments])
|
||||
selection (subscribe [:chat-ui-props :selection])]
|
||||
(input-model/current-chat-argument-position @command @input-text @selection @seq-arguments))))
|
||||
:<- [:selected-chat-command]
|
||||
:<- [:chat :input-text]
|
||||
:<- [:chat :seq-arguments]
|
||||
:<- [:chat-ui-props :selection]
|
||||
(fn [[command input-text seq-arguments selection]]
|
||||
(input-model/current-chat-argument-position command input-text selection seq-arguments)))
|
||||
|
||||
(reg-sub
|
||||
:chat-parameter-box
|
||||
|
@ -132,21 +158,14 @@
|
|||
(reg-sub
|
||||
:show-suggestions?
|
||||
(fn [db [_ chat-id]]
|
||||
(let [chat-id (or chat-id (db :current-chat-id))
|
||||
show-suggestions? (subscribe [:chat-ui-props :show-suggestions? chat-id])
|
||||
input-text (subscribe [:chat :input-text chat-id])
|
||||
selected-command (subscribe [:selected-chat-command chat-id])
|
||||
requests (subscribe [:chat :possible-requests chat-id])
|
||||
commands (subscribe [:chat :possible-commands chat-id])]
|
||||
(let [chat-id (or chat-id (db :current-chat-id))
|
||||
show-suggestions? (subscribe [:chat-ui-props :show-suggestions? chat-id])
|
||||
input-text (subscribe [:chat :input-text chat-id])
|
||||
selected-command (subscribe [:selected-chat-command chat-id])
|
||||
commands-responses (subscribe [:get-available-commands-responses])]
|
||||
(and (or @show-suggestions? (input-model/starts-as-command? (str/trim (or @input-text ""))))
|
||||
(not (:command @selected-command))
|
||||
(or (not-empty @requests)
|
||||
(not-empty @commands))))))
|
||||
|
||||
(reg-sub :get-current-chat
|
||||
(fn [db]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
(get-in db [:chats current-chat-id]))))
|
||||
(seq @commands-responses)))))
|
||||
|
||||
(reg-sub :get-chat
|
||||
(fn [db [_ chat-id]]
|
||||
|
@ -160,7 +179,7 @@
|
|||
(reg-sub :is-request-answered?
|
||||
:<- [:chat :requests]
|
||||
(fn [requests [_ message-id]]
|
||||
(not-any? #(= message-id (:message-id %)) requests)))
|
||||
(not= "open" (get-in requests [message-id :status]))))
|
||||
|
||||
(reg-sub :unviewed-messages-count
|
||||
(fn [db [_ chat-id]]
|
||||
|
|
|
@ -38,11 +38,6 @@
|
|||
(let [previous-message (first (get-in db [:chats chat-id :messages]))]
|
||||
(check-message previous-message message))))
|
||||
|
||||
(defn command-valid? [message validator]
|
||||
(if validator
|
||||
(validator message)
|
||||
(pos? (count message))))
|
||||
|
||||
(defn command-name [{:keys [bot name scope]}]
|
||||
(cond
|
||||
(:global? scope)
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
(chat-utils/command-name command)]]])
|
||||
|
||||
(defview commands-view []
|
||||
[all-commands [:get-suggested-commands]
|
||||
[all-commands-responses [:get-available-commands-responses]
|
||||
show-suggestions? [:show-suggestions?]]
|
||||
[view style/commands-root
|
||||
[view style/command-list-icon-container
|
||||
|
@ -48,7 +48,7 @@
|
|||
:showsHorizontalScrollIndicator false
|
||||
:keyboardShouldPersistTaps :always}
|
||||
[view style/commands
|
||||
(for [[index command] (map-indexed vector all-commands)]
|
||||
(for [[index command] (map-indexed vector all-commands-responses)]
|
||||
^{:key (str "command-" index)}
|
||||
[command-view (= index 0) command])]]])
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.ui.components.react :refer [view
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
text
|
||||
icon]]
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
text
|
||||
icon]]
|
||||
[status-im.data-store.messages :as messages]
|
||||
[status-im.chat.styles.input.suggestions :as style]
|
||||
[status-im.chat.constants :as const]
|
||||
|
@ -25,8 +25,8 @@
|
|||
:number-of-lines 2}
|
||||
description]]])
|
||||
|
||||
(defview request-item [{:keys [name description]
|
||||
{:keys [type message-id]} :request :as command} last?]
|
||||
(defview response-item [{:keys [name description]
|
||||
{:keys [type message-id]} :request :as command} last?]
|
||||
[{:keys [chat-id]} [:get-current-chat]]
|
||||
[suggestion-item
|
||||
{:on-press #(let [{:keys [params]} (messages/get-message-content-by-id message-id)
|
||||
|
@ -50,25 +50,23 @@
|
|||
|
||||
(defview suggestions-view []
|
||||
[show-suggestions? [:show-suggestions?]
|
||||
requests [:chat-actions :possible-requests]
|
||||
commands [:chat-actions :possible-commands]]
|
||||
responses [:get-available-responses]
|
||||
commands [:get-available-commands]]
|
||||
(when show-suggestions?
|
||||
[expandable-view {:key :suggestions
|
||||
:draggable? false
|
||||
:height 212}
|
||||
[view {:flex 1}
|
||||
[scroll-view {:keyboardShouldPersistTaps :always}
|
||||
(when (seq requests)
|
||||
(when (seq responses)
|
||||
[view
|
||||
[item-title false (label :t/suggestions-requests)]
|
||||
(for [[i {{:keys [chat-id message-id]} :request :as request}] (map-indexed vector requests)]
|
||||
^{:key [chat-id message-id]}
|
||||
[request-item request (= i (dec (count requests)))])])
|
||||
(for [[i response] (map-indexed vector responses)]
|
||||
^{:key i}
|
||||
[response-item response (= i (dec (count responses)))])])
|
||||
(when (seq commands)
|
||||
[view
|
||||
[item-title (seq requests) (label :t/suggestions-commands)]
|
||||
(for [[i command] (->> commands
|
||||
(remove #(nil? (:title %)))
|
||||
(map-indexed vector))]
|
||||
[item-title (seq responses) (label :t/suggestions-commands)]
|
||||
(for [[i command] (map-indexed vector commands)]
|
||||
^{:key i}
|
||||
[command-item command (= i (dec (count commands)))])])]]]))
|
||||
|
|
|
@ -121,12 +121,11 @@
|
|||
|
||||
(defview message-content-command
|
||||
[{:keys [message-id content content-type chat-id to from outgoing] :as message}]
|
||||
(letsubs [commands [:get-commands-for-chat chat-id]
|
||||
(letsubs [command [:get-command (:content-command-ref content)]
|
||||
current-chat-id [:get-current-chat-id]
|
||||
contact-chat [:get-in [:chats (if outgoing to from)]]
|
||||
preview [:get-message-preview message-id]]
|
||||
(let [{:keys [command params]} (commands/replace-name-with-request message commands)
|
||||
{:keys [name type]
|
||||
(let [{:keys [name type]
|
||||
icon-path :icon} command]
|
||||
[view st/content-command-view
|
||||
(when (:color command)
|
||||
|
@ -134,13 +133,13 @@
|
|||
[view (pill-st/pill command)
|
||||
[text {:style pill-st/pill-text
|
||||
:font :default}
|
||||
(str (if (= :command type) chat-consts/command-char "?") name)]]])
|
||||
(str chat-consts/command-char name)]]])
|
||||
(when icon-path
|
||||
[view st/command-image-view
|
||||
[icon icon-path st/command-image]])
|
||||
[command-preview {:command (:name command)
|
||||
:content-type content-type
|
||||
:params params
|
||||
:params (:params content)
|
||||
:outgoing? outgoing
|
||||
:preview preview
|
||||
:contact-chat contact-chat
|
||||
|
@ -285,7 +284,7 @@
|
|||
(defview message-delivery-status
|
||||
[{:keys [message-id chat-id message-status user-statuses content]}]
|
||||
[app-db-message-status-value [:get-in [:message-data :statuses message-id :status]]]
|
||||
(let [delivery-status (get-in user-statuses [chat-id :status])
|
||||
(let [delivery-status (get-in user-statuses [chat-id :status])
|
||||
status (cond (and (not (console/commands-with-delivery-status (:command content)))
|
||||
(cu/console? chat-id))
|
||||
:seen
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.ui.components.react :refer [view
|
||||
animated-view
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight]]
|
||||
animated-view
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight]]
|
||||
[status-im.chat.styles.message.message :as st]
|
||||
[status-im.chat.models.commands :as commands]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
|
@ -25,9 +25,9 @@
|
|||
(defn button-animation [val to-value loop? answered?]
|
||||
(anim/anim-sequence
|
||||
[(anim/anim-delay
|
||||
(if (and @loop? (not @answered?))
|
||||
request-message-icon-scale-delay
|
||||
0))
|
||||
(if (and @loop? (not @answered?))
|
||||
request-message-icon-scale-delay
|
||||
0))
|
||||
(anim/spring val {:toValue to-value})]))
|
||||
|
||||
(defn request-button-animation-logic
|
||||
|
@ -73,14 +73,12 @@
|
|||
|
||||
(defview message-content-command-request
|
||||
[{:keys [message-id chat-id content from incoming-group] :as message}]
|
||||
(letsubs [commands [:get-commands-for-chat chat-id]
|
||||
requests [:chat-actions :possible-requests]
|
||||
(letsubs [command [:get-command (:content-command-ref content)]
|
||||
answered? [:is-request-answered? message-id]
|
||||
status-initialized? [:get :status-module-initialized?]
|
||||
markup [:get-message-preview message-id]]
|
||||
(let [{:keys [prefill prefill-bot-db prefillBotDb params]
|
||||
text-content :text} content
|
||||
{:keys [command content]} (commands/replace-name-with-request message commands requests)
|
||||
text-content :text} content
|
||||
command (if (and params command)
|
||||
(merge command {:prefill prefill
|
||||
:prefill-bot-db (or prefill-bot-db prefillBotDb)})
|
||||
|
@ -98,7 +96,7 @@
|
|||
[view markup]
|
||||
[text {:style st/style-message-text
|
||||
:font :default}
|
||||
(or text-content markup content)])]]
|
||||
(or text-content markup (:content content))])]]
|
||||
(when (:request-text command)
|
||||
[view st/command-request-text-view
|
||||
[text {:style st/style-sub-text
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
(ns status-im.commands.events.loading
|
||||
(:require [clojure.string :as string]
|
||||
[clojure.set :as s]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.js-resources :as js-resources]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.data-store.local-storage :as local-storage]
|
||||
[status-im.bots.events :as bots-events]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;; COFX
|
||||
(re-frame/reg-cofx
|
||||
:get-local-storage-data
|
||||
(fn [cofx]
|
||||
(assoc cofx :get-local-storage-data local-storage/get-data)))
|
||||
|
||||
;; FX
|
||||
(re-frame/reg-fx
|
||||
::evaluate-jail-n
|
||||
(fn [jail-data]
|
||||
(doseq [{:keys [jail-id jail-resource]} jail-data]
|
||||
(status/parse-jail
|
||||
jail-id jail-resource
|
||||
(fn [jail-response]
|
||||
(re-frame/dispatch [::proceed-loading jail-id (types/json->clj jail-response)]))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::show-popup
|
||||
(fn [{:keys [title msg]}]
|
||||
(utils/show-popup title msg)))
|
||||
|
||||
;; Handlers
|
||||
(defn- valid-network-resource?
|
||||
[response]
|
||||
(some-> (.. response -headers)
|
||||
(get "Content-type")
|
||||
(string/includes? "application/javascript")))
|
||||
|
||||
(defn- evaluate-commands-in-jail
|
||||
[{:keys [db get-local-storage-data]} commands-resource whisper-identity]
|
||||
(let [data (get-local-storage-data whisper-identity)
|
||||
local-storage-snippet (js-resources/local-storage-data data)
|
||||
network-id (get-in db [:networks/networks (:network db) :raw-config :NetworkId])
|
||||
ethereum-id-snippet (js-resources/network-id network-id)
|
||||
commands-snippet (str local-storage-snippet ethereum-id-snippet commands-resource)]
|
||||
{::evaluate-jail-n [{:jail-id whisper-identity
|
||||
:jail-resource commands-snippet}]}))
|
||||
|
||||
(defn load-commands
|
||||
"This function takes coeffects, effects and contact and adds effects
|
||||
for loading all commands/responses/subscriptions.
|
||||
|
||||
It's currently working only for bots, eq we are not evaluating
|
||||
dapp resources in jail at all."
|
||||
[cofx fx {:keys [whisper-identity bot-url]}]
|
||||
(if bot-url
|
||||
(if-let [commands-resource (js-resources/get-resource bot-url)]
|
||||
(merge-with into fx (evaluate-commands-in-jail cofx commands-resource whisper-identity))
|
||||
(update fx :http-get-n conj {:url bot-url
|
||||
:response-validator valid-network-resource?
|
||||
:success-event-creator (fn [commands-resource]
|
||||
[::evaluate-commands-in-jail commands-resource whisper-identity])
|
||||
:failure-event-creator (fn [error-response]
|
||||
[::proceed-loading whisper-identity {:error error-response}])}))
|
||||
fx))
|
||||
|
||||
(defn- add-exclusive-choices [initial-scope exclusive-choices]
|
||||
(reduce (fn [scopes-set exclusive-choices]
|
||||
(reduce (fn [scopes-set scope]
|
||||
(let [exclusive-match (s/intersection scope exclusive-choices)]
|
||||
(if (seq exclusive-match)
|
||||
(reduce conj
|
||||
(disj scopes-set scope)
|
||||
(map (partial conj (s/difference scope exclusive-match))
|
||||
exclusive-match))
|
||||
scopes-set)))
|
||||
scopes-set
|
||||
scopes-set))
|
||||
#{initial-scope}
|
||||
exclusive-choices))
|
||||
|
||||
(defn- create-access-scopes
|
||||
"Based on command owner and command scope, create set of access-scopes which can be used to directly
|
||||
look up any commands/subscriptions relevant for actual context (type of chat opened, registered user
|
||||
or not, etc.)"
|
||||
[jail-id scope]
|
||||
(let [member-scope (cond-> scope
|
||||
(not (scope :global)) (conj jail-id))]
|
||||
(add-exclusive-choices member-scope [#{:personal-chats :group-chats}
|
||||
#{:anonymous :registered}
|
||||
#{:dapps :humans :public-chats}])))
|
||||
|
||||
(defn- index-by-access-scope-type
|
||||
[init jail-id items]
|
||||
(reduce (fn [acc {:keys [scope name type ref]}]
|
||||
(let [access-scopes (create-access-scopes jail-id scope)]
|
||||
(reduce (fn [acc access-scope]
|
||||
(assoc-in acc [access-scope type name] ref))
|
||||
acc
|
||||
access-scopes)))
|
||||
init
|
||||
items))
|
||||
|
||||
(defn- enrich
|
||||
[jail-id type [_ {:keys [scope-bitmask scope name] :as props}]]
|
||||
(-> props
|
||||
(assoc :scope (into #{} (map keyword) scope)
|
||||
:owner-id jail-id
|
||||
:bot jail-id
|
||||
:type type
|
||||
:ref [jail-id type scope-bitmask name])))
|
||||
|
||||
(defn add-jail-result
|
||||
"This function add commands/responses/subscriptions from jail-evaluated resource
|
||||
into the database"
|
||||
[db jail-id {:keys [commands responses subscriptions]}]
|
||||
(let [enriched-commands (map (partial enrich jail-id :command) commands)
|
||||
enriched-responses (map (partial enrich jail-id :response) responses)
|
||||
new-db (reduce (fn [acc {:keys [ref] :as props}]
|
||||
(assoc-in acc (into [:contacts/contacts] ref) props))
|
||||
db
|
||||
(concat enriched-commands enriched-responses))]
|
||||
(-> new-db
|
||||
(update :access-scope->commands-responses (fn [acc]
|
||||
(-> (or acc {})
|
||||
(index-by-access-scope-type jail-id enriched-commands)
|
||||
(index-by-access-scope-type jail-id enriched-responses))))
|
||||
(update-in [:contacts/contacts jail-id] assoc
|
||||
:subscriptions (bots-events/transform-bot-subscriptions subscriptions)
|
||||
:jail-loaded? true))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::evaluate-commands-in-jail
|
||||
[re-frame/trim-v (re-frame/inject-cofx :get-local-storage-data)]
|
||||
(fn [cofx [commands-resource whisper-identity]]
|
||||
(evaluate-commands-in-jail cofx commands-resource whisper-identity)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::proceed-loading
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [jail-id {:keys [error result]}]]
|
||||
(if error
|
||||
(let [message (string/join "\n" ["bot.js loading failed"
|
||||
jail-id
|
||||
error])]
|
||||
{::show-popup {:title "Error"
|
||||
:msg message}})
|
||||
(let [jail-loaded-events (get-in db [:contacts/contacts jail-id :jail-loaded-events])]
|
||||
(cond-> {:db (add-jail-result db jail-id result)
|
||||
:call-jail-function {:chat-id jail-id
|
||||
:function :init :context
|
||||
{:from (:accounts/current-account-id db)}}}
|
||||
(seq jail-loaded-events)
|
||||
(-> (assoc :dispatch-n jail-loaded-events)
|
||||
(update-in [:db :contacts/contacts jail-id] dissoc :jail-loaded-events)))))))
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.commands.handlers.debug
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.commands.events.loading :as loading-events]
|
||||
[status-im.data-store.accounts :as accounts]
|
||||
[status-im.data-store.messages :as messages]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
|
@ -84,8 +85,9 @@
|
|||
(when (and (= current-chat-id whisper-identity)
|
||||
webview-bridge)
|
||||
(.reload webview-bridge))
|
||||
(when (get-in contacts [whisper-identity :bot-url])
|
||||
(re-frame/dispatch [:load-commands! whisper-identity])))
|
||||
(when-let [bot-url (get-in contacts [whisper-identity :bot-url])]
|
||||
(re-frame/dispatch [::load-commands! {:whisper-identity whisper-identity
|
||||
:bot-url bot-url}])))
|
||||
(respond {:type :ok
|
||||
:text "Command has been executed."}))
|
||||
|
||||
|
@ -172,4 +174,10 @@
|
|||
(fn [{:keys [db]} [url post-data]]
|
||||
{::process-request-fx [db url post-data]}))
|
||||
|
||||
;; TODO(janherich) once `contact-changed` fn is refactored, get rid of this unnecessary event
|
||||
(handlers/register-handler-fx
|
||||
::load-commands
|
||||
[re-frame/trim-v (re-frame/inject-cofx :get-local-storage-data)]
|
||||
(fn [cofx [contact]]
|
||||
(loading-events/load-commands cofx {} contact)))
|
||||
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
(ns status-im.commands.handlers.loading
|
||||
(:require [re-frame.core :refer [path after dispatch subscribe trim-v debug]]
|
||||
[status-im.utils.handlers :as u]
|
||||
[status-im.utils.utils :refer [http-get show-popup]]
|
||||
[clojure.string :as s]
|
||||
[status-im.data-store.contacts :as contacts]
|
||||
[status-im.data-store.local-storage :as local-storage]
|
||||
[status-im.commands.utils :refer [reg-handler]]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.chat.models.commands :as commands-model]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.homoglyph :as h]
|
||||
[status-im.utils.js-resources :as js-res]
|
||||
[status-im.utils.types :as types]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
|
||||
(defn load-commands!
|
||||
[{:keys [current-chat-id chats]
|
||||
:contacts/keys [contacts]} [jail-id callback]]
|
||||
(let [identity (or jail-id current-chat-id)
|
||||
contact-ids (if (get contacts identity)
|
||||
[identity]
|
||||
(->> (get-in chats [identity :contacts])
|
||||
(map :identity)
|
||||
(into [])))]
|
||||
(when (seq contacts)
|
||||
(doseq [contact-id contact-ids]
|
||||
(when-let [contact (get contacts contact-id)]
|
||||
(dispatch [::fetch-commands! {:contact contact
|
||||
:callback callback}]))))))
|
||||
|
||||
(defn http-get-commands [params url]
|
||||
(http-get url
|
||||
(fn [response]
|
||||
(when-let [content-type (.. response -headers (get "Content-Type"))]
|
||||
(s/includes? content-type "application/javascript")))
|
||||
#(dispatch [::validate-hash params %])
|
||||
#(log/debug (str "command.js wasn't found at " url))))
|
||||
|
||||
|
||||
(defn fetch-commands!
|
||||
[_ [{{:keys [whisper-identity
|
||||
dapp-url
|
||||
bot-url
|
||||
dapp?]} :contact
|
||||
callback :callback
|
||||
:as params}]]
|
||||
(if bot-url
|
||||
(if-let [resource (js-res/get-resource bot-url)]
|
||||
(dispatch [::validate-hash params resource])
|
||||
(http-get-commands params bot-url))
|
||||
(when callback (callback))))
|
||||
|
||||
(defn dispatch-loaded!
|
||||
[db [{{:keys [whisper-identity]} :contact
|
||||
:as params} file]]
|
||||
(if (:command-hash-valid? db)
|
||||
(dispatch [::parse-commands! params file])
|
||||
(dispatch [::loading-failed! whisper-identity ::wrong-hash])))
|
||||
|
||||
(defn get-hash-by-identity
|
||||
[db identity]
|
||||
(get-in db [:contacts/contacts identity :dapp-hash]))
|
||||
|
||||
(defn get-hash-by-file
|
||||
[file]
|
||||
;; todo tbd hashing algorithm
|
||||
(hash file))
|
||||
|
||||
(defn parse-commands!
|
||||
[{:networks/keys [networks]
|
||||
:keys [network]
|
||||
:as db}
|
||||
[{{:keys [whisper-identity]} :contact
|
||||
:keys [callback]}
|
||||
file]]
|
||||
(let [data (local-storage/get-data whisper-identity)
|
||||
local-storage-js (js-res/local-storage-data data)
|
||||
network-id (get-in networks [network :raw-config :NetworkId])
|
||||
ethereum-id-js (js-res/network-id network-id)]
|
||||
(status/parse-jail
|
||||
whisper-identity (str local-storage-js ethereum-id-js file)
|
||||
(fn [result]
|
||||
(let [{:keys [error result]} (types/json->clj result)]
|
||||
(log/debug "Parsing commands results: " error result)
|
||||
(if error
|
||||
(dispatch [::loading-failed! whisper-identity ::error-in-jail error])
|
||||
(do
|
||||
(dispatch [::add-commands whisper-identity file result])
|
||||
(when callback (callback)))))))))
|
||||
|
||||
(defn validate-hash
|
||||
[db [_ file]]
|
||||
(let [valid? true
|
||||
;; todo check
|
||||
#_(= (get-hash-by-identity db identity)
|
||||
(get-hash-by-file file))]
|
||||
(assoc db :command-hash-valid? valid?)))
|
||||
|
||||
(defn each-merge [with coll]
|
||||
(->> coll
|
||||
(map (fn [[k v]] [k (merge v with)]))
|
||||
(into {})))
|
||||
|
||||
(defn extract-commands [{:keys [contacts]} commands]
|
||||
(->> commands
|
||||
(remove (fn [[_ {:keys [name]}]]
|
||||
(and (= (count contacts) 1)
|
||||
(not= console-chat-id (get (first contacts) :identity))
|
||||
(h/matches name "password"))))
|
||||
(map (fn [[k {:keys [name scope] :as v}]]
|
||||
[[name scope] v]))
|
||||
(into {})))
|
||||
|
||||
(defn extract-global-commands [commands chat-id]
|
||||
(->> commands
|
||||
(filter (fn [[_ {:keys [scope]}]]
|
||||
(:global? scope)))
|
||||
(map (fn [[k {:keys [name scope] :as v}]]
|
||||
[[name scope] (assoc v :bot chat-id :type :command)]))
|
||||
(into {})))
|
||||
|
||||
(defn transform-commands [commands]
|
||||
(reduce (fn [m [_ {:keys [name scope] :as v}]]
|
||||
(update m (keyword name) conj v))
|
||||
{}
|
||||
commands))
|
||||
|
||||
(defn add-commands
|
||||
[{:keys [current-account-id accounts chats] :as db}
|
||||
[id _ {:keys [commands responses subscriptions]}]]
|
||||
(let [account (get accounts current-account-id)
|
||||
chat (get chats id)
|
||||
global-commands (extract-global-commands commands id)
|
||||
mixable-commands (when-not (get-in db [:contacts/contacts id :mixable?])
|
||||
(commands-model/get-mixable-commands db))
|
||||
commands' (->> (apply dissoc commands (keys global-commands))
|
||||
(extract-commands chat)
|
||||
(each-merge {:type :command
|
||||
:owner-id id})
|
||||
(transform-commands)
|
||||
(merge mixable-commands))
|
||||
responses' (->> (extract-commands chat responses)
|
||||
(each-merge {:type :response
|
||||
:owner-id id})
|
||||
(transform-commands))
|
||||
new-db (-> db
|
||||
(update-in [:contacts/contacts id] assoc
|
||||
:commands-loaded? true
|
||||
:commands commands'
|
||||
:responses responses'
|
||||
:subscriptions subscriptions)
|
||||
(update :global-commands merge (transform-commands global-commands)))]
|
||||
new-db))
|
||||
|
||||
(defn loading-failed!
|
||||
[db [id reason details]]
|
||||
(let [url (get-in db [:chats id :dapp-url])]
|
||||
(let [m (s/join "\n" ["commands.js loading failed"
|
||||
url
|
||||
id
|
||||
(name reason)
|
||||
details])]
|
||||
(show-popup "Error" m)
|
||||
(log/debug m))))
|
||||
|
||||
(reg-handler :check-and-load-commands!
|
||||
(u/side-effect!
|
||||
(fn [{:contacts/keys [contacts]} [identity callback]]
|
||||
(if (get-in contacts [identity :commands-loaded?])
|
||||
(callback)
|
||||
(dispatch [:load-commands! identity callback])))))
|
||||
|
||||
(reg-handler :load-commands! (u/side-effect! load-commands!))
|
||||
(reg-handler ::fetch-commands! (u/side-effect! fetch-commands!))
|
||||
|
||||
(reg-handler ::validate-hash
|
||||
(after dispatch-loaded!)
|
||||
validate-hash)
|
||||
|
||||
(reg-handler ::parse-commands! (u/side-effect! parse-commands!))
|
||||
|
||||
(reg-handler ::add-commands
|
||||
(after (fn [_ [id]]
|
||||
(dispatch [:invoke-commands-loading-callbacks id])
|
||||
(dispatch [:update-suggestions])))
|
||||
add-commands)
|
||||
|
||||
(reg-handler ::loading-failed! (u/side-effect! loading-failed!))
|
||||
|
||||
(reg-handler :add-commands-loading-callback
|
||||
(fn [db [chat-id callback]]
|
||||
(update-in db [:commands-callbacks chat-id] conj callback)))
|
||||
|
||||
(reg-handler :invoke-commands-loading-callbacks
|
||||
(u/side-effect!
|
||||
(fn [db [chat-id]]
|
||||
(let [callbacks (get-in db [:commands-callbacks chat-id])]
|
||||
(doseq [callback callbacks]
|
||||
(callback))
|
||||
(dispatch [::clear-commands-callbacks chat-id])))))
|
||||
|
||||
(reg-handler ::clear-commands-callbacks
|
||||
(fn [db [chat-id]]
|
||||
(assoc-in db [:commands-callbacks chat-id] nil)))
|
|
@ -0,0 +1,4 @@
|
|||
(ns status-im.commands.specs
|
||||
(:require [cljs.spec.alpha :as spec]))
|
||||
|
||||
(spec/def :commands/access-scope->commands-responses (spec/nilable map?))
|
|
@ -0,0 +1,13 @@
|
|||
(ns status-im.commands.subs
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
(reg-sub
|
||||
:get-commands-responses-by-access-scope
|
||||
(fn [db _]
|
||||
(:access-scope->commands-responses db)))
|
||||
|
||||
(reg-sub
|
||||
:get-command
|
||||
:<- [:get-contacts]
|
||||
(fn [contacts [_ ref]]
|
||||
(some->> ref (get-in contacts))))
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.data-store.chats
|
||||
(:require [status-im.data-store.realm.chats :as data-store]
|
||||
[re-frame.core :refer [dispatch]])
|
||||
(:require [status-im.data-store.realm.chats :as data-store])
|
||||
(:refer-clojure :exclude [exists?]))
|
||||
|
||||
(defn- normalize-contacts
|
||||
|
@ -43,8 +42,7 @@
|
|||
|
||||
(defn add-contacts
|
||||
[chat-id identities]
|
||||
(data-store/add-contacts chat-id identities)
|
||||
(dispatch [:reload-chats]))
|
||||
(data-store/add-contacts chat-id identities))
|
||||
|
||||
(defn remove-contacts
|
||||
[chat-id identities]
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
(assoc :pending? (boolean (if contact-db
|
||||
(if (nil? pending?) pending-db? pending?)
|
||||
pending?)))
|
||||
(dissoc :commands :responses :global-command))]
|
||||
(dissoc :command :response :subscriptions :jail-loaded-events))]
|
||||
(data-store/save contact' (boolean contact-db))))
|
||||
|
||||
(defn save-all
|
||||
|
|
|
@ -1,45 +1,16 @@
|
|||
(ns status-im.data-store.realm.requests
|
||||
(:require [status-im.data-store.realm.core :as realm]))
|
||||
|
||||
(defn get-all
|
||||
(defn get-all-unanswered
|
||||
[]
|
||||
(realm/get-all @realm/account-realm :request))
|
||||
|
||||
(defn get-all-as-list
|
||||
[]
|
||||
(realm/js-object->clj (get-all)))
|
||||
|
||||
(defn get-open-by-chat-id
|
||||
[chat-id]
|
||||
(-> (realm/get-by-fields @realm/account-realm :request :and [[:chat-id chat-id]
|
||||
[:status "open"]])
|
||||
(realm/sorted :added :desc)
|
||||
(-> @realm/account-realm
|
||||
(realm/get-by-field :request :status "open")
|
||||
realm/js-object->clj))
|
||||
|
||||
;; NOTE(oskarth): phone command in Console can be answered again, so we want to list this
|
||||
;; TODO(oskarth): Refactor this, either by extending and/or query or changing status of message
|
||||
(defn- get-reanswerable-by-chat-id
|
||||
[chat-id]
|
||||
(-> (realm/get-by-fields @realm/account-realm :request :and [[:chat-id chat-id]
|
||||
[:type "phone"]
|
||||
[:status "answered"]])
|
||||
(realm/sorted :added :desc)
|
||||
realm/js-object->clj))
|
||||
|
||||
(defn get-available-by-chat-id
|
||||
[chat-id]
|
||||
(-> ((juxt get-open-by-chat-id get-reanswerable-by-chat-id) chat-id)
|
||||
flatten
|
||||
vec))
|
||||
|
||||
(defn save
|
||||
[request]
|
||||
(realm/save @realm/account-realm :request request true))
|
||||
|
||||
(defn save-all
|
||||
[requests]
|
||||
(realm/save-all @realm/account-realm :request requests true))
|
||||
|
||||
(defn- get-by-message-id
|
||||
[chat-id message-id]
|
||||
(-> @realm/account-realm
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[status-im.data-store.realm.schemas.account.v16.core :as v16]
|
||||
[status-im.data-store.realm.schemas.account.v17.core :as v17]
|
||||
[status-im.data-store.realm.schemas.account.v18.core :as v18]
|
||||
[status-im.data-store.realm.schemas.account.v19.core :as v19]
|
||||
))
|
||||
|
||||
;; TODO(oskarth): Add failing test if directory vXX exists but isn't in schemas.
|
||||
|
@ -76,4 +77,7 @@
|
|||
{:schema v18/schema
|
||||
:schemaVersion 18
|
||||
:migration v18/migration}
|
||||
{:schema v19/schema
|
||||
:schemaVersion 19
|
||||
:migration v19/migration}
|
||||
])
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v19.contact
|
||||
(:require [taoensso.timbre :as log]))
|
||||
|
||||
(def schema {:name :contact
|
||||
:primaryKey :whisper-identity
|
||||
:properties {:address {:type :string :optional true}
|
||||
:whisper-identity :string
|
||||
:name {:type :string :optional true}
|
||||
:photo-path {:type :string :optional true}
|
||||
:last-updated {:type :int :default 0}
|
||||
:last-online {:type :int :default 0}
|
||||
:pending? {:type :bool :default false}
|
||||
:hide-contact? {:type :bool :default false}
|
||||
:status {:type :string :optional true}
|
||||
:fcm-token {:type :string :optional true}
|
||||
:description {:type :string :optional true}
|
||||
:public-key {:type :string
|
||||
:optional true}
|
||||
:private-key {:type :string
|
||||
:optional true}
|
||||
:dapp? {:type :bool
|
||||
:default false}
|
||||
:dapp-url {:type :string
|
||||
:optional true}
|
||||
:bot-url {:type :string
|
||||
:optional true}
|
||||
:dapp-hash {:type :int
|
||||
:optional true}
|
||||
:debug? {:type :bool
|
||||
:default false}}})
|
|
@ -0,0 +1,100 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v19.core
|
||||
(:require [status-im.data-store.realm.schemas.account.v11.chat :as chat]
|
||||
[status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact]
|
||||
[status-im.data-store.realm.schemas.account.v6.command :as command]
|
||||
[status-im.data-store.realm.schemas.account.v9.command-parameter :as command-parameter]
|
||||
[status-im.data-store.realm.schemas.account.v19.contact :as contact]
|
||||
[status-im.data-store.realm.schemas.account.v1.discover :as discover]
|
||||
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
|
||||
[status-im.data-store.realm.schemas.account.v10.message :as message]
|
||||
[status-im.data-store.realm.schemas.account.v12.pending-message :as pending-message]
|
||||
[status-im.data-store.realm.schemas.account.v1.processed-message :as processed-message]
|
||||
[status-im.data-store.realm.schemas.account.v19.request :as request]
|
||||
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
|
||||
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]
|
||||
[status-im.data-store.realm.schemas.account.v5.contact-group :as contact-group]
|
||||
[status-im.data-store.realm.schemas.account.v5.group-contact :as group-contact]
|
||||
[status-im.data-store.realm.schemas.account.v8.local-storage :as local-storage]
|
||||
[status-im.data-store.realm.schemas.account.v13.handler-data :as handler-data]
|
||||
[taoensso.timbre :as log]
|
||||
[cljs.reader :as reader]))
|
||||
|
||||
(def schema [chat/schema
|
||||
chat-contact/schema
|
||||
command/schema
|
||||
command-parameter/schema
|
||||
contact/schema
|
||||
discover/schema
|
||||
kv-store/schema
|
||||
message/schema
|
||||
pending-message/schema
|
||||
processed-message/schema
|
||||
request/schema
|
||||
tag/schema
|
||||
user-status/schema
|
||||
contact-group/schema
|
||||
group-contact/schema
|
||||
local-storage/schema
|
||||
handler-data/schema])
|
||||
|
||||
(defn remove-contact! [new-realm whisper-identity]
|
||||
(when-let [contact (some-> new-realm
|
||||
(.objects "contact")
|
||||
(.filtered (str "whisper-identity = \"" whisper-identity "\""))
|
||||
(aget 0))]
|
||||
(log/debug "v19 Removing contact" (pr-str contact))
|
||||
(.delete new-realm contact)))
|
||||
|
||||
(def owner-command->new-props
|
||||
{;; console commands
|
||||
["console" "password"] {:content-command-ref ["console" :response 42 "password"]
|
||||
:content-command-scope-bitmask 42}
|
||||
["console" "debug"] {:content-command-ref ["console" :command 50 "debug"]
|
||||
:content-command-scope-bitmask 50}
|
||||
["console" "phone"] {:content-command-ref ["console" :response 50 "phone"]
|
||||
:content-command-scope-bitmask 50}
|
||||
["console" "confirmation-code"] {:content-command-ref ["console" :response 50 "confirmation-code"]
|
||||
:content-command-scope-bitmask 50}
|
||||
["console" "faucet"] {:content-command-ref ["console" :command 50 "faucet"]
|
||||
:content-command-scope-bitmask 50}
|
||||
;; mailman commands
|
||||
["mailman" "location"] {:content-command-ref ["mailman" :command 215 "location"]
|
||||
:content-command-scope-bitmask 215}
|
||||
;; transactor personal
|
||||
["transactor-personal" "send"] {:content-command-ref ["transactor" :command 83 "send"]
|
||||
:content-command-scope-bitmask 83
|
||||
:bot "transactor"}
|
||||
["transactor-personal" "request"] {:content-command-ref ["transactor" :command 83 "request"]
|
||||
:content-command-scope-bitmask 83
|
||||
:bot "transactor"}
|
||||
;; transactor group
|
||||
["transactor-group" "send"] {:content-command-ref ["transactor" :command 85 "send"]
|
||||
:content-command-scope-bitmask 85
|
||||
:bot "transactor"}
|
||||
["transactor-group" "request"] {:content-command-ref ["transactor" :command 85 "request"]
|
||||
:content-command-scope-bitmask 85
|
||||
:bot "transactor"}})
|
||||
|
||||
(def console-requests->new-props
|
||||
{;; console
|
||||
["password"] {:content-command-ref ["console" :response 42 "password"]}
|
||||
["phone"] {:content-command-ref ["console" :response 50 "phone"]}
|
||||
["confirmation-code"] {:content-command-ref ["console" :response 50 "confirmation-code"]}})
|
||||
|
||||
(defn update-commands [selector mapping new-realm content-type]
|
||||
(some-> new-realm
|
||||
(.objects "message")
|
||||
(.filtered (str "content-type = \"" content-type "\""))
|
||||
(.map (fn [object _ _]
|
||||
(let [content (reader/read-string (aget object "content"))
|
||||
new-props (get owner-command->new-props (selector content))
|
||||
new-content (merge content new-props)]
|
||||
(log/debug "migrating v19 command/request database, updating: " content " with: " new-props)
|
||||
(aset object "content" (pr-str new-content)))))))
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating v19 account database: " old-realm new-realm)
|
||||
(remove-contact! new-realm "transactor-personal")
|
||||
(remove-contact! new-realm "transactor-group")
|
||||
(update-commands owner-command->new-props (juxt :bot :command) new-realm "command")
|
||||
(update-commands console-requests->new-props (juxt :command) new-realm "command-request"))
|
|
@ -0,0 +1,8 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v19.request)
|
||||
|
||||
(def schema {:name :request
|
||||
:properties {:message-id :string
|
||||
:chat-id :string
|
||||
:response :string
|
||||
:status {:type :string
|
||||
:default "open"}}})
|
|
@ -1,26 +1,14 @@
|
|||
(ns status-im.data-store.requests
|
||||
(:require [status-im.data-store.realm.requests :as data-store]))
|
||||
|
||||
(defn get-all
|
||||
(defn get-all-unanswered
|
||||
[]
|
||||
(data-store/get-all-as-list))
|
||||
|
||||
(defn get-open-by-chat-id
|
||||
[chat-id]
|
||||
(data-store/get-open-by-chat-id chat-id))
|
||||
|
||||
(defn get-available-by-chat-id
|
||||
[chat-id]
|
||||
(data-store/get-available-by-chat-id chat-id))
|
||||
(data-store/get-all-unanswered))
|
||||
|
||||
(defn save
|
||||
[request]
|
||||
(data-store/save request))
|
||||
|
||||
(defn save-all
|
||||
[requests]
|
||||
(data-store/save-all requests))
|
||||
|
||||
(defn mark-as-answered
|
||||
[chat-id message-id]
|
||||
(data-store/mark-as-answered chat-id message-id))
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
ios-error? (re-find (re-pattern "Could not connect to the server.") message)
|
||||
android-error? (re-find (re-pattern "Failed to connect") message)]
|
||||
(when (or ios-error? android-error?)
|
||||
(when android-error? (status/init-jail))
|
||||
(dispatch [:load-commands!]))))))
|
||||
(when android-error? (status/init-jail)))))))
|
||||
|
||||
(register-handler
|
||||
:load-processed-messages
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
:default))
|
||||
:cancel-text (label :t/sharing-cancel)})))
|
||||
|
||||
(defn browse [command link]
|
||||
(defn browse [browse-command link]
|
||||
(let [list-selection-fn (:list-selection-fn platform-specific)]
|
||||
(list-selection-fn {:title (label :t/browsing-title)
|
||||
:options [{:text "@browse"}
|
||||
|
@ -37,7 +37,7 @@
|
|||
(case index
|
||||
0 (do
|
||||
(dispatch [:select-chat-input-command
|
||||
(assoc (first command) :prefill [link])
|
||||
(assoc browse-command :prefill [link])
|
||||
nil
|
||||
true])
|
||||
(js/setTimeout #(dispatch [:send-current-message]) 100))
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
(ns status-im.ui.screens.accounts.events
|
||||
(:require
|
||||
status-im.ui.screens.accounts.login.events
|
||||
status-im.ui.screens.accounts.recover.events
|
||||
|
||||
[status-im.data-store.accounts :as accounts-store]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.utils.identicon :refer [identicon]]
|
||||
[status-im.utils.random :as random]
|
||||
[clojure.string :as str]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.ui.screens.accounts.statuses :as statuses]
|
||||
[status-im.utils.signing-phrase.core :as signing-phrase]
|
||||
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
||||
[status-im.utils.hex :as utils.hex]))
|
||||
(:require [status-im.data-store.accounts :as accounts-store]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.utils.identicon :refer [identicon]]
|
||||
[status-im.utils.random :as random]
|
||||
[clojure.string :as str]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.ui.screens.accounts.statuses :as statuses]
|
||||
[status-im.utils.signing-phrase.core :as signing-phrase]
|
||||
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
||||
[status-im.utils.hex :as utils.hex]))
|
||||
|
||||
;;;; Helper fns
|
||||
|
||||
|
@ -26,6 +22,7 @@
|
|||
[db password]
|
||||
{:db (assoc db :accounts/creating-account? true)
|
||||
::create-account password
|
||||
;; TODO(janherich): get rid of this shitty delayed dispatch once sending commands/msgs is refactored
|
||||
:dispatch-later [{:ms 400 :dispatch [:account-generation-message]}]})
|
||||
|
||||
;;;; COFX
|
||||
|
@ -40,6 +37,16 @@
|
|||
(fn [coeffects _]
|
||||
(assoc coeffects :all-accounts (accounts-store/get-all))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
::get-signing-phrase
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :signing-phrase (signing-phrase/generate))))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
::get-status
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :status (rand-nth statuses/data))))
|
||||
|
||||
;;;; FX
|
||||
|
||||
(re-frame/reg-fx
|
||||
|
@ -47,33 +54,12 @@
|
|||
(fn [account]
|
||||
(accounts-store/save account true)))
|
||||
|
||||
(defn account-created [result password]
|
||||
(let [data (json->clj result)
|
||||
public-key (:pubkey data)
|
||||
address (:address data)
|
||||
mnemonic (:mnemonic data)
|
||||
phrase (signing-phrase/generate)
|
||||
{:keys [public private]} (protocol/new-keypair!)
|
||||
account {:public-key public-key
|
||||
:address address
|
||||
:name (generate-gfy public-key)
|
||||
:status (rand-nth statuses/data)
|
||||
:signed-up? true
|
||||
:updates-public-key public
|
||||
:updates-private-key private
|
||||
:photo-path (identicon public-key)
|
||||
:signing-phrase phrase}]
|
||||
(log/debug "account-created")
|
||||
(when-not (str/blank? public-key)
|
||||
(re-frame/dispatch [:show-mnemonic mnemonic phrase])
|
||||
(re-frame/dispatch [:add-account account password]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::create-account
|
||||
(fn [password]
|
||||
(status/create-account
|
||||
password
|
||||
#(account-created % password))))
|
||||
#(re-frame/dispatch [::account-created (json->clj %) password]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::broadcast-account-update
|
||||
|
@ -104,21 +90,42 @@
|
|||
:private updates-private-key}}}}))))
|
||||
;;;; Handlers
|
||||
|
||||
(defn add-account
|
||||
"Takes db and new account, creates map of effects describing adding account to database and realm"
|
||||
[{:keys [network] :networks/keys [networks] :as db} {:keys [address] :as account}]
|
||||
(let [enriched-account (assoc account
|
||||
:network network
|
||||
:networks networks
|
||||
:address address)]
|
||||
{:db (assoc-in db [:accounts/accounts address] enriched-account)
|
||||
::save-account enriched-account}))
|
||||
|
||||
;; TODO(janherich) we have this handler here only because of the tests, refactor/improve tests ASAP
|
||||
(handlers/register-handler-fx
|
||||
:add-account
|
||||
(fn [{{:keys [network]
|
||||
:networks/keys [networks]
|
||||
:as db} :db} [_ {:keys [address] :as account} password]]
|
||||
(let [address (utils.hex/normalize-hex address)
|
||||
account' (assoc account
|
||||
:network network
|
||||
:networks networks
|
||||
:address address)]
|
||||
(merge
|
||||
{:db (assoc-in db [:accounts/accounts address] account')
|
||||
::save-account account'}
|
||||
(when password
|
||||
{:dispatch-later [{:ms 400 :dispatch [:login-account address password true]}]})))))
|
||||
(fn [{:keys [db]} [_ new-account]]
|
||||
(add-account db new-account)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::account-created
|
||||
[re-frame/trim-v (re-frame/inject-cofx :get-new-keypair!)
|
||||
(re-frame/inject-cofx ::get-signing-phrase) (re-frame/inject-cofx ::get-status)]
|
||||
(fn [{:keys [keypair signing-phrase status db] :as cofx} [{:keys [pubkey address mnemonic]} password]]
|
||||
(let [normalized-address (utils.hex/normalize-hex address)
|
||||
account {:public-key pubkey
|
||||
:address normalized-address
|
||||
:name (generate-gfy pubkey)
|
||||
:status status
|
||||
:signed-up? true
|
||||
:updates-public-key (:public keypair)
|
||||
:updates-private-key (:private keypair)
|
||||
:photo-path (identicon pubkey)
|
||||
:signing-phrase signing-phrase}]
|
||||
(log/debug "account-created")
|
||||
(when-not (str/blank? pubkey)
|
||||
(-> (add-account db account)
|
||||
(assoc :dispatch-n [[:show-mnemonic mnemonic signing-phrase]
|
||||
[:login-account normalized-address password true]]))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:create-new-account-handler
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
(ns status-im.ui.screens.accounts.login.events
|
||||
(:require
|
||||
status-im.ui.screens.accounts.login.navigation
|
||||
|
||||
|
||||
[re-frame.core :refer [dispatch reg-fx]]
|
||||
[status-im.utils.handlers :refer [register-handler-db register-handler-fx]]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.chat.sign-up :as sign-up]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.data-store.core :as data-store]
|
||||
[status-im.native-module.core :as status]
|
||||
|
@ -65,7 +66,7 @@
|
|||
(let [{:keys [network config]} (get-network-by-address db address)]
|
||||
{:initialize-geth-fx config
|
||||
:db (assoc db :network network
|
||||
:node/after-start [::login-account address password])}))
|
||||
:node/after-start [::login-account address password])}))
|
||||
|
||||
(register-handler-fx
|
||||
::start-node
|
||||
|
@ -116,12 +117,15 @@
|
|||
(register-handler-fx
|
||||
:change-account-handler
|
||||
(fn [{db :db} [_ error address new-account?]]
|
||||
(if (nil? error)
|
||||
{:db (dissoc db :accounts/login)
|
||||
:dispatch-n [[:stop-debugging]
|
||||
[:initialize-account address]
|
||||
[:navigate-to-clean :chat-list]
|
||||
(if new-account?
|
||||
[:navigate-to-chat console-chat-id]
|
||||
[:navigate-to :chat-list])]}
|
||||
(log/debug "Error changing acount: " error))))
|
||||
(let [recover-in-progress? (:accounts/recover db)]
|
||||
(if (nil? error)
|
||||
{:db (dissoc db :accounts/login)
|
||||
:dispatch-n [[:stop-debugging]
|
||||
[:initialize-account address (when (or new-account?
|
||||
recover-in-progress?)
|
||||
sign-up/start-signup-events)]
|
||||
[:navigate-to-clean :chat-list]
|
||||
(if new-account?
|
||||
[:navigate-to-chat console-chat-id]
|
||||
[:navigate-to :chat-list])]}
|
||||
(log/debug "Error changing acount: " error)))))
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
|
||||
[re-frame.core :refer [reg-fx inject-cofx dispatch]]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.ui.screens.accounts.events :as accounts-events]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.utils.identicon :refer [identicon]]
|
||||
[taoensso.timbre :as log]
|
||||
[clojure.string :as str]
|
||||
[status-im.utils.handlers :refer [register-handler-fx]]
|
||||
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
||||
[status-im.utils.signing-phrase.core :as signing-phrase]))
|
||||
[status-im.utils.signing-phrase.core :as signing-phrase]
|
||||
[status-im.utils.hex :as utils.hex]))
|
||||
|
||||
;;;; FX
|
||||
|
||||
|
@ -30,7 +32,7 @@
|
|||
(fn [{:keys [db keypair]} [_ result]]
|
||||
(let [data (json->clj result)
|
||||
public-key (:pubkey data)
|
||||
address (:address data)
|
||||
address (-> data :address utils.hex/normalize-hex)
|
||||
phrase (signing-phrase/generate)
|
||||
{:keys [public private]} keypair
|
||||
account {:public-key public-key
|
||||
|
@ -43,9 +45,9 @@
|
|||
:signing-phrase phrase}]
|
||||
(log/debug "account-recovered")
|
||||
(when-not (str/blank? public-key)
|
||||
{:db (update db :accounts/recover assoc :passphrase "" :password "")
|
||||
:dispatch-n [[:add-account account]
|
||||
[:navigate-to-clean :accounts]]}))))
|
||||
(-> db
|
||||
(accounts-events/add-account account)
|
||||
(assoc :dispatch [:navigate-to-clean :accounts]))))))
|
||||
|
||||
(register-handler-fx
|
||||
:recover-account
|
||||
|
|
|
@ -4,4 +4,11 @@
|
|||
(reg-sub
|
||||
:get-accounts
|
||||
(fn [db _]
|
||||
(get db :accounts/accounts)))
|
||||
(get db :accounts/accounts)))
|
||||
|
||||
(reg-sub
|
||||
:get-current-account
|
||||
:<- [:get :accounts/current-account-id]
|
||||
:<- [:get-accounts]
|
||||
(fn [[account-id accounts]]
|
||||
(some-> accounts (get account-id))))
|
||||
|
|
|
@ -28,17 +28,17 @@
|
|||
(spec/def :contact/last-updated (spec/nilable int?))
|
||||
(spec/def :contact/last-online (spec/nilable int?))
|
||||
(spec/def :contact/pending? boolean?)
|
||||
(spec/def :contact/mixable? boolean?)
|
||||
(spec/def :contact/unremovable? boolean?)
|
||||
(spec/def :contact/hide-contact? boolean?)
|
||||
|
||||
(spec/def :contact/dapp? boolean?)
|
||||
(spec/def :contact/dapp-url (spec/nilable string?))
|
||||
(spec/def :contact/dapp-hash (spec/nilable int?))
|
||||
(spec/def :contact/bot-url (spec/nilable string?))
|
||||
(spec/def :contact/global-command (spec/nilable map?))
|
||||
(spec/def :contact/commands (spec/nilable (spec/map-of keyword? seq?)))
|
||||
(spec/def :contact/responses (spec/nilable (spec/map-of keyword? seq?)))
|
||||
(spec/def :contact/commands-loaded? (spec/nilable boolean?))
|
||||
(spec/def :contact/bot-url (spec/nilable string?))
|
||||
(spec/def :contact/command (spec/nilable (spec/map-of int? map?)))
|
||||
(spec/def :contact/response (spec/nilable (spec/map-of int? map?)))
|
||||
(spec/def :contact/jail-loaded? (spec/nilable boolean?))
|
||||
(spec/def :contact/jail-loaded-events (spec/nilable seq?))
|
||||
(spec/def :contact/subscriptions (spec/nilable map?))
|
||||
;true when contact added using status-dev-cli
|
||||
(spec/def :contact/debug? boolean?)
|
||||
|
@ -54,18 +54,17 @@
|
|||
:contact/status
|
||||
:contact/last-updated
|
||||
:contact/last-online
|
||||
:contact/pending?
|
||||
:contact/mixable?
|
||||
:contact/scope
|
||||
:contact/pending?
|
||||
:contact/hide-contact?
|
||||
:contact/unremovable?
|
||||
:contact/dapp?
|
||||
:contact/dapp-url
|
||||
:contact/dapp-hash
|
||||
:contact/bot-url
|
||||
:contact/global-command
|
||||
:contact/commands-loaded?
|
||||
:contact/commands
|
||||
:contact/responses
|
||||
:contact/bot-url
|
||||
:contact/jail-loaded?
|
||||
:contact/jail-loaded-events
|
||||
:contact/command
|
||||
:contact/response
|
||||
:contact/debug?
|
||||
:contact/subscriptions
|
||||
:contact/fcm-token
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[status-im.protocol.core :as protocol]
|
||||
[status-im.utils.utils :refer [http-post]]
|
||||
[status-im.utils.phone-number :refer [format-phone-number]]
|
||||
[status-im.utils.random :as random]
|
||||
[status-im.utils.random :as random]
|
||||
[taoensso.timbre :as log]
|
||||
[cljs.reader :refer [read-string]]
|
||||
[status-im.utils.js-resources :as js-res]
|
||||
|
@ -17,6 +17,8 @@
|
|||
[status-im.utils.gfycat.core :refer [generate-gfy]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.ui.screens.contacts.navigation]
|
||||
[status-im.chat.sign-up :as sign-up]
|
||||
[status-im.commands.events.loading :as loading-events]
|
||||
[cljs.spec.alpha :as spec]))
|
||||
|
||||
;;;; COFX
|
||||
|
@ -29,8 +31,9 @@
|
|||
(reg-cofx
|
||||
::get-default-contacts-and-groups
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :default-contacts js-res/default-contacts
|
||||
:default-groups js-res/default-contact-groups)))
|
||||
(assoc coeffects
|
||||
:default-contacts js-res/default-contacts
|
||||
:default-groups js-res/default-contact-groups)))
|
||||
|
||||
;;;; FX
|
||||
|
||||
|
@ -125,8 +128,9 @@
|
|||
(defn- add-identity [contacts-by-hash contacts]
|
||||
(map (fn [{:keys [phone-number-hash whisper-identity address]}]
|
||||
(let [contact (contacts-by-hash phone-number-hash)]
|
||||
(assoc contact :whisper-identity whisper-identity
|
||||
:address address)))
|
||||
(assoc contact
|
||||
:whisper-identity whisper-identity
|
||||
:address address)))
|
||||
(js->clj contacts)))
|
||||
|
||||
(reg-fx
|
||||
|
@ -213,23 +217,25 @@
|
|||
|
||||
;; NOTE(oskarth): We now overwrite default contacts upon upgrade with default_contacts.json data.
|
||||
(defn- prepare-default-contacts-events [contacts default-contacts]
|
||||
[[:add-contacts
|
||||
(for [[id {:keys [name photo-path public-key add-chat? pending? description
|
||||
dapp? dapp-url dapp-hash bot-url unremovable? mixable?]}] default-contacts
|
||||
:let [id' (clojure.core/name id)]]
|
||||
{:whisper-identity id'
|
||||
:address (public-key->address id')
|
||||
:name (:en name)
|
||||
:photo-path photo-path
|
||||
:public-key public-key
|
||||
:unremovable? (boolean unremovable?)
|
||||
:mixable? (boolean mixable?)
|
||||
:pending? pending?
|
||||
:dapp? dapp?
|
||||
:dapp-url (:en dapp-url)
|
||||
:bot-url bot-url
|
||||
:description description
|
||||
:dapp-hash dapp-hash})]])
|
||||
(let [default-contacts
|
||||
(for [[id {:keys [name photo-path public-key add-chat? pending? description
|
||||
dapp? dapp-url dapp-hash bot-url unremovable? hide-contact?]}] default-contacts
|
||||
:let [id' (clojure.core/name id)]]
|
||||
{:whisper-identity id'
|
||||
:address (public-key->address id')
|
||||
:name (:en name)
|
||||
:photo-path photo-path
|
||||
:public-key public-key
|
||||
:unremovable? (boolean unremovable?)
|
||||
:hide-contact? (boolean hide-contact?)
|
||||
:pending? pending?
|
||||
:dapp? dapp?
|
||||
:dapp-url (:en dapp-url)
|
||||
:bot-url bot-url
|
||||
:description description
|
||||
:dapp-hash dapp-hash})
|
||||
all-default-contacts (conj default-contacts sign-up/console-contact)]
|
||||
[[:add-contacts all-default-contacts]]))
|
||||
|
||||
(defn- prepare-add-chat-events [contacts default-contacts]
|
||||
(for [[id {:keys [name add-chat?]}] default-contacts
|
||||
|
@ -237,12 +243,6 @@
|
|||
:when (and (not (get contacts id')) add-chat?)]
|
||||
[:add-chat id' {:name (:en name)}]))
|
||||
|
||||
(defn- prepare-bot-commands-events [contacts default-contacts]
|
||||
(for [[id {:keys [bot-url]}] default-contacts
|
||||
:let [id' (clojure.core/name id)]
|
||||
:when bot-url]
|
||||
[:load-commands! id']))
|
||||
|
||||
(defn- prepare-add-contacts-to-groups-events [contacts default-contacts]
|
||||
(let [groups (for [[id {:keys [groups]}] default-contacts
|
||||
:let [id' (clojure.core/name id)]
|
||||
|
@ -258,14 +258,13 @@
|
|||
(register-handler-fx
|
||||
:load-default-contacts!
|
||||
[(inject-cofx ::get-default-contacts-and-groups)]
|
||||
(fn [{:keys [db default-contacts default-groups]} _]
|
||||
(fn [{:keys [db default-contacts default-groups] :as cofx} _]
|
||||
(let [{:contacts/keys [contacts] :group/keys [contact-groups]} db]
|
||||
{:dispatch-n (concat
|
||||
(prepare-default-groups-events contact-groups default-groups)
|
||||
(prepare-default-contacts-events contacts default-contacts)
|
||||
(prepare-add-chat-events contacts default-contacts)
|
||||
(prepare-bot-commands-events contacts default-contacts)
|
||||
(prepare-add-contacts-to-groups-events contacts default-contacts))})))
|
||||
(prepare-default-groups-events contact-groups default-groups)
|
||||
(prepare-default-contacts-events contacts default-contacts)
|
||||
(prepare-add-chat-events contacts default-contacts)
|
||||
(prepare-add-contacts-to-groups-events contacts default-contacts))})))
|
||||
|
||||
(register-handler-fx
|
||||
:load-contacts
|
||||
|
@ -273,7 +272,7 @@
|
|||
(fn [{:keys [db all-contacts]} _]
|
||||
(let [contacts-list (map #(vector (:whisper-identity %) %) all-contacts)
|
||||
contacts (into {} contacts-list)]
|
||||
{:db (assoc db :contacts/contacts contacts)
|
||||
{:db (update db :contacts/contacts #(merge contacts %))
|
||||
;; TODO (yenda) this mapv was dispatching useless events, fixed but is it necessary if
|
||||
;; it was dispatching useless events before with nil
|
||||
;;:dispatch-n (mapv (fn [[_ contact]] [:watch-contact contact]) contacts)
|
||||
|
@ -281,16 +280,21 @@
|
|||
|
||||
(register-handler-fx
|
||||
:add-contacts
|
||||
(fn [{:keys [db]} [_ new-contacts]]
|
||||
[(inject-cofx :get-local-storage-data)]
|
||||
(fn [{:keys [db] :as cofx} [_ new-contacts]]
|
||||
(let [{:contacts/keys [contacts]} db
|
||||
new-contacts' (->> new-contacts
|
||||
(map #(update-pending-status contacts %))
|
||||
;; NOTE(oskarth): Overwriting default contacts here
|
||||
;;(remove #(identities (:whisper-identity %)))
|
||||
(map #(vector (:whisper-identity %) %))
|
||||
(into {}))]
|
||||
{:db (update db :contacts/contacts merge new-contacts')
|
||||
::save-contacts! (vals new-contacts')})))
|
||||
(into {}))
|
||||
fx {:db (update db :contacts/contacts merge new-contacts')
|
||||
::save-contacts! (vals new-contacts')}]
|
||||
(transduce (map second)
|
||||
(completing (partial loading-events/load-commands (assoc cofx :db (:db fx))))
|
||||
fx
|
||||
new-contacts'))))
|
||||
|
||||
(register-handler-db
|
||||
:remove-contacts-click-handler
|
||||
|
@ -335,8 +339,9 @@
|
|||
contact (if-let [contact-info (get-in chats [chat-or-whisper-id :contact-info])]
|
||||
(read-string contact-info)
|
||||
(get contacts chat-or-whisper-id))
|
||||
contact' (assoc contact :address (public-key->address chat-or-whisper-id)
|
||||
:pending? false)]
|
||||
contact' (assoc contact
|
||||
:address (public-key->address chat-or-whisper-id)
|
||||
:pending? false)]
|
||||
{:dispatch-n [[::add-new-contact contact']
|
||||
[:watch-contact contact']
|
||||
[:discoveries-send-portions chat-or-whisper-id]]})))
|
||||
|
@ -392,8 +397,8 @@
|
|||
:hide-contact
|
||||
(fn [{:keys [db]} [_ {:keys [whisper-identity] :as contact}]]
|
||||
{::stop-watching-contact (merge
|
||||
(select-keys db [:web3])
|
||||
(select-keys contact [:whisper-identity]))
|
||||
(select-keys db [:web3])
|
||||
(select-keys contact [:whisper-identity]))
|
||||
:dispatch-n [[:update-contact! {:whisper-identity whisper-identity
|
||||
:pending? true}]
|
||||
[:account-update-keys]]}))
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
:<- [:get-contacts]
|
||||
(fn [contacts]
|
||||
(->> contacts
|
||||
(remove (fn [[_ {:keys [pending? mixable?]}]]
|
||||
(or pending? mixable?)))
|
||||
(remove (fn [[_ {:keys [pending? hide-contact?]}]]
|
||||
(or pending? hide-contact?)))
|
||||
(sort-contacts))))
|
||||
|
||||
(reg-sub :all-added-people-contacts
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
status-im.ui.screens.group.db
|
||||
status-im.chat.specs
|
||||
status-im.chat.new-public-chat.db
|
||||
status-im.commands.specs
|
||||
status-im.ui.screens.profile.db
|
||||
status-im.ui.screens.discover.db
|
||||
status-im.ui.screens.network-settings.db))
|
||||
|
@ -150,27 +151,24 @@
|
|||
:chat/chat-ui-props
|
||||
:chat/chat-list-ui-props
|
||||
:chat/layout-height
|
||||
:chat/expandable-view-height-to-value
|
||||
:chat/global-commands
|
||||
:chat/expandable-view-height-to-value
|
||||
:chat/loading-allowed
|
||||
:chat/message-data
|
||||
:chat/message-id->transaction-id
|
||||
:chat/message-status
|
||||
:chat/unviewed-messages
|
||||
:chat/selected-participants
|
||||
:chat/chat-loaded-callbacks
|
||||
:chat/commands-callbacks
|
||||
:chat/chat-loaded-callbacks
|
||||
:chat/command-hash-valid?
|
||||
:chat/public-group-topic
|
||||
:chat/confirmation-code-sms-listener
|
||||
:chat/messages
|
||||
:chat/handler-data
|
||||
:chat/loaded-chats
|
||||
:chat/bot-subscriptions
|
||||
:chat/new-request
|
||||
:chat/loaded-chats
|
||||
:chat/raw-unviewed-messages
|
||||
:chat/bot-db
|
||||
:chat/geolocation
|
||||
:commands/access-scope->commands-responses
|
||||
:discoveries/discoveries
|
||||
:discoveries/discover-search-tags
|
||||
:discoveries/discover-current-dapp
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
(:require status-im.bots.events
|
||||
status-im.chat.handlers
|
||||
status-im.commands.handlers.jail
|
||||
status-im.commands.handlers.loading
|
||||
status-im.commands.events.loading
|
||||
status-im.commands.handlers.debug
|
||||
status-im.network.handlers
|
||||
status-im.protocol.handlers
|
||||
status-im.ui.screens.accounts.events
|
||||
status-im.ui.screens.accounts.login.events
|
||||
status-im.ui.screens.accounts.recover.events
|
||||
status-im.ui.screens.contacts.events
|
||||
status-im.ui.screens.discover.events
|
||||
status-im.ui.screens.group.chat-settings.events
|
||||
|
@ -60,21 +62,21 @@
|
|||
;;;; COFX
|
||||
|
||||
(reg-cofx
|
||||
:now
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :now (time/now-ms))))
|
||||
:now
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :now (time/now-ms))))
|
||||
|
||||
(reg-cofx
|
||||
:random-id
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id (random/id))))
|
||||
:random-id
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id (random/id))))
|
||||
|
||||
(reg-cofx
|
||||
:random-id-seq
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id-seq
|
||||
((fn rand-id-seq []
|
||||
(cons (random/id) (lazy-seq (rand-id-seq))))))))
|
||||
:random-id-seq
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-id-seq
|
||||
((fn rand-id-seq []
|
||||
(cons (random/id) (lazy-seq (rand-id-seq))))))))
|
||||
|
||||
;;;; FX
|
||||
|
||||
|
@ -107,13 +109,26 @@
|
|||
#(dispatch (success-event-creator %))
|
||||
#(dispatch (failure-event-creator %)))))
|
||||
|
||||
(reg-fx
|
||||
:http-get
|
||||
(fn [{:keys [url success-event-creator failure-event-creator]}]
|
||||
(defn- http-get [{:keys [url response-validator success-event-creator failure-event-creator]}]
|
||||
(if response-validator
|
||||
(utils/http-get url
|
||||
response-validator
|
||||
#(dispatch (success-event-creator %))
|
||||
#(dispatch (failure-event-creator %)))
|
||||
(utils/http-get url
|
||||
#(dispatch (success-event-creator %))
|
||||
#(dispatch (failure-event-creator %)))))
|
||||
|
||||
(reg-fx
|
||||
:http-get
|
||||
http-get)
|
||||
|
||||
(reg-fx
|
||||
:http-get-n
|
||||
(fn [calls]
|
||||
(doseq [call calls]
|
||||
(http-get call))))
|
||||
|
||||
(reg-fx
|
||||
::init-store
|
||||
(fn []
|
||||
|
@ -123,29 +138,29 @@
|
|||
::initialize-crypt-fx
|
||||
(fn []
|
||||
(crypt/gen-random-bytes
|
||||
1024
|
||||
(fn [{:keys [error buffer]}]
|
||||
(if error
|
||||
(log/error "Failed to generate random bytes to initialize sjcl crypto")
|
||||
(->> (.toString buffer "hex")
|
||||
(.toBits (.. dependencies/eccjs -sjcl -codec -hex))
|
||||
(.addEntropy (.. dependencies/eccjs -sjcl -random))))))))
|
||||
1024
|
||||
(fn [{:keys [error buffer]}]
|
||||
(if error
|
||||
(log/error "Failed to generate random bytes to initialize sjcl crypto")
|
||||
(->> (.toString buffer "hex")
|
||||
(.toBits (.. dependencies/eccjs -sjcl -codec -hex))
|
||||
(.addEntropy (.. dependencies/eccjs -sjcl -random))))))))
|
||||
|
||||
(defn move-to-internal-storage [config]
|
||||
(status/move-to-internal-storage
|
||||
#(status/start-node config)))
|
||||
#(status/start-node config)))
|
||||
|
||||
(reg-fx
|
||||
:initialize-geth-fx
|
||||
(fn [config]
|
||||
(status/should-move-to-internal-storage?
|
||||
(fn [should-move?]
|
||||
(if should-move?
|
||||
(dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(move-to-internal-storage config)
|
||||
#(dispatch [:move-to-internal-failure-message])])
|
||||
(status/start-node config))))))
|
||||
(fn [should-move?]
|
||||
(if should-move?
|
||||
(dispatch [:request-permissions
|
||||
[:read-external-storage]
|
||||
#(move-to-internal-storage config)
|
||||
#(dispatch [:move-to-internal-failure-message])])
|
||||
(status/start-node config))))))
|
||||
|
||||
(reg-fx
|
||||
::status-module-initialized-fx
|
||||
|
@ -162,8 +177,8 @@
|
|||
(fn []
|
||||
(when config/testfairy-enabled?
|
||||
(utils/show-popup
|
||||
(i18n/label :testfairy-title)
|
||||
(i18n/label :testfairy-message)))))
|
||||
(i18n/label :testfairy-title)
|
||||
(i18n/label :testfairy-message)))))
|
||||
|
||||
(reg-fx
|
||||
::get-fcm-token-fx
|
||||
|
@ -226,45 +241,52 @@
|
|||
|
||||
(register-handler-db
|
||||
:initialize-account-db
|
||||
(fn [{:keys [accounts/accounts networks/networks network view-id navigation-stack
|
||||
(fn [{:keys [accounts/accounts contacts/contacts networks/networks
|
||||
network view-id navigation-stack chats
|
||||
access-scope->commands-responses layout-height
|
||||
status-module-initialized? status-node-started?]
|
||||
:or [network (get app-db :network)]
|
||||
:as db} [_ address]]
|
||||
(-> app-db
|
||||
(assoc :current-chat-id console-chat-id
|
||||
:accounts/current-account-id address
|
||||
;; TODO (yenda) bad, this is derived data and shouldn't be stored in the db
|
||||
;; the cost of retrieving public key from db with a function taking using
|
||||
;; current-account-id is negligeable
|
||||
:current-public-key (:public-key (accounts address))
|
||||
:view-id view-id
|
||||
:navigation-stack navigation-stack
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?)
|
||||
:status-node-started? status-node-started?
|
||||
:accounts/accounts accounts
|
||||
:accounts/creating-account? false
|
||||
:networks/networks networks
|
||||
:network network))))
|
||||
(let [console-contact (get contacts console-chat-id)]
|
||||
(cond-> (assoc app-db
|
||||
:access-scope->commands-responses access-scope->commands-responses
|
||||
:accounts/current-account-id address
|
||||
:layout-height layout-height
|
||||
;; TODO (yenda) bad, this is derived data and shouldn't be stored in the db
|
||||
;; the cost of retrieving public key from db with a function taking using
|
||||
;; current-account-id is negligeable
|
||||
:current-public-key (:public-key (accounts address))
|
||||
:view-id view-id
|
||||
:navigation-stack navigation-stack
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?)
|
||||
:status-node-started? status-node-started?
|
||||
:accounts/accounts accounts
|
||||
:accounts/creating-account? false
|
||||
:networks/networks networks
|
||||
:network network)
|
||||
console-contact
|
||||
(assoc :contacts/contacts {console-chat-id console-contact})))))
|
||||
|
||||
(register-handler-fx
|
||||
:initialize-account
|
||||
(fn [_ [_ address]]
|
||||
{:dispatch-n [[:initialize-account-db address]
|
||||
[:load-processed-messages]
|
||||
[:initialize-protocol address]
|
||||
[:initialize-sync-listener]
|
||||
[:initialize-chats]
|
||||
[:load-contacts]
|
||||
[:load-contact-groups]
|
||||
[:init-chat]
|
||||
[:init-discoveries]
|
||||
[:initialize-debugging {:address address}]
|
||||
[:send-account-update-if-needed]
|
||||
[:start-requesting-discoveries]
|
||||
[:remove-old-discoveries!]
|
||||
[:update-wallet]
|
||||
[:update-transactions]
|
||||
[:get-fcm-token]]}))
|
||||
(fn [_ [_ address events-after]]
|
||||
{:dispatch-n (cond-> [[:initialize-account-db address]
|
||||
[:load-processed-messages]
|
||||
[:initialize-protocol address]
|
||||
[:initialize-sync-listener]
|
||||
[:initialize-chats]
|
||||
[:load-contacts]
|
||||
[:load-contact-groups]
|
||||
[:init-discoveries]
|
||||
[:initialize-debugging {:address address}]
|
||||
[:send-account-update-if-needed]
|
||||
[:start-requesting-discoveries]
|
||||
[:remove-old-discoveries!]
|
||||
[:update-wallet]
|
||||
[:update-transactions]
|
||||
[:get-fcm-token]]
|
||||
(seq events-after)
|
||||
(into events-after))}))
|
||||
|
||||
(register-handler-fx
|
||||
:check-console-chat
|
||||
|
@ -277,10 +299,9 @@
|
|||
:view-id view
|
||||
:navigation-stack (list view))}
|
||||
(when (or (empty? accounts) open-console?)
|
||||
{:dispatch-n (concat [[:init-console-chat]
|
||||
[:load-commands!]]
|
||||
{:dispatch-n (concat [[:init-console-chat]]
|
||||
(when open-console?
|
||||
[[:navigate-to :chat console-chat-id]]))})))))
|
||||
[[:navigate-to-chat console-chat-id]]))})))))
|
||||
|
||||
(register-handler-fx
|
||||
:initialize-crypt
|
||||
|
@ -308,6 +329,15 @@
|
|||
(fn [_ _]
|
||||
{::get-fcm-token-fx nil}))
|
||||
|
||||
;; Because we send command to jail in params and command `:ref` is a lookup vector with
|
||||
;; keyword in it (for example `["transactor" :command 51 "send"]`), we lose that keyword
|
||||
;; information in the process of converting to/from JSON, and we need to restore it
|
||||
(defn- restore-command-ref-keyword
|
||||
[orig-params]
|
||||
(if [(get-in orig-params [:command :command :ref])]
|
||||
(update-in orig-params [:command :command :ref 1] keyword)
|
||||
orig-params))
|
||||
|
||||
(defn handle-jail-signal [{:keys [chat_id data]}]
|
||||
(let [{:keys [event data]} (types/json->clj data)]
|
||||
(case event
|
||||
|
@ -319,7 +349,8 @@
|
|||
:message data}])
|
||||
"handler-result" (let [orig-params (:origParams data)]
|
||||
;; TODO(janherich): figure out and fix chat_id from event
|
||||
(dispatch [:command-handler! (:chat-id orig-params) orig-params
|
||||
(dispatch [:command-handler! (:chat-id orig-params)
|
||||
(restore-command-ref-keyword orig-params)
|
||||
{:result {:returned (dissoc data :origParams)}}]))
|
||||
(log/debug "Unknown jail signal " event))))
|
||||
|
||||
|
@ -376,19 +407,19 @@
|
|||
(fn []
|
||||
(let [watch-id (atom nil)]
|
||||
(.getCurrentPosition
|
||||
navigator.geolocation
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
(clj->js {:enableHighAccuracy true :timeout 20000 :maximumAge 1000}))
|
||||
navigator.geolocation
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
(clj->js {:enableHighAccuracy true :timeout 20000 :maximumAge 1000}))
|
||||
(when platform/android?
|
||||
(reset! watch-id
|
||||
(.watchPosition
|
||||
navigator.geolocation
|
||||
#(do
|
||||
(.clearWatch
|
||||
navigator.geolocation
|
||||
@watch-id)
|
||||
(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])))))))]}))
|
||||
navigator.geolocation
|
||||
#(do
|
||||
(.clearWatch
|
||||
navigator.geolocation
|
||||
@watch-id)
|
||||
(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])))))))]}))
|
||||
|
||||
(register-handler-db
|
||||
:update-geolocation
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
(ns status-im.ui.screens.profile.events
|
||||
(:require [clojure.spec.alpha :as spec]
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame :refer [reg-fx trim-v]]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :refer [show-image-picker]]
|
||||
[status-im.constants :refer [console-chat-id]]
|
||||
[status-im.constants :as const]
|
||||
[status-im.chat.constants :as chat-const]
|
||||
[status-im.ui.screens.profile.db :as db]
|
||||
[status-im.ui.screens.profile.navigation]
|
||||
[status-im.ui.screens.accounts.events :as accounts-events]
|
||||
[status-im.chat.events :as chat-events]
|
||||
[status-im.chat.events.input :as input-events]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.image-processing :refer [img->base64]]
|
||||
[status-im.utils.utils :as utils]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(reg-fx
|
||||
(re-frame/reg-fx
|
||||
:open-image-picker
|
||||
;; the image picker is only used here for now, this effect can be use in other scenarios as well
|
||||
(fn [callback-event]
|
||||
|
@ -29,12 +32,12 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:profile/send-transaction
|
||||
[trim-v]
|
||||
(fn [{:keys [db]} [chat-id]]
|
||||
(let [send-command (first (get-in db [:contacts/contacts "transactor-personal" :commands :send]))]
|
||||
{:dispatch [:navigate-to :chat chat-id]
|
||||
;;TODO get rid of timeout
|
||||
:dispatch-later [{:ms 100 :dispatch [:select-chat-input-command send-command]}]})))
|
||||
[re-frame/trim-v (re-frame/inject-cofx :get-stored-messages)]
|
||||
(fn [{{:contacts/keys [contacts] :as db} :db :as cofx} [chat-id]]
|
||||
(let [send-command (get-in contacts chat-const/send-command-ref)]
|
||||
(-> (chat-events/navigate-to-chat cofx chat-id)
|
||||
(as-> fx
|
||||
(merge fx (input-events/select-chat-input-command (:db fx) send-command nil true)))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:profile/send-message
|
||||
|
@ -46,10 +49,11 @@
|
|||
:my-profile/update-phone-number
|
||||
;; Switch user to the console issuing the !phone command automatically to let him change his phone number.
|
||||
;; We allow to change phone number only from console because this requires entering SMS verification code.
|
||||
(fn [{:keys [db]} _]
|
||||
(let [phone-command (first (get-in db [:contacts/contacts "console" :responses :phone]))]
|
||||
{:dispatch-n [[:navigate-to-chat console-chat-id]
|
||||
[:select-chat-input-command phone-command]]})))
|
||||
(fn [{{:contacts/keys [contacts] :as db} :db :as cofx} _]
|
||||
(let [phone-command (get-in contacts chat-const/phone-command-ref)]
|
||||
(-> (chat-events/navigate-to-chat cofx const/console-chat-id)
|
||||
(as-> fx
|
||||
(merge fx (input-events/select-chat-input-command (:db fx) phone-command nil true)))))))
|
||||
|
||||
(defn get-current-account [{:keys [:accounts/current-account-id] :as db}]
|
||||
(get-in db [:accounts/accounts current-account-id]))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.ui.screens.subs
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
status-im.chat.subs
|
||||
status-im.commands.subs
|
||||
status-im.ui.screens.accounts.subs
|
||||
status-im.ui.screens.chats-list.subs
|
||||
status-im.ui.screens.group.chat-settings.subs
|
||||
|
@ -20,21 +21,14 @@
|
|||
(fn [db [_ k]]
|
||||
(get db k)))
|
||||
|
||||
(reg-sub :get-current-account
|
||||
(fn [db]
|
||||
(let [current-account-id (:accounts/current-account-id db)]
|
||||
(get-in db [:accounts/accounts current-account-id]))))
|
||||
|
||||
(reg-sub :get-in
|
||||
(fn [db [_ path]]
|
||||
(get-in db path)))
|
||||
|
||||
(reg-sub :signed-up?
|
||||
:<- [:get :accounts/current-account-id]
|
||||
:<- [:get-accounts]
|
||||
(fn [[account-id accounts]]
|
||||
(when (and accounts account-id)
|
||||
(get-in accounts [account-id :signed-up?]))))
|
||||
(reg-sub :signed-up?
|
||||
:<- [:get-current-account]
|
||||
(fn [current-account]
|
||||
(:signed-up? current-account)))
|
||||
|
||||
(reg-sub :tabs-hidden?
|
||||
:<- [:get-in [:toolbar-search :show]]
|
||||
|
|
|
@ -1,28 +1,34 @@
|
|||
(ns status-im.ui.screens.wallet.request.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.screens.wallet.db :as wallet.db]
|
||||
[status-im.ui.screens.wallet.db :as wallet-db]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.chat.constants :as chat-const]
|
||||
[status-im.chat.events.input :as input-events]
|
||||
[status-im.utils.money :as money]))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::wallet-send-chat-request
|
||||
(fn [_ [_ amount]]
|
||||
{:dispatch [:select-chat-input-command {:name "request" :prefill [amount]}]
|
||||
;; TODO get rid of the timeout
|
||||
:dispatch-later [{:ms 100 :dispatch [:send-current-message]}]}))
|
||||
[re-frame/trim-v]
|
||||
(fn [{{:contacts/keys [contacts] :as db} :db} [amount]]
|
||||
(-> db
|
||||
(input-events/select-chat-input-command
|
||||
(assoc (get-in contacts chat-const/request-command-ref) :prefill [amount]) nil true)
|
||||
(assoc :dispatch [:send-current-message]))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet-send-request
|
||||
(fn [{{:wallet/keys [request-transaction]} :db} [_ {:keys [whisper-identity]}]]
|
||||
[re-frame/trim-v]
|
||||
(fn [{{:wallet/keys [request-transaction]} :db} [{:keys [whisper-identity]}]]
|
||||
{:dispatch-n [[:navigate-back]
|
||||
[:navigate-to-clean :chat-list]
|
||||
[:add-chat-loaded-event whisper-identity [::wallet-send-chat-request (str (:amount request-transaction))]]
|
||||
[:add-chat-loaded-event whisper-identity
|
||||
[::wallet-send-chat-request (some-> request-transaction :amount money/wei->ether str)]]
|
||||
[:start-chat whisper-identity]]}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.request/set-and-validate-amount
|
||||
(fn [{:keys [db]} [_ amount]]
|
||||
(let [{:keys [value error]} (wallet.db/parse-amount amount)]
|
||||
(let [{:keys [value error]} (wallet-db/parse-amount amount)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet/request-transaction :amount] (money/ether->wei value))
|
||||
(assoc-in [:wallet/request-transaction :amount-error] error))})))
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
(def default-contacts (json->clj (slurp "resources/default_contacts.json")))
|
||||
(def default-contact-groups (json->clj (slurp "resources/default_contact_groups.json")))
|
||||
|
||||
(def transactor-group-js (slurp-bot :transactor_group))
|
||||
|
||||
(def transactor-personal-js (slurp-bot :transactor_personal))
|
||||
(def transactor-js (slurp-bot :transactor))
|
||||
|
||||
(def console-js (slurp-bot :console "web3_metadata.js"))
|
||||
|
||||
|
@ -24,12 +22,11 @@
|
|||
(def demo-bot-js (slurp-bot :demo_bot))
|
||||
|
||||
(def resources
|
||||
{:transactor-group-bot transactor-group-js
|
||||
:transactor-personal-bot transactor-personal-js
|
||||
:console-bot console-js
|
||||
:browse-bot browse-js
|
||||
:mailman-bot mailman-js
|
||||
:demo-bot demo-bot-js})
|
||||
{:transactor-bot transactor-js
|
||||
:console-bot console-js
|
||||
:browse-bot browse-js
|
||||
:mailman-bot mailman-js
|
||||
:demo-bot demo-bot-js})
|
||||
|
||||
(defn get-resource [url]
|
||||
(let [resource-name (keyword (subs url (count local-protocol)))]
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
[status-im.bots.events :as bots-events]))
|
||||
|
||||
(def ^:private initial-db
|
||||
{:bot-db {}
|
||||
:bot-subscriptions {}
|
||||
{:bot-db {}
|
||||
:contacts/contacts
|
||||
{"bot1" {:subscriptions
|
||||
{:feeExplanation
|
||||
|
@ -19,13 +18,13 @@
|
|||
|
||||
(deftest add-active-bot-subscriptions-test
|
||||
(testing "That active bot subscriptions are correctly transformed and added to db"
|
||||
(let [db (bots-events/add-active-bot-subscriptions initial-db #{"bot1" "bot3"})]
|
||||
(is (= #{"bot1" "bot3"} (-> db :bot-subscriptions keys set)))
|
||||
(let [db (update-in initial-db [:contacts/contacts "bot1" :subscriptions]
|
||||
bots-events/transform-bot-subscriptions)]
|
||||
(is (= {[:sliderValue] {:feeExplanation {:fee [:sliderValue]
|
||||
:tx [:transaction]}}
|
||||
[:transaction] {:feeExplanation {:fee [:sliderValue]
|
||||
:tx [:transaction]}}}
|
||||
(-> db :bot-subscriptions (get "bot1")))))))
|
||||
(get-in db [:contacts/contacts "bot1" :subscriptions]))))))
|
||||
|
||||
(defn- fake-subscription-call
|
||||
[db {:keys [chat-id parameters]}]
|
||||
|
@ -37,7 +36,8 @@
|
|||
|
||||
(deftest set-in-bot-db-test
|
||||
(let [{:keys [db call-jail-function-n]} (-> initial-db
|
||||
(bots-events/add-active-bot-subscriptions #{"bot1" "bot2"})
|
||||
(update-in [:contacts/contacts "bot1" :subscriptions]
|
||||
bots-events/transform-bot-subscriptions)
|
||||
(bots-events/set-in-bot-db {:bot "bot1"
|
||||
:path [:sliderValue]
|
||||
:value 2}))
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
(deftest init-console-chat
|
||||
(testing "initialising console if console is already added to chats, should not modify anything"
|
||||
(let [db {:chats {const/console-chat-id sign-up/console-chat}}
|
||||
fx (chat-events/init-console-chat db false)]
|
||||
fx (chat-events/init-console-chat db)]
|
||||
(is (= db (:db fx)))
|
||||
(is (= #{:db} (-> fx keys set)))))
|
||||
|
||||
(testing "initialising console without existing account and console chat not initialisated"
|
||||
(let [fresh-db {:chats {}
|
||||
:accounts/current-account-id nil}
|
||||
{:keys [db dispatch-n]} (chat-events/init-console-chat fresh-db false)]
|
||||
{:keys [db dispatch-n]} (chat-events/init-console-chat fresh-db)]
|
||||
(is (= (:current-chat-id db)
|
||||
(:chat-id sign-up/console-chat)))
|
||||
(is (= (:current-chat-id db)
|
||||
|
@ -36,7 +36,7 @@
|
|||
(testing "initialising console with existing account and console chat not initialisated"
|
||||
(let [fresh-db {:chats {}
|
||||
:accounts/current-account-id (:whisper-identity contact)}
|
||||
{:keys [db dispatch-n]} (chat-events/init-console-chat fresh-db false)]
|
||||
{:keys [db dispatch-n]} (chat-events/init-console-chat fresh-db)]
|
||||
(is (= (:current-chat-id db)
|
||||
(:chat-id sign-up/console-chat)))
|
||||
(is (= (:current-chat-id db)
|
||||
|
|
|
@ -3,33 +3,41 @@
|
|||
[status-im.chat.models.input :as input]))
|
||||
|
||||
(def fake-db
|
||||
{:global-commands {:command1 (list {:name "global-command1"})}
|
||||
:chats {"test1" {:contacts [{:identity "0x1"}]
|
||||
:requests nil
|
||||
:seq-arguments ["arg1" "arg2"]
|
||||
:possible-commands (list {:name "global-command1"}
|
||||
{:name "command2"})}
|
||||
"test2" {:contacts [{:identity "0x1"}
|
||||
{:identity "0x2"}]
|
||||
:requests [{:message-id "id1" :type :request1}]
|
||||
:possible-commands (list {:name "global-command1"}
|
||||
{:name "command2"}
|
||||
{:name "command3"})
|
||||
:possible-requests (list {:name "request1"})}
|
||||
"test3" {:contacts [{:identity "0x1"}]
|
||||
:requests [{:message-id "id1" :type :request1}]}
|
||||
"test4" {:contacts [{:identity "0x1"}
|
||||
{:identity "0x2"}]
|
||||
:requests [{:message-id "id2" :type :request2}]
|
||||
:input-metadata {:meta-k "meta-v"}
|
||||
:possible-commands (list {:name "global-command1"}
|
||||
{:name "command2"}
|
||||
{:name "command3"})
|
||||
:possible-requests (list {:name "request1"})}}
|
||||
:contacts/contacts {"0x1" {:commands {:command2 (list {:name "command2"})}
|
||||
:responses nil}
|
||||
"0x2" {:commands {:command3 (list {:name "command3"})}
|
||||
:responses {:request1 (list {:name "request1"})}}}})
|
||||
{:access-scope->commands-responses {#{:global :personal-chats :anonymous :dapps} {:command {"global-command1" ["0x1" :command 0 "global-command1"]}}
|
||||
#{"0x1" :personal-chats :anonymous :dapps} {:command {"command2" ["0x1" :command 2 "command2"]}}
|
||||
#{"0x1" :group-chats :anonymous :dapps} {:command {"command2" ["0x1" :command 4 "command2"]}}
|
||||
#{"0x2" :personal-chats :anonymous :dapps} {:command {"command3" ["0x2" :command 2 "command3"]}}
|
||||
#{"0x2" :group-chats :anonymous :dapps} {:response {"response1" ["0x2" :response 4 "response1"]}}}
|
||||
:chats {"test1" {:contacts [{:identity "0x1"}]
|
||||
:requests nil
|
||||
:seq-arguments ["arg1" "arg2"]}
|
||||
"test2" {:contacts [{:identity "0x1"}
|
||||
{:identity "0x2"}]
|
||||
:group-chat true
|
||||
:requests {"id1" {:message-id "id1"
|
||||
:response "response1"}}}
|
||||
"test3" {:contacts [{:identity "0x1"}]
|
||||
:requests {"id1" {:message-id "id1"
|
||||
:response "request1"}}}
|
||||
"test4" {:contacts [{:identity "0x1"}
|
||||
{:identity "0x2"}]
|
||||
:group-chat true
|
||||
:requests {"id2" {:message-id "id2"
|
||||
:response "response1"}}
|
||||
:input-metadata {:meta-k "meta-v"}}}
|
||||
:contacts/contacts {"0x1" {:dapp? true
|
||||
:command {0 {"global-command1" {:name "global-command1"
|
||||
:ref ["0x1" :command 0 "global-command1"]}}
|
||||
2 {"command2" {:name "command2"
|
||||
:ref ["0x1" :command 2 "command2"]}}
|
||||
4 {"command2" {:name "command2"
|
||||
:ref ["0x1" :command 4 "command2"]}}}
|
||||
:response {}}
|
||||
"0x2" {:dapp? true
|
||||
:command {2 {"command3" {:name "command3"
|
||||
:ref ["0x2" :command 2 "command3"]}}}
|
||||
:response {4 {"response1" {:name "response1"
|
||||
:ref ["0x2" :response 4 "response1"]}}}}}})
|
||||
|
||||
(deftest text->emoji
|
||||
(is (nil? (input/text->emoji nil)))
|
||||
|
@ -58,32 +66,47 @@
|
|||
|
||||
(deftest selected-chat-command
|
||||
(is (= (input/selected-chat-command fake-db "test1" "/global-command1")
|
||||
{:command {:name "global-command1"} :metadata nil :args ["arg1" "arg2"]}))
|
||||
(is (= (input/selected-chat-command fake-db "test2" "/global-command1")
|
||||
{:command {:name "global-command1"} :metadata nil :args []}))
|
||||
{:command {:name "global-command1"
|
||||
:ref ["0x1" :command 0 "global-command1"]}
|
||||
:metadata nil
|
||||
:args ["arg1" "arg2"]}))
|
||||
(is (= (input/selected-chat-command fake-db "test2" "/command2")
|
||||
{:command {:name "command2"
|
||||
:ref ["0x1" :command 4 "command2"]}
|
||||
:metadata nil
|
||||
:args []}))
|
||||
(is (nil? (input/selected-chat-command fake-db "test1" "/command3")))
|
||||
(is (= (input/selected-chat-command fake-db "test1" "/command2")
|
||||
{:command {:name "command2"} :metadata nil :args ["arg1" "arg2"]}))
|
||||
(is (= (input/selected-chat-command fake-db "test2" "/request1 arg1")
|
||||
{:command {:name "request1"} :metadata nil :args ["arg1"]}))
|
||||
{:command {:name "command2"
|
||||
:ref ["0x1" :command 2 "command2"]}
|
||||
:metadata nil
|
||||
:args ["arg1" "arg2"]}))
|
||||
(is (= (input/selected-chat-command fake-db "test2" "/response1 arg1")
|
||||
{:command {:name "response1"
|
||||
:ref ["0x2" :response 4 "response1"]}
|
||||
:metadata nil
|
||||
:args ["arg1"]}))
|
||||
(is (= (input/selected-chat-command fake-db "test4" "/command2 arg1")
|
||||
{:command {:name "command2"} :metadata {:meta-k "meta-v"} :args ["arg1"]})))
|
||||
{:command {:name "command2"
|
||||
:ref ["0x1" :command 4 "command2"]}
|
||||
:metadata {:meta-k "meta-v"}
|
||||
:args ["arg1"]})))
|
||||
|
||||
(deftest current-chat-argument-position
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command1"} "/command1 arg1 arg2 " 0 nil) -1))
|
||||
{:name "command1"} "/command1 arg1 arg2 " 0 nil) -1))
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command1"} "/command1 argument1 arg2 " 9 nil) -1))
|
||||
{:name "command1"} "/command1 argument1 arg2 " 9 nil) -1))
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command1"} "/command1 argument1 arg2 " 10 nil) 0))
|
||||
{:name "command1"} "/command1 argument1 arg2 " 10 nil) 0))
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command1"} "/command1 argument1 arg2 " 19 nil) 0))
|
||||
{:name "command1"} "/command1 argument1 arg2 " 19 nil) 0))
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command1"} "/command1 argument1 arg2 " 20 nil) 1))
|
||||
{:name "command1"} "/command1 argument1 arg2 " 20 nil) 1))
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command2"} "/command2 \"a r g u m e n t 1\" argument2" 30 nil) 1))
|
||||
{:name "command2"} "/command2 \"a r g u m e n t 1\" argument2" 30 nil) 1))
|
||||
(is (= (input/current-chat-argument-position
|
||||
{:name "command3" :command {:sequential-params true}} "/command3" 0 ["test1" "test2"]) 2)))
|
||||
{:name "command3" :command {:sequential-params true}} "/command3" 0 ["test1" "test2"]) 2)))
|
||||
|
||||
(deftest argument-position
|
||||
"Doesn't require a separate test because it simply calls `current-chat-argument-position")
|
||||
|
@ -136,4 +159,4 @@
|
|||
(is (= {} (input/command-dependent-context-params "console" {:name "any"}))))
|
||||
|
||||
(deftest modified-db-after-change
|
||||
"Just a combination of db modifications. Can be skipped now")
|
||||
"Just a combination of db modifications. Can be skipped now")
|
||||
|
|
Loading…
Reference in New Issue