Skip to content

Commit

Permalink
Allow admins to send service notifications (#38)
Browse files Browse the repository at this point in the history
* Allow admins to send service notifications

Closes #33

* Fix test
  • Loading branch information
LucaBernstein authored Nov 25, 2021
1 parent 8c5bd7e commit 4c82da7
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
67 changes: 67 additions & 0 deletions bot/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const (
CMD_DELETE_ALL = "deleteAll"
CMD_SUGGEST = "suggestions"
CMD_CURRENCY = "currency"

CMD_ADM_NOTIFY = "admin_notify"
)

func (bc *BotController) commandMappings() []*CMD {
Expand All @@ -70,6 +72,8 @@ func (bc *BotController) commandMappings() []*CMD {
{Command: CMD_CURRENCY, Handler: bc.commandCurrency, Help: "Set the currency to use globally for subsequent transactions"},
{Command: CMD_ARCHIVE_ALL, Handler: bc.commandArchiveTransactions, Help: "Archive recorded transactions"},
{Command: CMD_DELETE_ALL, Handler: bc.commandDeleteTransactions, Help: "Permanently delete recorded transactions"},

{Command: CMD_ADM_NOTIFY, Handler: bc.commandAdminNofify, Help: "Send notification to user(s): /" + CMD_ADM_NOTIFY + " [chatId] \"<message>\""},
}
}

Expand All @@ -86,10 +90,15 @@ func (bc *BotController) commandStart(m *tb.Message) {
func (bc *BotController) commandHelp(m *tb.Message) {
log.Printf("Sending help to %s (ChatID: %d)", m.Chat.Username, m.Chat.ID)
helpMsg := ""
adminCommands := []*CMD{}
for i, cmd := range bc.commandMappings() {
if cmd.Help == "" {
continue
}
if strings.HasPrefix(cmd.Command, "admin") {
adminCommands = append(adminCommands, cmd)
continue
}
if i != 0 {
helpMsg += "\n"
}
Expand All @@ -99,6 +108,12 @@ func (bc *BotController) commandHelp(m *tb.Message) {
}
helpMsg += fmt.Sprintf("/%s%s - %s", cmd.Command, optional, cmd.Help)
}
if len(adminCommands) > 0 && bc.Repo.UserIsAdmin(m) {
helpMsg += "\n\n** ADMIN COMMANDS **"
for _, cmd := range adminCommands {
helpMsg += fmt.Sprintf("\n/%s - %s", cmd.Command, cmd.Help)
}
}
bc.Bot.Send(m.Sender, helpMsg, clearKeyboard())
}

Expand Down Expand Up @@ -200,6 +215,58 @@ func (bc *BotController) commandCurrency(m *tb.Message) {
bc.Bot.Send(m.Sender, fmt.Sprintf("For all future transactions the currency '%s' will be used.", currency))
}

type ReceiverImpl struct {
chatId string
}

func (r ReceiverImpl) Recipient() string {
return r.chatId
}

func (bc *BotController) commandAdminNofify(m *tb.Message) {
isAdmin := bc.Repo.UserIsAdmin(m)
if !isAdmin {
log.Printf("Received admin command from non-admin user (%s, %d). Ignoring (treating as normal text input).", m.Chat.Username, m.Chat.ID)
bc.handleTextState(m)
return
}
text := strings.Split(m.Text, "\"")
var notificationMessage string
if len(text) >= 2 {
notificationMessage = text[1]
}
if len(text) == 0 || len(notificationMessage) == 0 {
bc.Bot.Send(m.Sender, "Something went wrong splitting your command parameters. Did you specify a text in double quotes (\")?")
return
}
// text[0] = /command [chatId]
command := strings.Split(strings.TrimRight(text[0], " "), " ")

if len(command) == 0 || len(command) >= 3 {
// invalid argument count
bc.Bot.Send(m.Sender, "Please check the command syntax")
return
}

var target string
if len(command) == 2 {
target = command[1]
}

receivers := bc.Repo.IndividualsWithNotifications(m.Chat.ID, target)
if len(receivers) == 0 {
bc.Bot.Send(m.Sender, "No receivers found to send notification to (you being excluded).")
return
}

for _, recipient := range receivers {
bc.Bot.Send(ReceiverImpl{chatId: recipient}, "*** Service notification ***\n\n"+notificationMessage)
log.Printf("Sent notification to %s", recipient)
// TODO: Add message like 'If you don't want to receive further service notifications, you can turn them off in the /settings with '/settings notif off'.'
// GitHub-issue: #28
}
}

func (bc *BotController) handleTextState(m *tb.Message) {
tx := bc.State.Get(m)
if tx == nil {
Expand Down
58 changes: 58 additions & 0 deletions db/crud/auth_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package crud

import (
"log"
"strconv"
"time"

tb "gopkg.in/tucnak/telebot.v2"
Expand Down Expand Up @@ -112,6 +113,63 @@ func (r *Repo) UserGetCurrency(m *tb.Message) string {
return DEFAULT_CURRENCY
}

func (r *Repo) UserIsAdmin(m *tb.Message) bool {
rows, err := r.db.Query(`
SELECT "isAdmin"
FROM "auth::user"
WHERE "tgChatId" = $1 AND "tgUserId" = "tgChatId" -- is a private chat
`, m.Chat.ID)
if err != nil {
log.Printf("Encountered error while getting user currency (user: %d): %s", m.Chat.ID, err.Error())
}
defer rows.Close()

isAdmin := false
if rows.Next() {
err = rows.Scan(&isAdmin)
if err != nil {
log.Printf("Encountered error while scanning user isAdmin into var (user: %d): %s", m.Chat.ID, err.Error())
return false
}
}
return isAdmin
}

func (r *Repo) IndividualsWithNotifications(myChatId int64, chatId string) (recipients []string) {
query := `
SELECT "tgChatId"
FROM "auth::user"
WHERE "tgUserId" = "tgChatId" -- is a private chat
AND "tgChatId" != $1
`
params := []interface{}{myChatId}

if chatId != "" {
i, err := strconv.ParseInt(chatId, 10, 64)
if err != nil {
log.Printf("Error while parsing chatId to int64: %s", err.Error())
}
query += `AND "tgChatId" = $2`
params = append(params, i)
}
rows, err := r.db.Query(query, params...)
if err != nil {
log.Printf("Encountered error while getting user currency: %s", err.Error())
}
defer rows.Close()

var rec string
if rows.Next() {
err = rows.Scan(&rec)
if err != nil {
log.Printf("Encountered error while scanning into var: %s", err.Error())
return []string{}
}
recipients = append(recipients, rec)
}
return
}

func (r *Repo) UserSetCurrency(m *tb.Message, currency string) error {
_, err := r.db.Exec(`
UPDATE "auth::user"
Expand Down
1 change: 1 addition & 0 deletions db/migrations/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func Migrate(db *sql.DB) {
migrationWrapper(v1, 1)(db)
migrationWrapper(v2, 2)(db)
migrationWrapper(v3, 3)(db)
migrationWrapper(v4, 4)(db)

fmt.Println("Migrations ran through. Schema version:", schema(db))
}
Expand Down
21 changes: 21 additions & 0 deletions db/migrations/v4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package migrations

import (
"database/sql"
"log"
)

func v4(db *sql.Tx) {
v4UserAdmin(db)
}

func v4UserAdmin(db *sql.Tx) {
sqlStatement := `
ALTER TABLE "auth::user"
ADD "isAdmin" BOOLEAN DEFAULT FALSE NOT NULL;
`
_, err := db.Exec(sqlStatement)
if err != nil {
log.Fatal(err)
}
}

0 comments on commit 4c82da7

Please sign in to comment.