Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ REDIS_PORT=6379
REDIS_PASSWORD=zenreply
REDIS_DB=0

# --- Slack ---
SLACK_CLIENT_ID=<SLACK_CLIENT_ID>
SLACK_CLIENT_SECRET=<SLACK_CLIENT_SECRET>
SLACK_SIGNING_SECRET=<SLACK_SIGNING_SECRET>

# --- JWT ---
JWT_SECRET=6ef0c2d5179f616e653915dc66844a763b80ef4ddac87953d4631290fe30de8a
JWT_EXPIRATION=24h
20 changes: 8 additions & 12 deletions backend/cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,8 @@
//
// @tag.name system
// @tag.description System health and diagnostics
// @tag.name auth
// @tag.description Slack OAuth 2.0 authentication flow
// @tag.name users
// @tag.description User profile management
// @tag.name deep-work
// @tag.description Deep work session management
// @tag.name settings
// @tag.description User auto-reply configuration
// @tag.name logs
// @tag.description Auto-reply message history
// @tag.name slack
// @tag.description Slack Events API webhook
// @tag.description Slack authentication flow

package main

Expand All @@ -49,7 +39,9 @@ import (
"github.com/kietle/zenreply/handler"
"github.com/kietle/zenreply/pkg/database"
"github.com/kietle/zenreply/pkg/logger"
"github.com/kietle/zenreply/pkg/slack"
"github.com/kietle/zenreply/route"
"github.com/kietle/zenreply/service"
)

