How to display HTML markup from telegram telego Go bot? - go

I'd like to push a formatted message to to clients from my bot in much the same way as the Durger King app does. In response to any input to the bot a message showing for formatted 'Let's get started' is displayed along with a picture. Underneath there is order food WebApp button which opens the PWA.
Is this simply and image or is it formatted HTML, which would possibly be easier to manage.
How can one send either a an image or formatted HTML using the telego Go bot.

Here's what is probably the wrong way of achieving this:
var (helloMsg = &tele.Message{Text: "<b>Let's get started!</b>🍟"})
func main() {
pref := tele.Settings{
Token: os.Getenv("TOKEN"),
Poller: &tele.LongPoller{Timeout: 5 * time.Second},
}
b, err := tele.NewBot(pref)
if err != nil {
log.Fatal(err)
return
}
b.Handle("/start", func(c tele.Context) error {
log.Println("Detected Start")
b.Send(c.Message().Sender, helloMsg.Text, &tele.SendOptions{
ParseMode: "HTML",
}, webapp)
return nil
})}
}
I haven't tried to see if it is possible to use the context instead of the bot itself, and returning nil probably isn't a great idea. But essentially you this is setting the ParseMode to HTML and somehow the emoji can be pasted in...
This is what it looks like:

Here's the version using the context:
b.Handle("/start", func(c tele.Context) error {
log.Println("Detected Start")
b.Send(c.Message().Sender, helloMsg.Text, &tele.SendOptions{
ParseMode: "HTML",
}, webapp)
return nil
})

Related

Is there a way to add collaborators to a Google Sheet using the Golang Client Library or REST API?

I am able to create a new spreadsheet with the gsheets client library, and my next step is to add editors to that newly created sheet so that the sheet can be accessed by the users of the application
Here is the code for creating the sheet:
ctx := context.Background()
srv, err := gsheets.NewService(ctx)
if err != nil {
log.Printf("Unable to retrieve Sheets client: %v", err)
}
sp := &gsheets.Spreadsheet{
Properties: &gsheets.SpreadsheetProperties{
Title: groupName,
},
}
spreadsheet, err := srv.Spreadsheets.Create(sp).Do()
if err != nil {
return nil, err
}
I have searched through the golang client library docs and the REST API docs, and I am unable to find anything related to adding collaborators
I was expecting there to be some request object that allows me to add a collaborator using their email and role:
req := gsheets.Request{
AddCollaborator: &gsheets.AddCollaboratorRequest{
Email: "person#gmail.com",
Role: "editor",
},
}
busr := &gsheets.BatchUpdateSpreadsheetRequest{
Requests: []*gsheets.Request{&req},
}
res, err := srv.Spreadsheets.BatchUpdate(spreadsheetId, busr).Do()
or at the very least I was expecting there to be an API endpoint where I can achieve the same result
I am also curious if there is a way to create this new spreadsheet as read only to the public? This would at least allow me to continue developing
It is possible to add editors with the google.golang.org/api/sheets/v4 library.
You can simply create a spreadsheet with:
func (r *SpreadsheetsService) Create(spreadsheet *Spreadsheet) *SpreadsheetsCreateCall
and add editors with Editor type:
type Editors struct {
...
// Users: The email addresses of users with edit access to the protected
// range.
Users []string `json:"users,omitempty"`
...
}
Check library docs for more details.

How to handle SPA urls correctly in Golang?

I am trying to embed and serve my frontend (nextjs with static export) with echo. I am currently using:
//go:embed all:frontend/out
var FrontendFS embed.FS
func BuildFrontendFS() http.FileSystem {
build, err := fs.Sub(FrontendFS, "frontend/out")
if err != nil {
log.Fatal(err)
}
return http.FS(build)
}
e := echo.New()
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
Filesystem: BuildFrontendFS(),
HTML5: true,
}))
e.Logger.Fatal(e.Start(":1323"))
It works great however when I try to open a url like localhost:1323/example it routes back to index.html. The problem is that there is a page called example.html and I am expecting to see that page instead. If I call the url like localhost:1323/example.html it works.
Any ideas how I can solve this so that I can just use localhost:1323/example ?
I see an ./out directory being referenced, so it looks like you're exporting to static HTML. If that's the case, enable the trailingSlash setting in your next.config.js:
module.exports = {
trailingSlash: true,
}
./example.html will become ./example/index.html after the export.

GO Gin Keeps returning empty status if Any part of my code returns false

