-
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.
- Loading branch information
Michael Freeman
committed
Oct 5, 2024
1 parent
60e62bf
commit e23073f
Showing
8 changed files
with
205 additions
and
0 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,35 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/carverauto/eventrunner/cmd/api/migrations" | ||
"github.com/carverauto/eventrunner/pkg/api/handlers" | ||
"github.com/carverauto/eventrunner/pkg/api/middleware" | ||
"gofr.dev/pkg/gofr" | ||
"gofr.dev/pkg/gofr/datasource/mongo" | ||
) | ||
|
||
func main() { | ||
app := gofr.New() | ||
|
||
// Set up MongoDB | ||
db := mongo.New(mongo.Config{URI: "mongodb://localhost:27017", Database: "eventrunner"}) | ||
app.AddMongo(db) | ||
|
||
// Run migrations | ||
app.Migrate(migrations.All()) | ||
|
||
// Set up routes | ||
tenantHandler := &handlers.TenantHandler{} | ||
userHandler := &handlers.UserHandler{} | ||
|
||
// Tenant routes (protected by API key) | ||
app.POST("/tenants", tenantHandler.Create, middleware.AuthenticateAPIKey) | ||
app.GET("/tenants", tenantHandler.GetAll, middleware.AuthenticateAPIKey) | ||
|
||
// User routes (protected by API key and role-based access) | ||
app.POST("/tenants/{tenant_id}/users", userHandler.Create, middleware.AuthenticateAPIKey, middleware.RequireRole("admin")) | ||
app.GET("/tenants/{tenant_id}/users", userHandler.GetAll, middleware.AuthenticateAPIKey, middleware.RequireRole("admin", "user")) | ||
|
||
// Run the application | ||
app.Run() | ||
} |
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,12 @@ | ||
package migrations | ||
|
||
import ( | ||
"gofr.dev/pkg/gofr/migration" | ||
) | ||
|
||
func All() map[int64]migration.Migrate { | ||
return map[int64]migration.Migrate{ | ||
20240226153000: createCollections(), | ||
Check failure on line 9 in cmd/api/migrations/all.go GitHub Actions / lint
|
||
20240226153100: createIndexes(), | ||
Check failure on line 10 in cmd/api/migrations/all.go GitHub Actions / lint
|
||
} | ||
} |
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
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
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,7 @@ | ||
package api | ||
|
||
import "errors" | ||
|
||
var ( | ||
ErrInsufficientPermissions = errors.New("insufficient permissions") | ||
) |
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,65 @@ | ||
package handlers | ||
|
||
import ( | ||
"github.com/carverauto/eventrunner/pkg/api/models" | ||
"go.mongodb.org/mongo-driver/bson" | ||
"go.mongodb.org/mongo-driver/bson/primitive" | ||
"gofr.dev/pkg/gofr" | ||
) | ||
|
||
type TenantHandler struct{} | ||
|
||
func (h *TenantHandler) Create(c *gofr.Context) (interface{}, error) { | ||
var tenant models.Tenant | ||
if err := c.Bind(&tenant); err != nil { | ||
return nil, err | ||
} | ||
|
||
result, err := c.Mongo.InsertOne(c, "tenants", tenant) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
tenant.ID = result.(primitive.ObjectID) | ||
|
||
return tenant, nil | ||
} | ||
|
||
func (h *TenantHandler) GetAll(c *gofr.Context) (interface{}, error) { | ||
var tenants []models.Tenant | ||
err := c.Mongo.Find(c, "tenants", bson.M{}, &tenants) | ||
|
||
return tenants, err | ||
} | ||
|
||
type UserHandler struct{} | ||
|
||
func (h *UserHandler) Create(c *gofr.Context) (interface{}, error) { | ||
var user models.User | ||
if err := c.Bind(&user); err != nil { | ||
return nil, err | ||
} | ||
|
||
// TODO: Hash password before storing | ||
|
||
result, err := c.Mongo.InsertOne(c, "users", user) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
user.ID = result.(primitive.ObjectID) | ||
|
||
return user, nil | ||
} | ||
|
||
func (h *UserHandler) GetAll(c *gofr.Context) (interface{}, error) { | ||
tenantID, err := primitive.ObjectIDFromHex(c.Param("tenant_id")) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var users []models.User | ||
err = c.Mongo.Find(c, "users", bson.M{"tenant_id": tenantID}, &users) | ||
|
||
return users, err | ||
} |
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,46 @@ | ||
package middleware | ||
|
||
import ( | ||
"github.com/carverauto/eventrunner/pkg/api" | ||
"github.com/carverauto/eventrunner/pkg/api/models" | ||
"go.mongodb.org/mongo-driver/bson" | ||
"gofr.dev/pkg/gofr" | ||
gofrHTTP "gofr.dev/pkg/gofr/http" | ||
) | ||
|
||
func AuthenticateAPIKey(next gofr.Handler) gofr.Handler { | ||
return func(c *gofr.Context) (interface{}, error) { | ||
apiKey := c.Request.Param("X-API-Key") | ||
if apiKey == "" { | ||
return nil, gofrHTTP.ErrorMissingParam{Params: []string{"X-API-Key"}} | ||
} | ||
|
||
var key models.APIKey | ||
if err := c.Mongo.FindOne(c, "api_keys", bson.M{"key": apiKey, "active": true}, &key); err != nil { | ||
return nil, gofrHTTP.ErrorInvalidParam{Params: []string{"X-API-Key"}} | ||
} | ||
|
||
// Store the API key in the context for later use if needed | ||
// Note: There doesn't seem to be a direct method to set parameters in the context | ||
// You might need to implement a custom method or use a different approach to store this | ||
|
||
return next(c) | ||
} | ||
} | ||
|
||
func RequireRole(roles ...string) gofr.Handler { | ||
return func(c *gofr.Context) (interface{}, error) { | ||
userRole := c.Request.Param("X-User-Role") | ||
if userRole == "" { | ||
return nil, gofrHTTP.ErrorMissingParam{Params: []string{"X-User-Role"}} | ||
} | ||
|
||
for _, role := range roles { | ||
if userRole == role { | ||
return nil, nil // Allow the request to proceed | ||
} | ||
} | ||
|
||
return nil, api.ErrInsufficientPermissions | ||
} | ||
} |
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,25 @@ | ||
package models | ||
|
||
import ( | ||
"go.mongodb.org/mongo-driver/bson/primitive" | ||
) | ||
|
||
type Tenant struct { | ||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` | ||
Name string `bson:"name" json:"name"` | ||
} | ||
|
||
type User struct { | ||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` | ||
TenantID primitive.ObjectID `bson:"tenant_id" json:"tenant_id"` | ||
Username string `bson:"username" json:"username"` | ||
Email string `bson:"email" json:"email"` | ||
Password string `bson:"password" json:"-"` // Don't expose password in JSON | ||
Role string `bson:"role" json:"role"` | ||
} | ||
|
||
type APIKey struct { | ||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` | ||
Key string `bson:"key" json:"key"` | ||
Active bool `bson:"active" json:"active"` | ||
} |