func main() {
Expand Down Expand Up @@ -87,8 +79,12 @@ func main() {
}
log.Info("migrations applied successfully")

// --- Service ---
slackOAuth := slack.NewSlackOAuth(cfg)
authSvc := service.NewOAuthService(cfg, rdb, slackOAuth)

// --- Handler ---
h := handler.New(cfg, db, rdb)
h := handler.New(cfg, db, rdb, authSvc)

// --- HTTP Server ---
router := route.Setup(cfg, h, log)
Expand Down
27 changes: 16 additions & 11 deletions backend/config/config.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package config

import (
"log"
"fmt"
"os"
"strconv"
"time"

"github.com/joho/godotenv"
)

type AppConfig struct {
Expand Down Expand Up @@ -44,21 +42,22 @@ type RedisConfig struct {
URL string
}

type SlackConfig struct {
ClientID string
ClientSecret string
SigningSecret string
RedirectURL string
}

type Config struct {
App AppConfig
Postgres PostgresConfig
Redis RedisConfig
JWT JWTConfig
Slack SlackConfig
}

func Load() *Config {
if os.Getenv("ENV") == "development" {
err := godotenv.Load()
if err != nil {
log.Println(".env not found")
}
}

return &Config{
App: AppConfig{
Port: getEnv("APP_PORT", "8080"),
Expand All @@ -72,7 +71,7 @@ func Load() *Config {
Port: getEnv("POSTGRES_PORT", "5432"),
User: getEnv("POSTGRES_USER", "postgres"),
Password: getEnv("POSTGRES_PASSWORD", "password"),
DB: getEnv("POSTGRES_DB", "attendance_db"),
DB: getEnv("POSTGRES_DB", "zenreply"),
},
Redis: RedisConfig{
Host: getEnv("REDIS_HOST", "localhost"),
Expand All @@ -84,6 +83,12 @@ func Load() *Config {
Secret: getEnv("JWT_SECRET", "secret"),
Expiry: getEnvAsDuration("JWT_EXPIRY", 3600*time.Second),
},
Slack: SlackConfig{
ClientID: getEnv("SLACK_CLIENT_ID", ""),
ClientSecret: getEnv("SLACK_CLIENT_SECRET", ""),
SigningSecret: getEnv("SLACK_SIGNING_SECRET", ""),
RedirectURL: fmt.Sprintf("%s/api/v1/slack/callback", getEnv("APP_BASE_URL", "https://localhost:8080")),
},
}
}

Expand Down
54 changes: 54 additions & 0 deletions backend/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,47 @@ const docTemplate = `{
}
}
}
},
"/slack/auth": {
"get": {
"description": "Generate a Slack OAuth URL for the user login",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"slack"
],
"summary": "Generate Slack OAuth URL",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/github_com_kietle_zenreply_pkg_response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handler.SlackAuthURLResponse"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/github_com_kietle_zenreply_pkg_response.Response"
}
}
}
}
}
},
"definitions": {
Expand Down Expand Up @@ -144,6 +185,19 @@ const docTemplate = `{
"example": "1.0.0"
}
}
},
"handler.SlackAuthURLResponse": {
"type": "object",
"properties": {
"state": {
"type": "string",
"example": "123456"
},
"url": {
"type": "string",
"example": "https://slack.com/oauth/v2/authorize?client_id=1234567890\u0026scope=chat:write,im:write,channels:read,groups:read,users:read,reactions:read\u0026redirect_uri=https://localhost:8080/api/v1/slack/auth/callback"
}
}
}
},
"securityDefinitions": {
Expand Down
54 changes: 54 additions & 0 deletions backend/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,47 @@
}
}
}
},
"/slack/auth": {
"get": {
"description": "Generate a Slack OAuth URL for the user login",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"slack"
],
"summary": "Generate Slack OAuth URL",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/github_com_kietle_zenreply_pkg_response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handler.SlackAuthURLResponse"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/github_com_kietle_zenreply_pkg_response.Response"
}
}
}
}
}
},
"definitions": {
Expand Down Expand Up @@ -142,6 +183,19 @@
"example": "1.0.0"
}
}
},
"handler.SlackAuthURLResponse": {
"type": "object",
"properties": {
"state": {
"type": "string",
"example": "123456"
},
"url": {
"type": "string",
"example": "https://slack.com/oauth/v2/authorize?client_id=1234567890\u0026scope=chat:write,im:write,channels:read,groups:read,users:read,reactions:read\u0026redirect_uri=https://localhost:8080/api/v1/slack/auth/callback"
}
}
}
},
"securityDefinitions": {
Expand Down
33 changes: 33 additions & 0 deletions backend/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ definitions:
example: 1.0.0
type: string
type: object
handler.SlackAuthURLResponse:
properties:
state:
example: "123456"
type: string
url:
example: https://slack.com/oauth/v2/authorize?client_id=1234567890&scope=chat:write,im:write,channels:read,groups:read,users:read,reactions:read&redirect_uri=https://localhost:8080/api/v1/slack/auth/callback
type: string
type: object
host: localhost:8080
info:
contact:
Expand Down Expand Up @@ -91,6 +100,30 @@ paths:
summary: Health check
tags:
- system
/slack/auth:
get:
consumes:
- application/json
description: Generate a Slack OAuth URL for the user login
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_kietle_zenreply_pkg_response.Response'
- properties:
data:
$ref: '#/definitions/handler.SlackAuthURLResponse'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/github_com_kietle_zenreply_pkg_response.Response'
summary: Generate Slack OAuth URL
tags:
- slack
schemes:
- http
- https
Expand Down
2 changes: 2 additions & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/go-playground/validator/v10 v10.30.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
Expand Down Expand Up @@ -58,6 +59,7 @@ require (
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/joho/godotenv v1.5.1
github.com/redis/go-redis/v9 v9.18.0
github.com/slack-go/slack v0.20.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.1
github.com/swaggo/swag v1.16.6
Expand Down
4 changes: 4 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
Expand Down Expand Up @@ -91,6 +93,8 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
github.com/slack-go/slack v0.20.0 h1:gbDdbee8+Z2o+DWx05Spq3GzbrLLleiRwHUKs+hZLSU=
github.com/slack-go/slack v0.20.0/go.mod h1:K81UmCivcYd/5Jmz8vLBfuyoZ3B4rQC2GHVXHteXiAE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down
17 changes: 10 additions & 7 deletions backend/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ package handler
import (
"github.com/jackc/pgx/v5/pgxpool"
"github.com/kietle/zenreply/config"
"github.com/kietle/zenreply/service"
"github.com/redis/go-redis/v9"
)

type Handler struct {
config *config.Config
db *pgxpool.Pool
rdb *redis.Client
config *config.Config
db *pgxpool.Pool
rdb *redis.Client
authSvc *service.AuthService
}

func New(cfg *config.Config, db *pgxpool.Pool, rdb *redis.Client) *Handler {
func New(cfg *config.Config, db *pgxpool.Pool, rdb *redis.Client, authSvc *service.AuthService) *Handler {
return &Handler{
config: cfg,
db: db,
rdb: rdb,
config: cfg,
db: db,
rdb: rdb,
authSvc: authSvc,
}
}
Loading
Loading