Skip to content

Commit

Permalink
Merge pull request #15 from Beebeeoii/integrations-tele
Browse files Browse the repository at this point in the history
implemented telegram integration
  • Loading branch information
Jia Wei Lee authored Dec 17, 2021
2 parents 3bcfc69 + 34ca64c commit d5ba605
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 22 deletions.
4 changes: 2 additions & 2 deletions FyneApp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ Website = "https://github.com/beebeeoii/lominus"
Icon = "./assets/app-icon.png"
Name = "Lominus"
ID = "com.beebeeoii.lominus"
Version = "1.0.0"
Build = 8
Version = "1.1.0"
Build = 48
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [API](#getting-started-api)
- [Example: Retrieving modules](#getting-started-api-example)
- [Example: Sample Output](#getting-started-api-example-output)
4. [Integrations](#integrations)
5. [Screenshots](#screenshots)
6. [Contributing](#contributing)

Expand All @@ -32,11 +33,12 @@ Lominus removes the hassle to download (or redownload) whenever files are upload
- System notification sync status
- Dark/light mode (based on your system's theme)
- System tray icon (Windows only)
- Telegram integration

To be implemented:

- Notification when new grades are released in gradebooks
- User-defined webhook for Telegram/Notion/custom integrations
- Notion integration
- Custom webhook integration

# Getting Started <a name="getting-started">

Expand Down Expand Up @@ -153,6 +155,24 @@ func main() {
2021/12/09 12:51:49 SOCT101 SoC Teaching Workshop
```

# Integrations <a name="integrations">

## Telegram

As a major messenging platform, Telegram can be used to receive notifications for things such as new grades releases.

### Setting up

1) You need to create a bot on your own via [BotFather](https://telegram.me/BotFather). Take note of the _bot token_ sent to you by **BotFather**.

2) **_Important_**: Drop the bot you have just created a message to enable it to message you.

3) You will also need to figure out your _Telegram ID_. The simplest way to get your _Telegram ID_ is via [UserInfoBot](https://telegram.me/userinfobot).

4) Copy and paste the _bot token_ and your _Telegram ID_ in Lominus, under the Integrations tab.

5) Click save and you should receive a test message from your bot.

# Screenshots <a name="screenshots">

Login Info | Preferences
Expand Down
12 changes: 12 additions & 0 deletions internal/app/integrations/telegram/telegram.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package intTelegram

import (
"path/filepath"

appDir "github.com/beebeeoii/lominus/internal/app/dir"
"github.com/beebeeoii/lominus/internal/lominus"
)

func GetTelegramInfoPath() string {
return filepath.Join(appDir.GetBaseDir(), lominus.TELEGRAM_FILE_NAME)
}
69 changes: 56 additions & 13 deletions internal/cron/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"time"

appApp "github.com/beebeeoii/lominus/internal/app"
intTelegram "github.com/beebeeoii/lominus/internal/app/integrations/telegram"
appPref "github.com/beebeeoii/lominus/internal/app/pref"
"github.com/beebeeoii/lominus/internal/indexing"
logs "github.com/beebeeoii/lominus/internal/log"
"github.com/beebeeoii/lominus/internal/notifications"
"github.com/beebeeoii/lominus/pkg/api"
"github.com/beebeeoii/lominus/pkg/integrations/telegram"
"github.com/beebeeoii/lominus/pkg/pref"

"github.com/go-co-op/gocron"
Expand Down Expand Up @@ -85,21 +87,21 @@ func createJob(frequency int) (*gocron.Job, error) {
return
}

if preferences.Directory != "" {
moduleRequest, modReqErr := api.BuildModuleRequest()
if modReqErr != nil {
notifications.NotificationChannel <- notifications.Notification{Title: "Sync", Content: "Authentication failed"}
logs.WarningLogger.Println(modReqErr)
return
}
moduleRequest, modReqErr := api.BuildModuleRequest()
if modReqErr != nil {
notifications.NotificationChannel <- notifications.Notification{Title: "Sync", Content: "Authentication failed"}
logs.WarningLogger.Println(modReqErr)
return
}

modules, modErr := moduleRequest.GetModules()
if modErr != nil {
notifications.NotificationChannel <- notifications.Notification{Title: "Sync", Content: "Unable to retrieve modules"}
logs.WarningLogger.Println(modErr)
return
}
modules, modErr := moduleRequest.GetModules()
if modErr != nil {
notifications.NotificationChannel <- notifications.Notification{Title: "Sync", Content: "Unable to retrieve modules"}
logs.WarningLogger.Println(modErr)
return
}

if preferences.Directory != "" {
updatedFiles := make([]api.File, 0)
for _, module := range modules {
fileRequest, fileReqErr := api.BuildDocumentRequest(module, api.GET_ALL_FILES)
Expand Down Expand Up @@ -162,6 +164,47 @@ func createJob(frequency int) (*gocron.Job, error) {
notifications.NotificationChannel <- notifications.Notification{Title: "Sync", Content: filesUpdatedNotificationContent}
logs.InfoLogger.Printf("job completed: %s\n", time.Now().Format(time.RFC3339))
}

telegramInfo, telegramInfoErr := telegram.LoadTelegramData(intTelegram.GetTelegramInfoPath())
if telegramInfoErr != nil {
logs.WarningLogger.Println(telegramInfoErr)
return
}

for _, module := range modules {
gradeRequest, gradeReqErr := api.BuildGradeRequest(module)
if gradeReqErr != nil {
notifications.NotificationChannel <- notifications.Notification{Title: "Grades", Content: "Unable to retrieve grades"}
logs.WarningLogger.Println(gradeReqErr)
continue
}

grades, gradesErr := gradeRequest.GetGrades()
if gradesErr != nil {
notifications.NotificationChannel <- notifications.Notification{Title: "Grades", Content: "Unable to retrieve grades"}
logs.WarningLogger.Println(gradesErr)
continue
}

for _, grade := range grades {
frequencyDuration, freqErr := time.ParseDuration(fmt.Sprintf("%dh", preferences.Frequency))
if freqErr != nil {
logs.ErrorLogger.Println(freqErr)
continue
}

if time.Since(time.Unix(grade.LastUpdated, 0)) > frequencyDuration {
continue
}

gradeMsgErr := telegram.SendMessage(telegramInfo.BotApi, telegramInfo.UserId, telegram.GenerateGradeMessageFormat(module.ModuleCode, grade.Name, grade.Comments, grade.Marks, grade.MaxMarks))

if gradeMsgErr != nil {
logs.WarningLogger.Println(gradeMsgErr)
continue
}
}
}
})
}

Expand Down
5 changes: 3 additions & 2 deletions internal/lominus/lominus.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package lominus

const APP_NAME = "Lominus"
const APP_ID = "com.lominus.beebeeoii"
const APP_VERSION = "1.0"
const APP_VERSION = "1.1.0"

const LOCK_FILE_NAME = "lominus.lock"

const PREFERENCES_FILE_NAME = "pref.gob"
const CREDENTIALS_FILE_NAME = "creds.gob"
const PREFERENCES_FILE_NAME = "pref.gob"
const TELEGRAM_FILE_NAME = "telegram.gob"
const JWT_DATA_FILE_NAME = "jwt.gob"
const LOG_FILE_NAME = "lominus.log"
75 changes: 72 additions & 3 deletions internal/ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ui
import (
"fmt"
"runtime"
"strings"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
Expand All @@ -13,13 +14,15 @@ import (

appApp "github.com/beebeeoii/lominus/internal/app"
appAuth "github.com/beebeeoii/lominus/internal/app/auth"
intTelegram "github.com/beebeeoii/lominus/internal/app/integrations/telegram"
appPref "github.com/beebeeoii/lominus/internal/app/pref"
"github.com/beebeeoii/lominus/internal/cron"
"github.com/beebeeoii/lominus/internal/file"
logs "github.com/beebeeoii/lominus/internal/log"
"github.com/beebeeoii/lominus/internal/lominus"
"github.com/beebeeoii/lominus/internal/notifications"
"github.com/beebeeoii/lominus/pkg/auth"
"github.com/beebeeoii/lominus/pkg/integrations/telegram"
"github.com/beebeeoii/lominus/pkg/pref"
"github.com/getlantern/systray"
fileDialog "github.com/sqweek/dialog"
Expand Down Expand Up @@ -61,7 +64,6 @@ func Init() error {
}()

w = mainApp.NewWindow(lominus.APP_NAME)
header := widget.NewLabelWithStyle(fmt.Sprintf("%s v%s", lominus.APP_NAME, lominus.APP_VERSION), fyne.TextAlignCenter, fyne.TextStyle{Bold: true, Italic: false, Monospace: false, TabWidth: 0})

credentialsTab, credentialsUiErr := getCredentialsTab(w)
if credentialsUiErr != nil {
Expand All @@ -73,9 +75,13 @@ func Init() error {
return preferencesErr
}

tabsContainer := container.NewAppTabs(credentialsTab, preferencesTab)
integrationsTab, integrationsErr := getIntegrationsTab(w)
if integrationsErr != nil {
return integrationsErr
}

tabsContainer := container.NewAppTabs(credentialsTab, preferencesTab, integrationsTab)
content := container.NewVBox(
header,
tabsContainer,
layout.NewSpacer(),
getSyncButton(w),
Expand Down Expand Up @@ -241,6 +247,69 @@ func getPreferencesTab(parentWindow fyne.Window) (*container.TabItem, error) {
return tab, nil
}

func getIntegrationsTab(parentWindow fyne.Window) (*container.TabItem, error) {
tab := container.NewTabItem("Integrations", container.NewVBox())

label := widget.NewLabelWithStyle("Telegram", fyne.TextAlignLeading, fyne.TextStyle{Bold: true, Italic: false, Monospace: false, TabWidth: 0})
subLabel := widget.NewRichTextFromMarkdown("Lominus can be linked to your Telegram bot to notify you when new grades are released.")
subLabel.Wrapping = fyne.TextWrapBreak

botApiEntry := widget.NewEntry()
botApiEntry.SetPlaceHolder("Your bot's API token")
userIdEntry := widget.NewEntry()
userIdEntry.SetPlaceHolder("Your account's ID")

telegramInfoPath := intTelegram.GetTelegramInfoPath()

if file.Exists(telegramInfoPath) {
telegramInfo, err := telegram.LoadTelegramData(telegramInfoPath)
if err != nil {
return tab, err
}

botApiEntry.SetText(telegramInfo.BotApi)
userIdEntry.SetText(telegramInfo.UserId)
}

telegramForm := widget.NewForm(widget.NewFormItem("Bot API Token", botApiEntry), widget.NewFormItem("User ID", userIdEntry))

saveButtonText := "Save Telegram Info"
if botApiEntry.Text != "" && userIdEntry.Text != "" {
saveButtonText = "Update Telegram Info"
}

saveButton := widget.NewButton(saveButtonText, func() {
botApi := botApiEntry.Text
userId := userIdEntry.Text

status := widget.NewLabel("Please wait while we send you a test message...")
progressBar := widget.NewProgressBarInfinite()

mainDialog := dialog.NewCustom(lominus.APP_NAME, "Cancel", container.NewVBox(status, progressBar), parentWindow)
mainDialog.Show()

err := telegram.SendMessage(botApi, userId, "Thank you for using Lominus! You have succesfully integrated Telegram with Lominus!\n\nBy integrating Telegram with Lominus, you will be notified of the following whenever Lominus polls for new update based on the intervals set:\n💥 new grades releases\n💥 new announcements (TBC)")
mainDialog.Hide()
if err != nil {
errMessage := fmt.Sprintf("%s: %s", err.Error()[:13], err.Error()[strings.Index(err.Error(), "description")+14:len(err.Error())-2])
dialog.NewInformation(lominus.APP_NAME, errMessage, parentWindow).Show()
} else {
telegram.SaveTelegramData(telegramInfoPath, telegram.TelegramInfo{BotApi: botApi, UserId: userId})
dialog.NewInformation(lominus.APP_NAME, "Test message sent!\nTelegram info saved successfully.", parentWindow).Show()
}
})

tab.Content = container.NewVBox(
label,
widget.NewSeparator(),
subLabel,
telegramForm,
saveButton,
)

return tab, nil
}

func getPreferences() appPref.Preferences {
preference, err := pref.LoadPreferences(appPref.GetPreferencesPath())
if err != nil {
Expand Down
Loading

0 comments on commit d5ba605

Please sign in to comment.