Skip to content

Commit

Permalink
feat: feature flag system
Browse files Browse the repository at this point in the history
  • Loading branch information
aldy505 committed Dec 25, 2023
1 parent 3ec09f8 commit 567d147
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 163 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ jobs:
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --debug --only-verified

ci:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ jobs:
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --debug --only-verified

ci:
Expand Down
2 changes: 0 additions & 2 deletions analytics/analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package analytics

import (
"github.com/allegro/bigcache/v3"
"github.com/getsentry/sentry-go"
"github.com/jmoiron/sqlx"
tb "gopkg.in/telebot.v3"
)
Expand All @@ -12,7 +11,6 @@ import (
type Dependency struct {
Memory *bigcache.BigCache
Bot *tb.Bot
Logger *sentry.Client
DB *sqlx.DB
TeknumID string
}
Expand Down
44 changes: 29 additions & 15 deletions analytics/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package server

import (
"errors"
"net"
"net/http"
"os"
"time"

"github.com/teknologi-umum/captcha/analytics"
Expand Down Expand Up @@ -58,12 +56,12 @@ var ErrInvalidValue = errors.New("invalid value")
// Config is the configuration struct for the server package.
// Only the Port field is optional. It will be set to 8080 if not set.
type Config struct {
DB *sqlx.DB
Mongo *mongo.Client
MongoDBName string
Memory *bigcache.BigCache
Logger *sentry.Client
Port string
DB *sqlx.DB
Mongo *mongo.Client
MongoDBName string
Memory *bigcache.BigCache
Environment string
ListeningAddress string
}

// New creates and runs an HTTP server instance for fetching analytics data
Expand All @@ -72,26 +70,25 @@ type Config struct {
// Requires 3 parameter that should be sent from the main goroutine.
func New(config Config) *http.Server {
// Give default port
if config.Port == "" {
config.Port = "8080"
if config.ListeningAddress == "" {
config.ListeningAddress = ":8080"
}

deps := &Dependency{
DB: config.DB,
Memory: config.Memory,
Logger: config.Logger,
Mongo: config.Mongo,
MongoDBName: config.MongoDBName,
}

secureMiddleware := secure.New(secure.Options{
BrowserXssFilter: true,
ContentTypeNosniff: true,
SSLRedirect: os.Getenv("ENV") == "production",
IsDevelopment: os.Getenv("ENV") == "development",
SSLRedirect: config.Environment == "production",
IsDevelopment: config.Environment == "development",
})
corsMiddleware := cors.New(cors.Options{
Debug: os.Getenv("ENV") == "development",
Debug: config.Environment == "development",
AllowedOrigins: []string{},
AllowedMethods: []string{"GET", "OPTIONS"},
})
Expand All @@ -114,6 +111,11 @@ func New(config Config) *http.Server {
})

r.Get("/users", func(w http.ResponseWriter, r *http.Request) {
if deps.DB == nil {
w.WriteHeader(http.StatusNotFound)
return
}

data, err := deps.GetAll(r.Context())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand All @@ -140,6 +142,10 @@ func New(config Config) *http.Server {
})

r.Get("/hourly", func(w http.ResponseWriter, r *http.Request) {
if deps.DB == nil {
w.WriteHeader(http.StatusNotFound)
return
}
data, err := deps.GetHourly(r.Context())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand All @@ -166,6 +172,10 @@ func New(config Config) *http.Server {
})

r.Get("/total", func(w http.ResponseWriter, r *http.Request) {
if deps.DB == nil {
w.WriteHeader(http.StatusNotFound)
return
}
data, err := deps.GetTotal(r.Context())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand All @@ -192,6 +202,10 @@ func New(config Config) *http.Server {
})

r.Get("/dukun", func(w http.ResponseWriter, r *http.Request) {
if deps.Mongo == nil {
w.WriteHeader(http.StatusNotFound)
return
}
data, err := deps.GetDukunPoints(r.Context())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand Down Expand Up @@ -219,7 +233,7 @@ func New(config Config) *http.Server {

return &http.Server{
Handler: r,
Addr: net.JoinHostPort("", config.Port),
Addr: config.ListeningAddress,
ReadTimeout: time.Minute,
WriteTimeout: time.Minute,
ReadHeaderTimeout: time.Minute,
Expand Down
4 changes: 1 addition & 3 deletions ascii/ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ import (
"github.com/teknologi-umum/captcha/shared"
"github.com/teknologi-umum/captcha/utils"

"github.com/getsentry/sentry-go"
tb "gopkg.in/telebot.v3"
)

// Dependencies contains dependency injection struct
// to be used for the Ascii package.
type Dependencies struct {
Bot *tb.Bot
Logger *sentry.Client
Bot *tb.Bot
}

// Ascii simply sends ASCII art message for fun.
Expand Down
5 changes: 2 additions & 3 deletions badwords/badwords.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package badwords

import (
"context"
"os"
"strings"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
Expand All @@ -14,6 +12,7 @@ import (
type Dependency struct {
Mongo *mongo.Client
MongoDBName string
AdminIDs []string
}

// AddBadWords will add a new word into the MongoDB database.
Expand All @@ -29,7 +28,7 @@ func (d *Dependency) AddBadWord(ctx context.Context, word string) error {
// Authenticate will check if the user is allowed to add a new
// badword into the database.
func (d *Dependency) Authenticate(id string) bool {
admins := strings.Split(os.Getenv("ADMIN_ID"), ",")
admins := d.AdminIDs

for _, admin := range admins {
if admin == id {
Expand Down
2 changes: 0 additions & 2 deletions captcha/captcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"github.com/teknologi-umum/captcha/analytics"

"github.com/allegro/bigcache/v3"
"github.com/getsentry/sentry-go"
tb "gopkg.in/telebot.v3"
)

Expand All @@ -13,7 +12,6 @@ import (
type Dependencies struct {
Memory *bigcache.BigCache
Bot *tb.Bot
Logger *sentry.Client
Analytics *analytics.Dependency
TeknumID string
}
84 changes: 42 additions & 42 deletions cmd/captcha/captcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"context"
"fmt"
"os"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -35,6 +34,8 @@ type Dependency struct {
Mongo *mongo.Client
MongoDBName string
TeknumID string
AdminIDs []string
FeatureFlag FeatureFlag
captcha *captcha.Dependencies
ascii *ascii.Dependencies
analytics *analytics.Dependency
Expand All @@ -53,12 +54,14 @@ func New(deps Dependency) *Dependency {
TeknumID: deps.TeknumID,
}
return &Dependency{
Bot: deps.Bot,
Memory: deps.Memory,
Bot: deps.Bot,
DB: deps.DB,
Mongo: deps.Mongo,
MongoDBName: deps.MongoDBName,
TeknumID: deps.TeknumID,
AdminIDs: deps.AdminIDs,
FeatureFlag: deps.FeatureFlag,
captcha: &captcha.Dependencies{
Memory: deps.Memory,
Bot: deps.Bot,
Expand All @@ -72,6 +75,7 @@ func New(deps Dependency) *Dependency {
badwords: &badwords.Dependency{
Mongo: deps.Mongo,
MongoDBName: deps.MongoDBName,
AdminIDs: deps.AdminIDs,
},
underAttack: &underattack.Dependency{
Memory: deps.Memory,
Expand All @@ -87,9 +91,11 @@ func (d *Dependency) OnTextHandler(c tb.Context) error {

d.captcha.WaitForAnswer(ctx, c.Message())

err := d.analytics.NewMessage(c.Message())
if err != nil {
shared.HandleError(ctx, err)
if d.FeatureFlag.Analytics {
err := d.analytics.NewMessage(c.Message())
if err != nil {
shared.HandleError(ctx, err)
}
}

return nil
Expand All @@ -110,17 +116,19 @@ func (d *Dependency) OnUserJoinHandler(c tb.Context) error {
defer span.Finish()
ctx = span.Context()

underAttack, err := d.underAttack.AreWe(ctx, c.Chat().ID)
if err != nil {
shared.HandleError(ctx, err)
}

if underAttack {
err := d.underAttack.Kicker(ctx, c)
if d.FeatureFlag.UnderAttack {
underAttack, err := d.underAttack.AreWe(ctx, c.Chat().ID)
if err != nil {
shared.HandleBotError(ctx, err, d.Bot, c.Message())
shared.HandleError(ctx, err)
}

if underAttack {
err := d.underAttack.Kicker(ctx, c)
if err != nil {
shared.HandleBotError(ctx, err, d.Bot, c.Message())
}
return nil
}
return nil
}

var tempSender *tb.User
Expand All @@ -130,7 +138,9 @@ func (d *Dependency) OnUserJoinHandler(c tb.Context) error {
tempSender = c.Message().Sender
}

go d.analytics.NewUser(ctx, c.Message(), tempSender)
if d.FeatureFlag.Analytics {
go d.analytics.NewUser(ctx, c.Message(), tempSender)
}

d.captcha.CaptchaUserJoin(ctx, c.Message())

Expand All @@ -144,9 +154,11 @@ func (d *Dependency) OnNonTextHandler(c tb.Context) error {

d.captcha.NonTextListener(ctx, c.Message())

err := d.analytics.NewMessage(c.Message())
if err != nil {
shared.HandleError(ctx, err)
if d.FeatureFlag.Analytics {
err := d.analytics.NewMessage(c.Message())
if err != nil {
shared.HandleError(ctx, err)
}
}

return nil
Expand All @@ -161,18 +173,14 @@ func (d *Dependency) OnUserLeftHandler(c tb.Context) error {
return nil
}

// AsciiCmdHandler handle the /ascii command.
func (d *Dependency) AsciiCmdHandler(c tb.Context) error {
ctx := sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone())

d.ascii.Ascii(ctx, c.Message())
return nil
}

// BadWordHandler handle the /badwords command.
// This can only be accessed by some users on Telegram
// and only valid for private chats.
func (d *Dependency) BadWordHandler(c tb.Context) error {
if d.FeatureFlag.BadwordsInsertion {
return nil
}

if !c.Message().Private() {
return nil
}
Expand Down Expand Up @@ -200,38 +208,30 @@ func (d *Dependency) BadWordHandler(c tb.Context) error {
return nil
}

// CukupHandler was created just to mock laode.
func (d *Dependency) CukupHandler(c tb.Context) error {
if c.Message().Private() {
// EnableUnderAttackModeHandler provides a handler for /underattack command.
func (d *Dependency) EnableUnderAttackModeHandler(c tb.Context) error {
if !d.FeatureFlag.UnderAttack {
return nil
}

ctx := sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone())

_, err := c.Bot().Send(c.Chat(), &tb.Photo{File: tb.FromURL("https://i.ibb.co/WvynnPb/ezgif-4-13e23b17f1.jpg")})
if err != nil {
shared.HandleBotError(ctx, err, c.Bot(), c.Message())
}

return nil
}

// EnableUnderAttackModeHandler provides a handler for /underattack command.
func (d *Dependency) EnableUnderAttackModeHandler(c tb.Context) error {
ctx := sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone())

return d.underAttack.EnableUnderAttackModeHandler(ctx, c)
}

// DisableUnderAttackModeHandler provides a handler for /disableunderattack command.
func (d *Dependency) DisableUnderAttackModeHandler(c tb.Context) error {
if !d.FeatureFlag.UnderAttack {
return nil
}

ctx := sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone())

return d.underAttack.DisableUnderAttackModeHandler(ctx, c)
}

func (d *Dependency) SetirHandler(c tb.Context) error {
admin := strings.Split(os.Getenv("ADMIN_ID"), ",")
admin := d.AdminIDs
if !utils.IsIn(admin, strconv.FormatInt(c.Sender().ID, 10)) || c.Chat().Type != tb.ChatPrivate {
return nil
}
Expand Down
Loading

0 comments on commit 567d147

Please sign in to comment.