Iam using Gorilla/Sessions.
I got a template page, where the user can choose between different devices.
If he uses one of the submit buttons under each device my controller function should add the id value to my existing session value.
func Cart(w http.ResponseWriter, r *http.Request) {
data := CartData{
Name: "Cart",
Equipment: model.GetEquipment(model.Db),
Pages: []Page{
{
Title: "Meine Geräte",
Active: false,
Link: "/my-equipment",
},
{
Title: "Equipment",
Active: false,
Link: "/equipment",
},
{
Title: "Logout",
Active: false,
Link: "/logout",
},
},
}
equipment,_ := model.GetEquipmentByID(r.FormValue("id"))
session, _ := store.Get(r, "cookie-name")
Strings := strconv.Itoa(equipment.ID)
fmt.Println(Strings)
StringsWithComma := Strings + ","
session.Values["EquipmentIDs"] = session.Values["EquipmentIDs"] + StringsWithComma // THIS CODE LINE DOES NOT WORK, I want to expand "EquipmentIDs" with the new ID
tmpl:= template.Must(template.ParseFiles("template/base_user.html", "template/cart.html"))
tmpl.ExecuteTemplate(w, "base", data)
}
}
Example: User is visiting my Device page. He uses the submit button with id=2
SessionValue["EquipmentIDs"] should be = "2" right now.
After that the User is visiting the Device Page again an uses the submit button with id=6.
Now the SessionValue should be = "2,6"
I am attached to the problem all day and can not get any further
If you have Questions or want to see other parts of my code feel free to ask
Thanks in advance
I thought that you should get original equipment value from the session, combine the equipment ID that user clicks on and save into session for the next request.
I update your code as following:
// ...
equipment, _ := model.GetEquipmentByID(r.FormValue("id"))
session, _ := store.Get(r, "cookie-name")
equipmentIdsStr := strconv.Itoa(equipment.ID)
if original, exist := session.Values["EquipmentIDs"]; exist {
equipmentIdsStr = fmt.Sprintf("%v,%v", original, equipmentIdsStr)
}
session.Values["EquipmentIDs"] = equipmentIdsStr
//You have to save your updated session value
session.Save(r, w)
// ...
Hope this help.
Related
Scroll collapses everytime i use list widget inside scroll container, if i use label widget then scroll container is full width and full height but when i use list widget it just collapses.
Not Working (Scroll collapses)
func ShowListDialog(win fyne.Window, messages []string){
list := widget.NewList(
func() int {
return len(messages)
},
func() fyne.CanvasObject {
return widget.NewLabel("label")
},
func(i widget.ListItemID, o fyne.CanvasObject) {
o.(*widget.Label).SetText(messages[i])
},
)
d := dialog.NewCustom("Messages", "Close" , container.NewScroll(list), win)
d.Resize(fyne.NewSize(500, 400))
d.Show()
}
Working for label (scroll has full width&height)
func ShowLabelDialog(win fyne.Window, message string){
d := dialog.NewCustom("Message", "Close", container.NewScroll(widget.NewLabel(message)), win)
d.Resize(fyne.NewSize(500, 400))
d.Show()
}
The list widget already contains a scroll - removing the outer one should resolve your issue.
I am using the library https://github.com/go-telegram-bot-api/telegram-bot-api
But I do not understand how I can implement the output of buttons and arrows. A lot of data with pagination comes from my api, but I don't understand how to make pages in telegrams. If someone gives an example, I will be very grateful!
This is perfectly implemented in python: https://pypi.org/project/python-telegram-bot-pagination/
But i need for Golang :(
As I checked there were no plugins or wrappers for telegram-bot-api package, so you're gonna have to handle this manually.
Suppose we have this data:
var data = []string{"DummyData1", "DummyData2", "DummyData3", "DummyData4", "DummyData5", "DummyData6", "DummyData7", "DummyData8", "DummyData9", "DummyData10"}
If we're going to show 2 items on each page for 10 items, we would have 5 pages:
var count = 2
var maxPages = len(data) / count // = 5
First we should have a function that calculates data slice and gives us the inlineKeyboardMarkup:
func DummyDataTextMarkup(currentPage, count int) (text string, markup tgbotapi.InlineKeyboardMarkup) {
text = strings.Join(data[currentPage*count:currentPage*count+count], "\n")
var rows []tgbotapi.InlineKeyboardButton
if currentPage > 0 {
rows = append(rows, tgbotapi.NewInlineKeyboardButtonData("Previous", fmt.Sprintf("pager:prev:%d:%d", currentPage, count)))
}
if currentPage < maxPages-1 {
rows = append(rows, tgbotapi.NewInlineKeyboardButtonData("Next", fmt.Sprintf("pager:next:%d:%d", currentPage, count)))
}
markup = tgbotapi.NewInlineKeyboardMarkup(rows)
return
}
Then there is going to be a function to send/edit the calculated data and keyboard by passing chatId, currentPage, count and messageId:
func SendDummyData(chatId int64, currentPage, count int, messageId *int) {
text, keyboard := DummyDataTextMarkup(currentPage, count)
var cfg tgbotapi.Chattable
if messageId == nil {
msg := tgbotapi.NewMessage(chatId, text)
msg.ReplyMarkup = keyboard
cfg = msg
} else {
msg := tgbotapi.NewEditMessageText(chatId, *messageId, text)
msg.ReplyMarkup = &keyboard
cfg = msg
}
bot.Send(cfg)
}
(Note: If we pass a messageId to this function it's going to edit our message with new data)
The next step is to have a CallbackQueryHandler to handle a user's click on inline buttons:
func CallbackQueryHandler(query *tgbotapi.CallbackQuery) {
split := strings.Split(query.Data, ":")
if split[0] == "pager" {
HandleNavigationCallbackQuery(query.Message.MessageID, split[1:]...)
return
}
}
func HandleNavigationCallbackQuery(messageId int, data ...string) {
pagerType := data[0]
currentPage, _ := strconv.Atoi(data[1])
itemsPerPage, _ := strconv.Atoi(data[2])
if pagerType == "next" {
nextPage := currentPage + 1
if nextPage < maxPages {
SendDummyData(chatId, nextPage, itemsPerPage, &messageId)
}
}
if pagerType == "prev" {
previousPage := currentPage - 1
if previousPage >= 0 {
SendDummyData(chatId, previousPage, itemsPerPage, &messageId)
}
}
}
(Note: The first function CallbackQueryHandler is a global callback handler that calls our desired callbackhandler by splitting its query with : and getting the handler's name, here it is pager as we have defined and its handler is called HandleNavigationCallbackQuery).
The last step would be to call CallbackQueryHandler in your update loop as well as sending the initial data to your desired chat:
var chatId = int64(0) // <--- Place Chat Id Here
SendDummyData(chatId, 0, 2, nil) // Send initial data
for update := range updates {
if update.CallbackQuery != nil {
CallbackQueryHandler(update.CallbackQuery)
continue
}
}
You can check the full example on my GitHub's gist here
I'm having trouble sending tokens to many addresses simultaneously. As far as I know, Cosmos does not support batch sending, so I have to make one tx for each recipient, and make sure the account sequence (nonce) is correct for each tx.
So if I specify the account sequence manually, I can create many send transactions at once - but I still have to wait for the node to confirm one tx and update the account sequence before sending the next one.
What can one do in this case?
Cosmos actually does support a MultiSend operation on the bank module, unfortunately it is not wired into the clients for support typically however it is widely used by exhanges such as Coinbase to optimize transfers.
https://github.com/cosmos/cosmos-sdk/blob/e957fad1a7ffd73712cd681116c9b6e09fa3e60b/x/bank/keeper/msg_server.go#L73
I have since been reminded that a single Cosmos transaction can consist of multiple Messages, where each Message is a message to the bank module to send tokens to one account. That's how batch sending works in Cosmos.
Unfortunately this is not available via the command line, so one has to use the SDK to make such a transaction.
Here's a link to CosmJS demonstration of sending a transaction with two messages and two signatures on the v0.39.x LTS release of the Cosmos SDK here (hat tip Ethan Frey from Confio for pointing this out)
In case the link changes at any point here's the code:
describe("appendSignature", () => {
it("works", async () => {
pendingWithoutLaunchpad();
const wallet0 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(0));
const wallet1 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(1));
const client0 = new SigningCosmosClient(launchpad.endpoint, faucet.address0, wallet0);
const client1 = new SigningCosmosClient(launchpad.endpoint, faucet.address1, wallet1);
const msg1: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: faucet.address0,
to_address: makeRandomAddress(),
amount: coins(1234567, "ucosm"),
},
};
const msg2: MsgSend = {
type: "cosmos-sdk/MsgSend",
value: {
from_address: faucet.address1,
to_address: makeRandomAddress(),
amount: coins(1234567, "ucosm"),
},
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "160000", // 2*80k
};
const memo = "This must be authorized by the two of us";
const signed = await client0.sign([msg1, msg2], fee, memo);
const cosigned = await client1.appendSignature(signed);
expect(cosigned.msg).toEqual([msg1, msg2]);
expect(cosigned.fee).toEqual(fee);
expect(cosigned.memo).toEqual(memo);
expect(cosigned.signatures).toEqual([
{
pub_key: faucet.pubkey0,
signature: jasmine.stringMatching(base64Matcher),
},
{
pub_key: faucet.pubkey1,
signature: jasmine.stringMatching(base64Matcher),
},
]);
// Ensure signed transaction is valid
const broadcastResult = await client0.broadcastTx(cosigned);
assertIsBroadcastTxSuccess(broadcastResult);
});
});
For doing this kind of thing in Golang, like with the Cosmos SDK client CLI, you can take the distribution module as an example: https://github.com/cosmos/cosmos-sdk/blob/master/x/distribution/client/cli/tx.go#L165-L180
msgs := make([]sdk.Msg, 0, len(validators))
for _, valAddr := range validators {
val, err := sdk.ValAddressFromBech32(valAddr)
if err != nil {
return err
}
msg := types.NewMsgWithdrawDelegatorReward(delAddr, val)
if err := msg.ValidateBasic(); err != nil {
return err
}
msgs = append(msgs, msg)
}
chunkSize, _ := cmd.Flags().GetInt(FlagMaxMessagesPerTx)
return newSplitAndApply(tx.GenerateOrBroadcastTxCLI, clientCtx, cmd.Flags(), msgs, chunkSize)
In one view, I have this func to signUp and get userName
func signUp() {
if self.email != "" {
if self.password == self.repass {
session.signUp(email: email, password: password) { (result, error) in
if error != nil {
self.error = error!.localizedDescription
//self.error = "A senha deve ter 6 caracteres ou mais"
}
else{
self.email = ""
self.password = ""
let db = Firestore.firestore()
db.collection("Users").document(result!.user.uid).setData(["userName": userName]) { (error) in
if error != nil{
}
}
}
}
}
else{
self.error = "Senhas não coincidem"
}
}
else{
self.error = "Complete todos espaços"
}
}
In other view, I want to get the userName the user typed ad display it, but for this I need to link both views to get access to func SignUp. How to do it?
EDIT:
Based on the answer I was given, I did the corresponding changes:
SessionStore:
#Published var session: User? = nil
var handle: AuthStateDidChangeListenerHandle?
#Published var userName: String = ""
func listen() {
handle = Auth.auth().addStateDidChangeListener({ [self] (auth, user) in
if let user = user {
self.session = User(uid: user.uid, email: user.email!, userName: userName)
}
else {
self.session = nil
}
})
}
struct User {
var uid:String
var email:String
var userName: String
}
HomeView ----> var userName: User
Text(userName.userName)
explaining how my code works: the #main view is MedAppApp: App. From there, the code goes to ContentView. if session.session != nil, TransitionView, else, SignView. Continuing from SignView, there I have both SignInView and SignUpView views, which they have Button(action: signIn) and Button(action: Signup), respectively. Continuing from TransitionView, there is where I have:
struct TransitionView: View {
#StateObject var LocationModel = LocationViewModel()
#State var userName = User(uid: "", email: "", userName: "")
var body: some View {
HomeView(LocationModel: LocationModel, userName: userName)
}
}
#State var userName =... and userName: userName needed to be added
The app launches, I can signUp with username (and its stored in Firestore with uid as document), but the userName isn't displayed. I think the problem must be in User(uid: "", email: "", password: ""). I didn't know what to add there.
By the way, Im thinking about maintaining the code and then get the userName by using the document id (that already is the user uid) so I can access it. Don't have a final answer yet, but Im working on it.
EDIT2:
I added #StateObject var session = SessionStore()
Tried to use:
#State var userName = User(uid: SessionStore().session?.uid ?? "", email: SessionStore().session?.email ?? "", userName: SessionStore().session?.userName ?? "")
Still doesn't work
Your question is too open-ended, but I'll provide an answer that hopefully will set you up on the right direction.
First, in SwiftUI, separate the concept of a view (i.e. how things are arranged on the screen) from the concept of data that drives the views. What I mean by that is, if you need some data, like userName, the code that obtains it shouldn't know or care about which view will make use of it. And Views, shouldn't care how the data is obtained.
Second, in SwiftUI, views should not be thought of as "entities" (like in UIKit) with their own life cycles. They are just declarative statements that define how the UI is arranged.
For example, suppose you have this (fake) class that signs the user in, and when signed-in, populates the userName property. The instance of this class is a view model.
struct User {
let userName: String
}
class Session: ObservableObject {
#Published var user: User? = nil
func signIn(_ completion: (User) -> ()) {
DispatchQueue.main.asyncAfter(.now() + 0.5) {
self.user = User(userName: "Mateus") // fake sign-in
completion(self.user) // not really used in this example
}
}
}
#Published and ObservableObject in combination are how SwiftUI views know to react to changes to this object. Read more about them, if you don't know what they do.
Next, design a root view that decides what inner view to display depending on whether the user is signed in or not:
struct RootView: View {
#StateObject var session = Session()
var body: some View {
VStack() {
if let user = session.user {
ContentView(user: user) // view is conditionally rendered
} else {
Button("sign in") { self.signIn() }
}
}
}
func signIn() {
self.session.signIn() {
print("signed in...!")
}
}
}
#StateObject manages the life cycle of the view model for the view.
As you see above, ContentView will only be rendered when session.user is not nil (i.e. when user has signed in), so the view is driven by changes in data. I did not need to create a ContentView instance anywhere ahead of time.
Then ContentView is straightforward:
struct ContentView: View {
var user: User
var body: some View {
Text("signed-in username: \(user.userName)")
}
}
I am looking into writing a CLI application in Go.
One of the requirements is auto complete. Not of the command itself but of possible options.
Imagine I want to add a new entry using the CLI. Each entry can have a category.
The categories are available in a slice. What I want to do now is to enable the user to tab through the available categories when typing in add.
I am aware of libraries like https://github.com/chzyer/readline and https://github.com/spf13/cobra but could not find if or how they support this.
Thank you #ain and #JimB for pointing me in the right direction.
Based on the example provided at https://github.com/chzyer/readline/tree/master/example/readline-demo I was able to achieve the desired functionality.
The following code has to main commands newEntry and newCategory. If the user types newEntry and than presses TAB he can choose from the available categories. The newCategory command allow to add a new custom category which is immediately available the next time newEntry is executed.
package main
import (
"io"
"log"
"strconv"
"strings"
"github.com/chzyer/readline"
)
// completer defines which commands the user can use
var completer = readline.NewPrefixCompleter()
// categories holding the initial default categories. The user can add categories.
var categories = []string{"Category A", "Category B", "Category C"}
var l *readline.Instance
func main() {
// Initialize config
config := readline.Config{
Prompt: "\033[31m»\033[0m ",
HistoryFile: "/tmp/readline.tmp",
AutoComplete: completer,
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
}
var err error
// Create instance
l, err = readline.NewEx(&config)
if err != nil {
panic(err)
}
defer l.Close()
// Initial initialization of the completer
updateCompleter(categories)
log.SetOutput(l.Stderr())
// This loop watches for user input and process it
for {
line, err := l.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
line = strings.TrimSpace(line)
// Checking which command the user typed
switch {
// Add new category
case strings.HasPrefix(line, "newCategory"):
// Remove the "newCategory " prefix (including space)
if len(line) <= 12 {
log.Println("newCategory <NameOfCategory>")
break
}
// Append everything that comes behind the command as the name of the new category
categories = append(categories, line[12:])
// Update the completer to make the new category available in the cmd
updateCompleter(categories)
// Program is closed when user types "exit"
case line == "exit":
goto exit
// Log all commands we don't know
default:
log.Println("Unknown command:", strconv.Quote(line))
}
}
exit:
}
// updateCompleter is updates the completer allowing to add new command during runtime. The completer is recreated
// and the configuration of the instance update.
func updateCompleter(categories []string) {
var items []readline.PrefixCompleterInterface
for _, category := range categories {
items = append(items, readline.PcItem(category))
}
completer = readline.NewPrefixCompleter(
readline.PcItem("newEntry",
items...,
),
readline.PcItem("newCategory"),
)
l.Config.AutoComplete = completer
}