Wooo API!
This commit is contained in:
@@ -1,248 +1,124 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"strings"
|
||||
"context"
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/lestrrat-go/jwx/jwt"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/lestrrat-go/jwx/jwt"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
|
||||
func (api *API) loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
if r.Method != http.MethodPost {
|
||||
errorJSON(w, "Method is not supported.", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
func (api *API) refreshTokens(refreshToken jwt.Token) (string, string, error) {
|
||||
// Acquire User & Device
|
||||
did, ok := refreshToken.Get("did")
|
||||
if !ok {
|
||||
return "", "", errors.New("Missing DID")
|
||||
}
|
||||
uid, ok := refreshToken.Get(jwt.SubjectKey)
|
||||
if !ok {
|
||||
return "", "", errors.New("Missing UID")
|
||||
}
|
||||
deviceUUID, err := uuid.Parse(fmt.Sprintf("%v", did))
|
||||
if err != nil {
|
||||
return "", "", errors.New("Invalid DID")
|
||||
}
|
||||
userUUID, err := uuid.Parse(fmt.Sprintf("%v", uid))
|
||||
if err != nil {
|
||||
return "", "", errors.New("Invalid UID")
|
||||
}
|
||||
|
||||
// Decode into Struct
|
||||
var creds APICredentials
|
||||
err := json.NewDecoder(r.Body).Decode(&creds)
|
||||
if err != nil {
|
||||
errorJSON(w, "Invalid parameters.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Device & User Skeleton
|
||||
user := model.User{ID: userUUID.String()}
|
||||
device := model.Device{ID: deviceUUID.String()}
|
||||
|
||||
// Validate
|
||||
if creds.User == "" || creds.Password == "" {
|
||||
errorJSON(w, "Invalid parameters.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// Find User
|
||||
_, err = api.DB.User(&user)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Do login
|
||||
resp, user := api.Auth.AuthenticateUser(creds.User, creds.Password)
|
||||
if !resp {
|
||||
errorJSON(w, "Invalid credentials.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
// Update Access Token
|
||||
accessTokenCookie, err := api.Auth.CreateJWTAccessToken(user, device)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Upsert device
|
||||
device, err := api.upsertRequestedDevice(user, r)
|
||||
if err != nil {
|
||||
log.Error("[api] loginHandler - Failed to upsert device: ", err)
|
||||
errorJSON(w, "DB error. Unable to proceed.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Create Tokens
|
||||
accessToken, err := api.Auth.CreateJWTAccessToken(user, device)
|
||||
refreshToken, err := api.Auth.CreateJWTRefreshToken(user, device)
|
||||
|
||||
// Set appropriate cookies
|
||||
accessCookie := http.Cookie{Name: "AccessToken", Value: accessToken, Path: "/", HttpOnly: true}
|
||||
refreshCookie := http.Cookie{Name: "RefreshToken", Value: refreshToken, Path: "/", HttpOnly: true}
|
||||
http.SetCookie(w, &accessCookie)
|
||||
http.SetCookie(w, &refreshCookie)
|
||||
|
||||
// Response success
|
||||
successJSON(w, "Login success.", http.StatusOK)
|
||||
return accessTokenCookie, "", err
|
||||
}
|
||||
|
||||
func (api *API) logoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method is not supported.", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
func (api *API) validateTokens(w *http.ResponseWriter, r *http.Request) (jwt.Token, error) {
|
||||
// Validate Access Token
|
||||
accessCookie, _ := r.Cookie("AccessToken")
|
||||
if accessCookie != nil {
|
||||
accessToken, err := api.Auth.ValidateJWTAccessToken(accessCookie.Value)
|
||||
if err == nil {
|
||||
return accessToken, nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Reset Refresh Key
|
||||
// Validate Refresh Cookie Exists
|
||||
refreshCookie, _ := r.Cookie("RefreshToken")
|
||||
if refreshCookie == nil {
|
||||
return nil, errors.New("Tokens Invalid")
|
||||
}
|
||||
|
||||
// Clear Cookies
|
||||
http.SetCookie(w, &http.Cookie{Name: "AccessToken", Expires: time.Unix(0, 0)})
|
||||
http.SetCookie(w, &http.Cookie{Name: "RefreshToken", Expires: time.Unix(0, 0)})
|
||||
// Validate Refresh Token
|
||||
refreshToken, err := api.Auth.ValidateJWTRefreshToken(refreshCookie.Value)
|
||||
if err != nil {
|
||||
return nil, errors.New("Tokens Invalid")
|
||||
}
|
||||
|
||||
successJSON(w, "Logout success.", http.StatusOK)
|
||||
// Refresh Access Token & Generate New Refresh Token
|
||||
newAccessCookie, newRefreshCookie, err := api.refreshTokens(refreshToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Actually Refresh Refresh Token
|
||||
newRefreshCookie = refreshCookie.Value
|
||||
|
||||
// Update Access & Refresh Cookies
|
||||
http.SetCookie(*w, &http.Cookie{
|
||||
Name: "AccessToken",
|
||||
Value: newAccessCookie,
|
||||
})
|
||||
http.SetCookie(*w, &http.Cookie{
|
||||
Name: "RefreshToken",
|
||||
Value: newRefreshCookie,
|
||||
})
|
||||
|
||||
return jwt.ParseBytes([]byte(newAccessCookie))
|
||||
}
|
||||
|
||||
/**
|
||||
* This will find or create the requested device based on ID and User.
|
||||
**/
|
||||
func (api *API) upsertRequestedDevice(user model.User, r *http.Request) (model.Device, error) {
|
||||
requestedDevice := deriveRequestedDevice(r)
|
||||
requestedDevice.Type = deriveDeviceType(r)
|
||||
requestedDevice.User.ID = user.ID
|
||||
func (api *API) hasMinRoleDirective(ctx context.Context, obj interface{}, next graphql.Resolver, role model.Role) (res interface{}, err error) {
|
||||
authContext := ctx.Value("auth").(*model.AuthContext)
|
||||
accessToken, err := api.validateTokens(authContext.AuthResponse, authContext.AuthRequest)
|
||||
if err != nil {
|
||||
return nil, errors.New("Access Denied")
|
||||
}
|
||||
authContext.AccessToken = &accessToken
|
||||
|
||||
if *requestedDevice.ID == "" {
|
||||
err := api.DB.CreateDevice(&requestedDevice)
|
||||
createdDevice, err := api.DB.Device(&requestedDevice)
|
||||
return createdDevice, err
|
||||
}
|
||||
userRole, ok := accessToken.Get("role")
|
||||
if !ok {
|
||||
return nil, errors.New("Access Denied")
|
||||
}
|
||||
|
||||
foundDevice, err := api.DB.Device(&model.Device{
|
||||
ID: requestedDevice.ID,
|
||||
User: &user,
|
||||
})
|
||||
if userRole == model.RoleAdmin.String() {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
return foundDevice, err
|
||||
if userRole == role.String() {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
return nil, errors.New("Role Not Authenticated")
|
||||
}
|
||||
|
||||
func deriveDeviceType(r *http.Request) model.DeviceType {
|
||||
userAgent := strings.ToLower(r.Header.Get("User-Agent"))
|
||||
if strings.HasPrefix(userAgent, "ios-imagini"){
|
||||
return model.DeviceTypeIOs
|
||||
} else if strings.HasPrefix(userAgent, "android-imagini"){
|
||||
return model.DeviceTypeAndroid
|
||||
} else if strings.HasPrefix(userAgent, "chrome"){
|
||||
return model.DeviceTypeChrome
|
||||
} else if strings.HasPrefix(userAgent, "firefox"){
|
||||
return model.DeviceTypeFirefox
|
||||
} else if strings.HasPrefix(userAgent, "msie"){
|
||||
return model.DeviceTypeInternetExplorer
|
||||
} else if strings.HasPrefix(userAgent, "edge"){
|
||||
return model.DeviceTypeEdge
|
||||
} else if strings.HasPrefix(userAgent, "safari"){
|
||||
return model.DeviceTypeSafari
|
||||
}
|
||||
return model.DeviceTypeUnknown
|
||||
}
|
||||
|
||||
func deriveRequestedDevice(r *http.Request) model.Device {
|
||||
deviceSkeleton := model.Device{}
|
||||
authHeader := r.Header.Get("X-Imagini-Authorization")
|
||||
splitAuthInfo := strings.Split(authHeader, ",")
|
||||
|
||||
// For each Key - Value pair
|
||||
for i := range splitAuthInfo {
|
||||
|
||||
// Split Key - Value
|
||||
item := strings.TrimSpace(splitAuthInfo[i])
|
||||
splitItem := strings.SplitN(item, "=", 2)
|
||||
if len(splitItem) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Derive Key
|
||||
key := strings.ToLower(strings.TrimSpace(splitItem[0]))
|
||||
if key != "deviceid" && key != "devicename" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Derive Value
|
||||
val := trimQuotes(strings.TrimSpace(splitItem[1]))
|
||||
if key == "deviceid" {
|
||||
parsedDeviceUUID, err := uuid.Parse(val)
|
||||
if err != nil {
|
||||
log.Warn("[auth] deriveRequestedDevice - Unable to parse requested DeviceUUID: ", val)
|
||||
continue
|
||||
}
|
||||
stringDeviceUUID := parsedDeviceUUID.String()
|
||||
deviceSkeleton.ID = &stringDeviceUUID
|
||||
} else if key == "devicename" {
|
||||
deviceSkeleton.Name = val
|
||||
}
|
||||
}
|
||||
|
||||
// If name not set, set to type
|
||||
if deviceSkeleton.Name == "" {
|
||||
deviceSkeleton.Name = deviceSkeleton.Type.String()
|
||||
}
|
||||
|
||||
return deviceSkeleton
|
||||
}
|
||||
|
||||
func (api *API) refreshAccessToken(w http.ResponseWriter, r *http.Request) (jwt.Token, error) {
|
||||
refreshCookie, err := r.Cookie("RefreshToken")
|
||||
if err != nil {
|
||||
log.Warn("[middleware] RefreshToken not found")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Validate Refresh Token
|
||||
refreshToken, err := api.Auth.ValidateJWTRefreshToken(refreshCookie.Value)
|
||||
if err != nil {
|
||||
http.SetCookie(w, &http.Cookie{Name: "AccessToken", Expires: time.Unix(0, 0)})
|
||||
http.SetCookie(w, &http.Cookie{Name: "RefreshToken", Expires: time.Unix(0, 0)})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Acquire User & Device (Trusted)
|
||||
did, ok := refreshToken.Get("did")
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
uid, ok := refreshToken.Get(jwt.SubjectKey)
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
deviceUUID, err := uuid.Parse(fmt.Sprintf("%v", did))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userUUID, err := uuid.Parse(fmt.Sprintf("%v", uid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stringUserUUID := userUUID.String()
|
||||
stringDeviceUUID := deviceUUID.String()
|
||||
|
||||
// Device & User Skeleton
|
||||
user := model.User{ID: &stringUserUUID}
|
||||
device := model.Device{ID: &stringDeviceUUID}
|
||||
|
||||
// Update token
|
||||
accessTokenString, err := api.Auth.CreateJWTAccessToken(user, device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accessCookie := http.Cookie{Name: "AccessToken", Value: accessTokenString}
|
||||
http.SetCookie(w, &accessCookie)
|
||||
|
||||
// TODO: Update Refresh Key & Token
|
||||
|
||||
// Convert to jwt.Token
|
||||
accessTokenBytes := []byte(accessTokenString)
|
||||
accessToken, err := jwt.ParseBytes(accessTokenBytes)
|
||||
|
||||
return accessToken, err
|
||||
}
|
||||
|
||||
func trimQuotes(s string) string {
|
||||
if len(s) >= 2 {
|
||||
if s[0] == '"' && s[len(s)-1] == '"' {
|
||||
return s[1 : len(s)-1]
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func hasMinRoleDirective(ctx context.Context, obj interface{}, next graphql.Resolver, role model.Role) (res interface{}, err error) {
|
||||
// if !getCurrentUser(ctx).HasRole(role) {
|
||||
// // block calling the next resolver
|
||||
// return nil, fmt.Errorf("Access denied")
|
||||
// }
|
||||
|
||||
// or let it pass through
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
func metaDirective(ctx context.Context, obj interface{}, next graphql.Resolver, gorm *string) (res interface{}, err error){
|
||||
return next(ctx)
|
||||
func (api *API) metaDirective(ctx context.Context, obj interface{}, next graphql.Resolver, gorm *string) (res interface{}, err error) {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
@@ -1,50 +1,53 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
|
||||
// Responsible for serving up static images / videos
|
||||
func (api *API) mediaHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if path.Dir(r.URL.Path) != "/media" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if path.Dir(r.URL.Path) != "/media" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Acquire Width & Height Parameters
|
||||
query := r.URL.Query()
|
||||
width := query["width"]
|
||||
height := query["height"]
|
||||
_ = width
|
||||
_ = height
|
||||
// Acquire Width & Height Parameters
|
||||
query := r.URL.Query()
|
||||
width := query["width"]
|
||||
height := query["height"]
|
||||
_ = width
|
||||
_ = height
|
||||
|
||||
// TODO: Caching & Resizing
|
||||
// - If both, force resize with new scale
|
||||
// - If one, scale resize proportionally
|
||||
// TODO: Caching & Resizing
|
||||
// - If both, force resize with new scale
|
||||
// - If one, scale resize proportionally
|
||||
|
||||
// Pull out UUIDs
|
||||
reqInfo := r.Context().Value("uuids").(map[string]string)
|
||||
uid := reqInfo["uid"]
|
||||
// Pull out userID
|
||||
authContext := r.Context().Value("auth").(*model.AuthContext)
|
||||
rawUserID, _ := (*authContext.AccessToken).Get("sub")
|
||||
userID := rawUserID.(string)
|
||||
|
||||
// Derive Path
|
||||
fileName := path.Base(r.URL.Path)
|
||||
folderPath := path.Join("/" + api.Config.DataPath + "/media/" + uid)
|
||||
mediaPath := path.Join(folderPath + "/" + fileName)
|
||||
// Derive Path
|
||||
fileName := path.Base(r.URL.Path)
|
||||
folderPath := path.Join("/" + api.Config.DataPath + "/media/" + userID)
|
||||
mediaPath := path.Join(folderPath + "/" + fileName)
|
||||
|
||||
// Check if File Exists
|
||||
_, err := os.Stat(mediaPath)
|
||||
if os.IsNotExist(err) {
|
||||
// TODO: Different HTTP Response Code?
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
// Check if File Exists
|
||||
_, err := os.Stat(mediaPath)
|
||||
if os.IsNotExist(err) {
|
||||
// TODO: Different HTTP Response Code?
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeFile(w, r, mediaPath)
|
||||
http.ServeFile(w, r, mediaPath)
|
||||
}
|
||||
|
||||
@@ -1,104 +1,79 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
"context"
|
||||
"os"
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
|
||||
type Middleware func(http.Handler) http.HandlerFunc
|
||||
|
||||
func multipleMiddleware(h http.HandlerFunc, m ...Middleware) http.HandlerFunc {
|
||||
if len(m) < 1 {
|
||||
return h
|
||||
}
|
||||
wrapped := h
|
||||
for i := len(m) - 1; i >= 0; i-- {
|
||||
wrapped = m[i](wrapped)
|
||||
}
|
||||
return wrapped
|
||||
if len(m) < 1 {
|
||||
return h
|
||||
}
|
||||
wrapped := h
|
||||
for i := len(m) - 1; i >= 0; i-- {
|
||||
wrapped = m[i](wrapped)
|
||||
}
|
||||
return wrapped
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used for the graphQL endpoints that may require access to the
|
||||
* Request and ResponseWriter variables. These are used to get / set cookies.
|
||||
**/
|
||||
func (api *API) injectContextMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info("[middleware] Entering testMiddleware...")
|
||||
authContext := &model.AuthContext{
|
||||
AuthResponse: &w,
|
||||
AuthRequest: r,
|
||||
}
|
||||
accessCookie, err := r.Cookie("AccessToken")
|
||||
if err != nil {
|
||||
log.Warn("[middleware] AccessToken not found")
|
||||
} else {
|
||||
authContext.AccessToken = accessCookie.Value
|
||||
}
|
||||
refreshCookie, err := r.Cookie("RefreshToken")
|
||||
if err != nil {
|
||||
log.Warn("[middleware] RefreshToken not found")
|
||||
} else {
|
||||
authContext.RefreshToken = refreshCookie.Value
|
||||
}
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Add context
|
||||
ctx := context.WithValue(r.Context(), "auth", authContext)
|
||||
r = r.WithContext(ctx)
|
||||
authContext := &model.AuthContext{
|
||||
AuthResponse: &w,
|
||||
AuthRequest: r,
|
||||
}
|
||||
|
||||
log.Info("[middleware] Exiting testMiddleware...")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
// Add context
|
||||
ctx := context.WithValue(r.Context(), "auth", authContext)
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used for non graphQL endpoints that require authentication.
|
||||
**/
|
||||
func (api *API) authMiddleware(next http.Handler) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Acquire Token
|
||||
accessCookie, err := r.Cookie("AccessToken")
|
||||
if err != nil {
|
||||
log.Warn("[middleware] AccessToken not found")
|
||||
errorJSON(w, "Invalid token.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
accessToken, err := api.validateTokens(&w, r)
|
||||
if err != nil {
|
||||
errorJSON(w, "Invalid token.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate JWT Tokens
|
||||
accessToken, err := api.Auth.ValidateJWTAccessToken(accessCookie.Value)
|
||||
// Create Context
|
||||
authContext := &model.AuthContext{
|
||||
AccessToken: &accessToken,
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), "auth", authContext)
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
if err != nil && err.Error() == "exp not satisfied" {
|
||||
log.Info("[middleware] Refreshing AccessToken")
|
||||
accessToken, err = api.refreshAccessToken(w, r)
|
||||
if err != nil {
|
||||
log.Warn("[middleware] Refreshing AccessToken failed: ", err)
|
||||
errorJSON(w, "Invalid token.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
log.Info("[middleware] AccessToken Refreshed")
|
||||
} else if err != nil {
|
||||
log.Warn("[middleware] AccessToken failed to validate")
|
||||
errorJSON(w, "Invalid token.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
// Acquire UserID and DeviceID
|
||||
reqInfo := make(map[string]string)
|
||||
uid, _ := accessToken.Get("sub")
|
||||
did, _ := accessToken.Get("did")
|
||||
reqInfo["uid"] = uid.(string)
|
||||
reqInfo["did"] = did.(string)
|
||||
|
||||
// Add context
|
||||
ctx := context.WithValue(r.Context(), "uuids", reqInfo)
|
||||
sr := r.WithContext(ctx)
|
||||
|
||||
next.ServeHTTP(w, sr)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API) logMiddleware(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.Println(r.Method, r.URL)
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.SetOutput(os.Stdout)
|
||||
log.Println(r.Method, r.URL)
|
||||
h.ServeHTTP(w, r)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
@@ -13,39 +13,46 @@ import (
|
||||
|
||||
func (api *API) registerRoutes() {
|
||||
|
||||
// Set up Directives
|
||||
c := generated.Config{ Resolvers: &graph.Resolver{ DB: api.DB } }
|
||||
c.Directives.HasMinRole = hasMinRoleDirective
|
||||
c.Directives.Meta = metaDirective
|
||||
srv := handler.NewDefaultServer(generated.NewExecutableSchema(c))
|
||||
// Set up Directives
|
||||
graphConfig := generated.Config{
|
||||
Resolvers: &graph.Resolver{
|
||||
DB: api.DB,
|
||||
Auth: api.Auth,
|
||||
},
|
||||
Directives: generated.DirectiveRoot{
|
||||
Meta: api.metaDirective,
|
||||
HasMinRole: api.hasMinRoleDirective,
|
||||
},
|
||||
}
|
||||
srv := handler.NewDefaultServer(generated.NewExecutableSchema(graphConfig))
|
||||
|
||||
// Handle GraphQL
|
||||
// Handle GraphQL
|
||||
api.Router.Handle("/playground", playground.Handler("GraphQL playground", "/query"))
|
||||
api.Router.Handle("/query", api.injectContextMiddleware(srv))
|
||||
|
||||
// Handle Resource Route
|
||||
api.Router.HandleFunc("/media/", multipleMiddleware(
|
||||
api.mediaHandler,
|
||||
api.authMiddleware,
|
||||
))
|
||||
// Handle Resource Route
|
||||
api.Router.HandleFunc("/media/", multipleMiddleware(
|
||||
api.mediaHandler,
|
||||
api.authMiddleware,
|
||||
))
|
||||
|
||||
}
|
||||
|
||||
func errorJSON(w http.ResponseWriter, err string, code int) {
|
||||
errStruct := &APIResponse{Error: &APIError{Message: err, Code: int64(code)}}
|
||||
responseJSON(w, errStruct, code)
|
||||
errStruct := &APIResponse{Error: &APIError{Message: err, Code: int64(code)}}
|
||||
responseJSON(w, errStruct, code)
|
||||
}
|
||||
|
||||
func responseJSON(w http.ResponseWriter, msg interface{}, code int) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
json.NewEncoder(w).Encode(msg)
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
json.NewEncoder(w).Encode(msg)
|
||||
}
|
||||
|
||||
func successJSON(w http.ResponseWriter, msg string, code int) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"success": msg})
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.WriteHeader(code)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"success": msg})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user