-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* clean up * split into small chunks * tests * code review * refactoring + ignore * refactoring * clean up * tests * unit tests * more tests * more tests --------- Co-authored-by: Maksym Bilan <>
- Loading branch information
1 parent
01afb7d
commit b6a45f0
Showing
12 changed files
with
528 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package scheduler | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/capymind/internal/database" | ||
"github.com/capymind/internal/helpers" | ||
"github.com/capymind/internal/translator" | ||
) | ||
|
||
func prepareAdminStats(ctx *context.Context, locale translator.Locale, adminStorage database.AdminStorage, feedbackStorage database.FeedbackStorage) *string { | ||
stats := helpers.GetStats(ctx, locale, adminStorage, feedbackStorage) | ||
|
||
var finalString string | ||
for _, stat := range stats { | ||
finalString += stat + "\n" | ||
} | ||
return &finalString | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package scheduler | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/capymind/internal/mocks" | ||
"github.com/capymind/internal/translator" | ||
) | ||
|
||
func TestAdminStats(t *testing.T) { | ||
context := context.Background() | ||
locale := translator.EN | ||
adminStorage := mocks.AdminStorageMock{} | ||
feedbackStorage := mocks.FeedbackStorageMock{} | ||
|
||
response := prepareAdminStats(&context, locale, adminStorage, feedbackStorage) | ||
|
||
if *response != "The total number of users is 100\nThe total number of active users is 75\nThe total number of notes is 999\n\nFeedback from last week 📈\n\nJohn \nDoe\n:\n\nTest feedback\n\nJohn \nDoe\n:\n\nTest feedback 2\n\n" { | ||
t.Errorf("Expected valid response, got %s", *response) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package scheduler | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"log" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/capymind/internal/botservice" | ||
"github.com/capymind/internal/database" | ||
"github.com/capymind/internal/taskservice" | ||
"github.com/capymind/internal/translator" | ||
) | ||
|
||
func prepareMessage(user *database.User, ctx *context.Context, offset int, messageType taskservice.MessageType, message string, isCloud bool) { | ||
//coverage:ignore | ||
defer wg.Done() | ||
|
||
log.Printf("[Scheduler] Schedule a message for user: %s", user.ID) | ||
|
||
userLocale := translator.Locale(*user.Locale) | ||
|
||
var localizedMessage *string | ||
if messageType == taskservice.WeeklyAnalysis { | ||
localizedMessage = prepareWeeklyAnalysis(user, ctx, userLocale, noteStorage, aiService) | ||
} else if messageType == taskservice.UserStats { | ||
// Send only to active users | ||
if !user.IsActive() { | ||
return | ||
} | ||
localizedMessage = prepareUserStats(user, ctx, userLocale, noteStorage) | ||
} else if messageType == taskservice.AdminStats { | ||
// Send only to admins | ||
if !database.IsAdmin(user.Role) { | ||
return | ||
} | ||
localizedMessage = prepareAdminStats(ctx, userLocale, adminStorage, feedbackStorage) | ||
} else { | ||
msg := translator.Translate(userLocale, message) | ||
localizedMessage = &msg | ||
} | ||
|
||
if localizedMessage == nil { | ||
return | ||
} | ||
|
||
var scheduledTime time.Time | ||
if isCloud { | ||
scheduledTime = time.Now().Add(time.Duration(offset) * time.Hour) | ||
scheduledTime = scheduledTime.Add(-time.Duration(*user.SecondsFromUTC) * time.Second) | ||
} else { | ||
// For local testing, schedule the message in 10 seconds | ||
scheduledTime = time.Now().Add(10 * time.Second) | ||
} | ||
|
||
scheduledMessage := taskservice.ScheduledTask{ | ||
ChatID: user.ChatID, | ||
Text: *localizedMessage, | ||
Type: messageType, | ||
Locale: userLocale, | ||
} | ||
|
||
tasks.Schedule(ctx, scheduledMessage, scheduledTime) | ||
} | ||
|
||
// Send a message to a user | ||
func SendMessage(w http.ResponseWriter, r *http.Request) { | ||
//coverage:ignore | ||
var msg taskservice.ScheduledTask | ||
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil { | ||
log.Printf("[Scheduler] Could not parse message %s", err.Error()) | ||
return | ||
} | ||
|
||
result := prepareBotResult(msg) | ||
bot.SendResult(msg.ChatID, result) | ||
log.Printf("[Scheduler] Message sent to user: %d", msg.ChatID) | ||
} | ||
|
||
func prepareBotResult(scheduledTask taskservice.ScheduledTask) botservice.BotResult { | ||
var result botservice.BotResult | ||
switch scheduledTask.Type { | ||
case taskservice.Morning, taskservice.Evening: | ||
var button botservice.BotResultTextButton = botservice.BotResultTextButton{ | ||
TextID: "make_record_to_journal", | ||
Locale: scheduledTask.Locale, | ||
Callback: "/note", | ||
} | ||
result = botservice.BotResult{ | ||
TextID: scheduledTask.Text, | ||
Locale: scheduledTask.Locale, | ||
Buttons: []botservice.BotResultTextButton{button}, | ||
} | ||
case taskservice.Feedback: | ||
var button botservice.BotResultTextButton = botservice.BotResultTextButton{ | ||
TextID: "feedback_button", | ||
Locale: scheduledTask.Locale, | ||
Callback: "/support", | ||
} | ||
result = botservice.BotResult{ | ||
TextID: scheduledTask.Text, | ||
Locale: scheduledTask.Locale, | ||
Buttons: []botservice.BotResultTextButton{button}, | ||
} | ||
default: | ||
result = botservice.BotResult{ | ||
TextID: scheduledTask.Text, | ||
Locale: scheduledTask.Locale, | ||
} | ||
} | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package scheduler | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/capymind/internal/taskservice" | ||
) | ||
|
||
func TestPrepareMorningMessage(t *testing.T) { | ||
scheduledMessage := taskservice.ScheduledTask{ | ||
ChatID: 1, | ||
Text: "Bot result", | ||
Type: taskservice.Morning, | ||
Locale: "en", | ||
} | ||
|
||
result := prepareBotResult(scheduledMessage) | ||
if result.TextID != "Bot result" { | ||
t.Error("Expected Bot result, got nil") | ||
} | ||
if result.Locale != "en" { | ||
t.Error("Expected en, got nil") | ||
} | ||
if result.Buttons[0].TextID != "make_record_to_journal" { | ||
t.Error("Expected make_record_to_journal, got nil") | ||
} | ||
if result.Buttons[0].Locale != "en" { | ||
t.Error("Expected en, got nil") | ||
} | ||
if result.Buttons[0].Callback != "/note" { | ||
t.Error("Expected /note, got nil") | ||
} | ||
} | ||
|
||
func TestPrepareFeedbackMessage(t *testing.T) { | ||
scheduledMessage := taskservice.ScheduledTask{ | ||
ChatID: 1, | ||
Text: "Bot result", | ||
Type: taskservice.Feedback, | ||
Locale: "en", | ||
} | ||
|
||
result := prepareBotResult(scheduledMessage) | ||
if result.TextID != "Bot result" { | ||
t.Error("Expected Bot result, got nil") | ||
} | ||
if result.Locale != "en" { | ||
t.Error("Expected en, got nil") | ||
} | ||
if result.Buttons[0].TextID != "feedback_button" { | ||
t.Error("Expected feedback_button, got nil") | ||
} | ||
if result.Buttons[0].Locale != "en" { | ||
t.Error("Expected en, got nil") | ||
} | ||
if result.Buttons[0].Callback != "/support" { | ||
t.Error("Expected /support, got nil") | ||
} | ||
} | ||
|
||
func TestPrepareRegularMessage(t *testing.T) { | ||
scheduledMessage := taskservice.ScheduledTask{ | ||
ChatID: 1, | ||
Text: "Bot result", | ||
Type: taskservice.Regular, | ||
Locale: "en", | ||
} | ||
|
||
result := prepareBotResult(scheduledMessage) | ||
if result.TextID != "Bot result" { | ||
t.Error("Expected Bot result, got nil") | ||
} | ||
if result.Locale != "en" { | ||
t.Error("Expected en, got nil") | ||
} | ||
if len(result.Buttons) != 0 { | ||
t.Error("Expected no buttons, got some") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package scheduler | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/url" | ||
"time" | ||
|
||
"github.com/capymind/internal/taskservice" | ||
) | ||
|
||
// Returns the type and offset parameters from the URL | ||
func parse(url *url.URL) (*string, int) { | ||
typeStr := url.Query().Get("type") | ||
offsetStr := url.Query().Get("offset") // hours (from UTC 0) | ||
var offset int = 0 | ||
if offsetStr != "" { | ||
_, err := fmt.Sscanf(offsetStr, "%d", &offset) | ||
if err != nil { | ||
log.Printf("[Scheduler] Error getting offset parameter, %s", err.Error()) | ||
} | ||
} | ||
return &typeStr, offset | ||
} | ||
|
||
func getTextMessage(messageType taskservice.MessageType) *string { | ||
var message string | ||
switch messageType { | ||
case taskservice.Morning, taskservice.Evening: | ||
message = taskservice.GetMessage(messageType, time.Now().Weekday()) | ||
case taskservice.Feedback: | ||
message = "ask_write_review_about_bot" | ||
case taskservice.WeeklyAnalysis, taskservice.UserStats, taskservice.AdminStats: | ||
// Personalized for each user | ||
message = "" | ||
default: | ||
log.Println("Missing message type parameter") | ||
return nil | ||
} | ||
return &message | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package scheduler | ||
|
||
import ( | ||
"net/url" | ||
"testing" | ||
|
||
"github.com/capymind/internal/taskservice" | ||
) | ||
|
||
func TestParse(t *testing.T) { | ||
url1 := url.URL{ | ||
RawQuery: "type=morning&offset=2", | ||
} | ||
|
||
typeStr, offset := parse(&url1) | ||
if *typeStr != "morning" { | ||
t.Errorf("Expected type=morning, got %s", *typeStr) | ||
} | ||
if offset != 2 { | ||
t.Errorf("Expected offset=2, got %d", offset) | ||
} | ||
|
||
url2 := url.URL{ | ||
RawQuery: "type=evening&offset=0", | ||
} | ||
|
||
typeStr, offset = parse(&url2) | ||
if *typeStr != "evening" { | ||
t.Errorf("Expected type=evening, got %s", *typeStr) | ||
} | ||
if offset != 0 { | ||
t.Errorf("Expected offset=0, got %d", offset) | ||
} | ||
|
||
url3 := url.URL{ | ||
RawQuery: "type=weekly_analysis&offset=-1", | ||
} | ||
|
||
typeStr, offset = parse(&url3) | ||
if *typeStr != "weekly_analysis" { | ||
t.Errorf("Expected type=weekly_analysis, got %s", *typeStr) | ||
} | ||
if offset != -1 { | ||
t.Errorf("Expected offset=-1, got %d", offset) | ||
} | ||
|
||
url4 := url.URL{ | ||
RawQuery: "type=aaa&", | ||
} | ||
|
||
typeStr, offset = parse(&url4) | ||
if *typeStr != "aaa" { | ||
t.Errorf("Expected nil, got %s", *typeStr) | ||
} | ||
if offset != 0 { | ||
t.Errorf("Expected offset=0, got %d", offset) | ||
} | ||
|
||
url5 := url.URL{ | ||
RawQuery: "offset=2", | ||
} | ||
|
||
typeStr, offset = parse(&url5) | ||
if *typeStr != "" { | ||
t.Errorf("Expected nil, got %s", *typeStr) | ||
} | ||
if offset != 2 { | ||
t.Errorf("Expected offset=2, got %d", offset) | ||
} | ||
} | ||
|
||
func TestGetTextMessage(t *testing.T) { | ||
message := getTextMessage(taskservice.Morning) | ||
if *message != "how_are_you_morning_monday" { | ||
t.Errorf("Expected how_are_you_morning_monday, got %s", *message) | ||
} | ||
|
||
message = getTextMessage(taskservice.Evening) | ||
if *message != "how_are_you_evening_monday" { | ||
t.Errorf("Expected how_are_you_evening_monday, got %s", *message) | ||
} | ||
|
||
message = getTextMessage(taskservice.Feedback) | ||
if *message != "ask_write_review_about_bot" { | ||
t.Errorf("Expected ask_write_review_about_bot, got %s", *message) | ||
} | ||
|
||
message = getTextMessage(taskservice.WeeklyAnalysis) | ||
if *message != "" { | ||
t.Errorf("Expected empty string, got %s", *message) | ||
} | ||
|
||
message = getTextMessage(taskservice.UserStats) | ||
if *message != "" { | ||
t.Errorf("Expected empty string, got %s", *message) | ||
} | ||
|
||
message = getTextMessage(taskservice.AdminStats) | ||
if *message != "" { | ||
t.Errorf("Expected empty string, got %s", *message) | ||
} | ||
|
||
message = getTextMessage("") | ||
if message != nil { | ||
t.Errorf("Expected nil, got %s", *message) | ||
} | ||
} |
Oops, something went wrong.