I am relatively new to Golang and Gin(framework)
I am writing some really simple API endpoints . But I notice something really weird about Gin, if there is any codition or function within my code that returns false the rest of my code or conditions does not get executed and Gin just returns a JSON with empty status :
{"status":""}
Here is a very simple code to explain what I mean
In a functions.go file I have :
func VerifyUserLogin(username,password,userAgent string) (string, string) {
userData := Users{}
userQueryColumn := "username=?"
// if they are trying to login with email
if nEmailHelpers.EmailIsValid(username) == true{
userQueryColumn = "email=?"
}
if getUserData := db.Select("password").Where(userQueryColumn, strings.ToLower(username)).First(&userData); getUserData.Error != nil {
// Meaning there was an error, most likely no data found , so we just return false todo improve this error handling later to handle more specific errors
return "", feedback["InvalidLogin"]
} else {
if getUserData.RowsAffected == 1 {
if nSecurityHelpers.CheckPasswordHash(password, userData.Password)==true {
token, tokenError := CreateToken(username, userAgent, false, 60)
if tokenError == nil {
return token, feedback["ValidLogin"]
} else {
return "", feedback["TokenNotGenerated"]
}
} else {
return "", feedback["InvalidLogin"]
}
}
return "", feedback["InvalidLogin"]
}
}
In another go file that references the functions.go file I have :
func main(){
router := gin.Default()
router.POST ("login",loginUser)
router.Run()
}
var feedback = userFeedback.Users()
// loginUser function to login a user
func loginUser(c *gin.Context){
requestBody := neielRequestsHelpers.RequestBody(c)
username := requestBody["username"]
password := requestBody["password"]
userAgent := c.Request.Header.Get("User-Agent")
token, loginMessage := userFunctions.VerifyUserLogin(username,password,userAgent)
// todo come back and fix proper error message when user does not exist
fmt.Println(loginMessage)
if loginMessage==feedback["ValidLogin"]{
c.JSON(http.StatusOK, gin.H{"status":loginMessage,"token":token})
}else{
c.JSON(http.StatusUnauthorized, gin.H{"status":feedback["InvalidLogin"]})
}
}
If all my inputs are correct , all goes well (Username exists and password is correct). But I have to handle scenario where username or password is invalid .If for any reason getUserData or nSecurityHelpers.CheckPasswordHash() is false , or any function for that matter returns a boolean of false . The entire function just terminates and doesn't allow me handle the error the way I want and output custom JSON response. I just get this {"status":""}
I am 100% sure this issue is from Gin , but I don't know what to activate or deactivate to allow me handle errors on my own. I have read the docs, but its obvious I am missing something .
Kindly help me please .
I have resolved this, thanks to everyone that tried to help
It was a typo error causing the issue "InValidLogin" instead of "InvalidLogin" in another file.
It was really subtle

Google Directory API add Custom Schema/Update it to Users per google API (in go)

I am trying to upload a CustomSchema to all Users of a company in GSuite. This Custom Schema contains their Github Usernames, which I extracted with the github API.
The problem is, after running the code, the account in Gsuite is not added.
Relevant code (A connection to GSuite with admin Authentication is established, the map has all user entries. If you still want more code, I can provide you with it - just trying to keep it simple):
for _, u := range allUsers.Users {
if u.CustomSchemas != nil {
log.Printf("%v", string(u.CustomSchemas["User_Names"]))
}else{
u.CustomSchemas = map[string]googleapi.RawMessage{}
}
nameFromGsuite := u.Name.FullName
if githubLogin, ok := gitHubAccs[nameFromGsuite]; ok {
userSchemaForGithub := GithubAcc{GitHub: githubLogin}
jsonRaw, err := json.Marshal(userSchemaForGithub)
if err != nil {
log.Fatalf("Something went wrong logging: %v", err)
}
u.CustomSchemas["User_Names"] = jsonRaw
adminService.Users.Update(u.Id, u)
} else {
log.Printf("User not found for %v\n", nameFromGsuite)
}
}
This is the struct for the json encoding:
type GithubAcc struct {
GitHub string `json:"GitHub"`
}
For anyone stumbling upon this.
Everything in the code snippet is correct. By the way the method is written, I expected that adminService.Users.Update() actually updates the user. Instead, it returns an UserUpdatesCall.
You need to execute that update by calling .Do()
From the API:
Do executes the "directory.users.update" call.
So the solution is to change adminService.Users.Update(u.Id, u)
into adminService.Users.Update(u.Id, u).Do()

Sentry Go Integration, how to specify error level?

According to the official docs https://docs.sentry.io/clients/go/ you can log errors in Sentry from a golang project with:
// For Errors
raven.CapturePanic(func() {
// do all of the scary things here
}, nil)
// For panic
if err != nil {
raven.CaptureErrorAndWait(err, nil)
log.Panic(err)
}
This works like a charm, the problem is in Sentry both functions are logged with level 'Error'. Anyone knows how can the logging level be specified for each call? In Python is very explicit, but I don't see it for Go.
Using the sentry-go SDK, the Level is set on the Scope.
Documentation:
https://pkg.go.dev/github.com/getsentry/sentry-go?tab=doc#Scope.SetLevel
https://pkg.go.dev/github.com/getsentry/sentry-go?tab=doc#Level
Example:
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetLevel(sentry.LevelFatal)
sentry.CaptureException(errors.New("example error"))
})
I followed the advice in the comments, and came up with this:
// sentryErrorCapture sends error data to Sentry asynchronously. Use for non-Fatal errors.
var sentryErrorCapture = func(err error, severity raven.Severity, tags map[string]string, interfaces ...raven.Interface) string {
packet := newSentryPackage(err, severity, tags, interfaces...)
eventID, _ := raven.Capture(packet, tags)
return eventID
}
func newSentryPackage(err error, severity raven.Severity, tags map[string]string, interfaces ...raven.Interface) (packet *raven.Packet) {
interfaces = append(interfaces,
raven.NewException(err, raven.GetOrNewStacktrace(err, 1, 3, raven.IncludePaths())))
packet = &raven.Packet{
Message: err.Error(),
Level: severity,
Interfaces: interfaces,
Extra: getSentryExtraInfo(),
}
return
}
When I want to log an error specifying the level I call: sentryErrorCapture(err, raven.ERROR, nil).

Resources