2019-05-16 10:39:25 -04:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
|
2019-07-13 12:16:28 -08:00
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/mid"
|
|
|
|
saasSwagger "geeks-accelerator/oss/saas-starter-kit/internal/mid/saas-swagger"
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
|
2019-08-04 14:48:43 -08:00
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
|
2019-08-05 19:49:30 -08:00
|
|
|
_ "geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
|
2019-07-13 12:16:28 -08:00
|
|
|
_ "geeks-accelerator/oss/saas-starter-kit/internal/signup"
|
2019-08-17 11:03:48 +07:00
|
|
|
|
2019-05-23 14:32:24 -05:00
|
|
|
"github.com/jmoiron/sqlx"
|
2019-06-24 17:36:42 -08:00
|
|
|
"gopkg.in/DataDog/dd-trace-go.v1/contrib/go-redis/redis"
|
2019-05-16 10:39:25 -04:00
|
|
|
)
|
|
|
|
|
2019-08-13 23:41:06 -08:00
|
|
|
type AppContext struct {
|
2019-08-14 12:53:40 -08:00
|
|
|
Log *log.Logger
|
|
|
|
Env webcontext.Env
|
|
|
|
MasterDB *sqlx.DB
|
|
|
|
Redis *redis.Client
|
2019-08-17 11:03:48 +07:00
|
|
|
UserRepo UserRepository
|
|
|
|
UserAccountRepo UserAccountRepository
|
|
|
|
AccountRepo AccountRepository
|
|
|
|
AccountPrefRepo AccountPrefRepository
|
|
|
|
AuthRepo UserAuthRepository
|
|
|
|
SignupRepo SignupRepository
|
|
|
|
InviteRepo UserInviteRepository
|
|
|
|
ProjectRepo ProjectRepository
|
2019-08-14 12:53:40 -08:00
|
|
|
Authenticator *auth.Authenticator
|
|
|
|
PreAppMiddleware []web.Middleware
|
2019-08-13 23:41:06 -08:00
|
|
|
PostAppMiddleware []web.Middleware
|
|
|
|
}
|
|
|
|
|
2019-05-16 10:39:25 -04:00
|
|
|
// API returns a handler for a set of routes.
|
2019-08-14 12:53:40 -08:00
|
|
|
func API(shutdown chan os.Signal, appCtx *AppContext) http.Handler {
|
2019-07-12 11:41:41 -08:00
|
|
|
|
2019-08-13 23:41:06 -08:00
|
|
|
// Include the pre middlewares first.
|
2019-08-14 12:53:40 -08:00
|
|
|
middlewares := appCtx.PreAppMiddleware
|
2019-08-13 23:41:06 -08:00
|
|
|
|
|
|
|
// Define app middlewares applied to all requests.
|
|
|
|
middlewares = append(middlewares,
|
|
|
|
mid.Trace(),
|
2019-08-14 12:53:40 -08:00
|
|
|
mid.Logger(appCtx.Log),
|
|
|
|
mid.Errors(appCtx.Log, nil),
|
2019-08-13 23:41:06 -08:00
|
|
|
mid.Metrics(),
|
|
|
|
mid.Panics())
|
2019-07-12 11:41:41 -08:00
|
|
|
|
2019-08-13 23:41:06 -08:00
|
|
|
// Append any global middlewares that should be included after the app middlewares.
|
2019-08-14 12:53:40 -08:00
|
|
|
if len(appCtx.PostAppMiddleware) > 0 {
|
|
|
|
middlewares = append(middlewares, appCtx.PostAppMiddleware...)
|
2019-07-12 11:41:41 -08:00
|
|
|
}
|
2019-05-16 10:39:25 -04:00
|
|
|
|
|
|
|
// Construct the web.App which holds all routes as well as common Middleware.
|
2019-08-14 12:53:40 -08:00
|
|
|
app := web.NewApp(shutdown, appCtx.Log, appCtx.Env, middlewares...)
|
2019-05-16 10:39:25 -04:00
|
|
|
|
|
|
|
// Register health check endpoint. This route is not authenticated.
|
|
|
|
check := Check{
|
2019-08-14 12:53:40 -08:00
|
|
|
MasterDB: appCtx.MasterDB,
|
|
|
|
Redis: appCtx.Redis,
|
2019-05-16 10:39:25 -04:00
|
|
|
}
|
|
|
|
app.Handle("GET", "/v1/health", check.Health)
|
2019-07-10 16:24:10 -08:00
|
|
|
app.Handle("GET", "/ping", check.Ping)
|
2019-05-16 10:39:25 -04:00
|
|
|
|
2019-08-14 12:53:40 -08:00
|
|
|
// Register example endpoints.
|
|
|
|
ex := Example{
|
|
|
|
Project: appCtx.ProjectRepo,
|
|
|
|
}
|
|
|
|
app.Handle("GET", "/v1/examples/error-response", ex.ErrorResponse)
|
|
|
|
|
2019-05-16 10:39:25 -04:00
|
|
|
// Register user management and authentication endpoints.
|
2019-08-17 11:03:48 +07:00
|
|
|
u := Users{
|
|
|
|
UserRepo: appCtx.UserRepo,
|
|
|
|
AuthRepo: appCtx.AuthRepo,
|
2019-05-16 10:39:25 -04:00
|
|
|
}
|
2019-08-14 12:53:40 -08:00
|
|
|
app.Handle("GET", "/v1/users", u.Find, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("POST", "/v1/users", u.Create, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("GET", "/v1/users/:id", u.Read, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/users", u.Update, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/users/password", u.UpdatePassword, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/users/archive", u.Archive, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("DELETE", "/v1/users/:id", u.Delete, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("PATCH", "/v1/users/switch-account/:account_id", u.SwitchAccount, mid.AuthenticateHeader(appCtx.Authenticator))
|
2019-05-16 10:39:25 -04:00
|
|
|
|
|
|
|
// This route is not authenticated
|
2019-06-24 22:41:21 -08:00
|
|
|
app.Handle("POST", "/v1/oauth/token", u.Token)
|
2019-05-16 10:39:25 -04:00
|
|
|
|
2019-06-26 20:21:00 -08:00
|
|
|
// Register user account management endpoints.
|
|
|
|
ua := UserAccount{
|
2019-08-14 12:53:40 -08:00
|
|
|
Repository: appCtx.UserAccountRepo,
|
2019-06-26 20:21:00 -08:00
|
|
|
}
|
2019-08-14 12:53:40 -08:00
|
|
|
app.Handle("GET", "/v1/user_accounts", ua.Find, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("POST", "/v1/user_accounts", ua.Create, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("GET", "/v1/user_accounts/:user_id/:account_id", ua.Read, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/user_accounts", ua.Update, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/user_accounts/archive", ua.Archive, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("DELETE", "/v1/user_accounts", ua.Delete, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-24 17:36:42 -08:00
|
|
|
// Register account endpoints.
|
2019-08-17 11:03:48 +07:00
|
|
|
a := Accounts{
|
2019-08-14 12:53:40 -08:00
|
|
|
Repository: appCtx.AccountRepo,
|
2019-06-24 17:36:42 -08:00
|
|
|
}
|
2019-08-14 12:53:40 -08:00
|
|
|
app.Handle("GET", "/v1/accounts/:id", a.Read, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/accounts", a.Update, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
2019-06-24 17:36:42 -08:00
|
|
|
|
2019-06-25 02:40:29 -08:00
|
|
|
// Register signup endpoints.
|
|
|
|
s := Signup{
|
2019-08-14 12:53:40 -08:00
|
|
|
Repository: appCtx.SignupRepo,
|
2019-06-25 02:40:29 -08:00
|
|
|
}
|
|
|
|
app.Handle("POST", "/v1/signup", s.Signup)
|
|
|
|
|
2019-06-24 17:36:42 -08:00
|
|
|
// Register project.
|
2019-08-17 11:03:48 +07:00
|
|
|
p := Projects{
|
2019-08-14 12:53:40 -08:00
|
|
|
Repository: appCtx.ProjectRepo,
|
2019-05-16 10:39:25 -04:00
|
|
|
}
|
2019-08-14 12:53:40 -08:00
|
|
|
app.Handle("GET", "/v1/projects", p.Find, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("POST", "/v1/projects", p.Create, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("GET", "/v1/projects/:id", p.Read, mid.AuthenticateHeader(appCtx.Authenticator))
|
|
|
|
app.Handle("PATCH", "/v1/projects", p.Update, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("PATCH", "/v1/projects/archive", p.Archive, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
|
|
|
app.Handle("DELETE", "/v1/projects/:id", p.Delete, mid.AuthenticateHeader(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
2019-08-07 16:17:17 -08:00
|
|
|
|
2019-06-24 17:36:42 -08:00
|
|
|
// Register swagger documentation.
|
2019-06-24 22:41:21 -08:00
|
|
|
// TODO: Add authentication. Current authenticator requires an Authorization header
|
|
|
|
// which breaks the browser experience.
|
2019-07-14 17:59:06 -08:00
|
|
|
app.Handle("GET", "/docs/", saasSwagger.WrapHandler)
|
|
|
|
app.Handle("GET", "/docs/*", saasSwagger.WrapHandler)
|
2019-05-16 10:39:25 -04:00
|
|
|
|
|
|
|
return app
|
|
|
|
}
|
2019-06-25 22:31:54 -08:00
|
|
|
|
|
|
|
// Types godoc
|
|
|
|
// @Summary List of types.
|
2019-08-05 19:49:30 -08:00
|
|
|
// @Param data body weberror.FieldError false "Field Error"
|
2019-06-25 22:31:54 -08:00
|
|
|
// @Param data body web.TimeResponse false "Time Response"
|
|
|
|
// @Param data body web.EnumResponse false "Enum Response"
|
2019-08-05 19:49:30 -08:00
|
|
|
// @Param data body web.EnumMultiResponse false "Enum Multi Response"
|
2019-06-25 22:31:54 -08:00
|
|
|
// @Param data body web.EnumOption false "Enum Option"
|
2019-06-26 01:16:57 -08:00
|
|
|
// @Param data body signup.SignupAccount false "SignupAccount"
|
|
|
|
// @Param data body signup.SignupUser false "SignupUser"
|
2019-06-25 22:31:54 -08:00
|
|
|
// To support nested types not parsed by swag.
|
|
|
|
func Types() {}
|