コード例 #1
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
// ApiFindOne verifies the session and returns user and profile in meta if valid.
func (SessionResourceHooks) ApiFindOne(res kit.Resource, rawId string, r kit.Request) kit.Response {
	if rawId == "" {
		return kit.NewErrorResponse("empty_token", "Empty token")
	}

	userService := res.Registry().UserService()

	user, session, err := userService.VerifySession(rawId)
	if err != nil {
		return kit.NewErrorResponse(err)
	}

	meta := make(map[string]interface{})

	if user != nil {
		userData, err := res.Backend().ModelToMap(user, true, false)
		if err != nil {
			return kit.NewErrorResponse("marshal_error", err)
		}
		meta["user"] = userData

		if user.GetProfile() != nil {
			profileData, err := res.Backend().ModelToMap(user.GetProfile(), true, false)
			if err != nil {
				return kit.NewErrorResponse("marshal_error", err)
			}
			meta["profile"] = profileData
		}
	}

	return &kit.AppResponse{
		Data: session,
		Meta: meta,
	}
}
コード例 #2
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (_ FilesResource) ApiCreate(res kit.Resource, obj kit.Model, r kit.Request) kit.Response {
	// Verify that tmp path is set either in metadata or on model.

	file := obj.(kit.File)
	if file.GetTmpPath() == "" {
		file.SetTmpPath(r.GetMeta().String("file"))
	}

	filePath := file.GetTmpPath()
	if filePath == "" {
		return kit.NewErrorResponse("no_tmp_path", "A tmp path must be set when creating a file", true)
	}

	tmpPath := getTmpPath(res)

	if !strings.HasPrefix(filePath, tmpPath) && filePath[0] != '/' {
		filePath = tmpPath + string(os.PathSeparator) + filePath
		file.SetTmpPath(filePath)
	}

	// Build the file, save it to backend and persist it to the db.
	err := res.Registry().FileService().BuildFile(file, r.GetUser(), true, true)
	if err != nil {
		kit.NewErrorResponse(err)
	}

	return &kit.AppResponse{
		Data: file,
	}
}
コード例 #3
0
ファイル: handlers.go プロジェクト: app-kit/go-appkit
func HandleFind(registry kit.Registry, request kit.Request) (kit.Response, bool) {
	collection := request.GetContext().MustString("collection")

	res := registry.Resource(collection)
	if res == nil || !res.IsPublic() {
		err := &apperror.Err{
			Code:    "unknown_resource",
			Message: fmt.Sprintf("The resource '%v' does not exist", collection),
		}
		return kit.NewErrorResponse(err), false
	}

	response, err := Find(res, request)
	if err != nil {
		response = kit.NewErrorResponse(err)
	}

	// If response contains a count and the request a "perPage" param, add a total_pages param
	// to meta.
	perPage, err2 := request.GetContext().Int("per_page")

	meta := response.GetMeta()
	if meta != nil && err2 == nil {
		count, ok := meta["count"]
		if ok {
			meta["total_pages"] = math.Ceil(float64(count.(int)) / float64(perPage))
		}
	}

	return response, false
}
コード例 #4
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
func (SessionResourceHooks) ApiDelete(res kit.Resource, id string, r kit.Request) kit.Response {
	if id != r.GetSession().GetStrId() {
		return kit.NewErrorResponse("permission_denied", "Permission denied", 403)
	}

	if err := res.Backend().Delete(r.GetSession()); err != nil {
		return kit.NewErrorResponse("db_delete_error", err, true)
	}

	return &kit.AppResponse{}
}
コード例 #5
0
ファイル: api.go プロジェクト: app-kit/go-appkit
func AuthenticationMiddleware(registry kit.Registry, r kit.Request) (kit.Response, bool) {
	// Handle authentication.
	httpRequest := r.GetHttpRequest()
	userService := registry.UserService()

	if userService == nil {
		return nil, false
	}

	authHeader := httpRequest.Header.Get("Authentication")
	if authHeader == "" {
		return nil, false
	}

	// Check for basic auth.
	if strings.HasPrefix(authHeader, "Basic ") {
		str := authHeader[6:]
		data, err := base64.StdEncoding.DecodeString(str)
		if err != nil {
			return kit.NewErrorResponse("invalid_basic_auth"), false
		} else {
			parts := strings.Split(string(data), ":")
			if len(parts) == 2 {
				userIdentifier := parts[0]
				pw := parts[1]

				user, err := userService.AuthenticateUser(userIdentifier, "password", map[string]interface{}{"password": pw})
				if err != nil {
					return kit.NewErrorResponse(err), false
				}

				r.SetUser(user)
				return nil, false
			}
		}
	}

	// Check for auth token.
	if authHeader != "" {
		token := authHeader
		user, session, err := userService.VerifySession(token)
		if err == nil {
			r.SetUser(user)
			r.SetSession(session)

			return nil, false
		} else {
			return kit.NewErrorResponse(err), false
		}
	}

	return nil, false
}
コード例 #6
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
func (hooks UserResourceHooks) ApiCreate(res kit.Resource, obj kit.Model, r kit.Request) kit.Response {
	meta := r.GetMeta()

	adaptor := meta.String("adaptor")
	if adaptor == "" {
		return kit.NewErrorResponse("adaptor_missing", "Expected 'adaptor' in metadata.", true)
	}

	rawData, ok := meta.Get("authData")
	if !ok {
		return kit.NewErrorResponse("auth_data_missing", "Expected 'authData' in metadata.", true)
	}

	data, ok := rawData.(map[string]interface{})
	if !ok {
		return kit.NewErrorResponse("invalid_auth_data", "Invalid auth data: expected dictionary", true)
	}

	user := obj.(kit.User)

	service := res.Registry().UserService()

	// If a profile model was registered, and profile data is in meta,
	// create the profile model.
	if profiles := service.ProfileResource(); profiles != nil {
		profile := profiles.CreateModel().(kit.UserProfile)

		if rawData, ok := meta.Get("profile"); ok {
			if data, ok := rawData.(map[string]interface{}); ok {
				// Profile data present in meta.
				// Update profile with data.
				if err := res.ModelInfo().UpdateModelFromData(profile, data); err != nil {
					return kit.NewErrorResponse("invalid_profile_data", "Invalid profile data.", err, true)
				}
			}
		}

		user.SetProfile(profile)
	}

	if err := service.CreateUser(user, adaptor, data); err != nil {
		return kit.NewErrorResponse(err)
	}

	return &kit.AppResponse{
		Data: user,
	}
}
コード例 #7
0
ファイル: middlewares.go プロジェクト: app-kit/go-appkit
func SerializeResponseMiddleware(registry kit.Registry, request kit.Request, response kit.Response) (kit.Response, bool) {
	// Try to serialize the reponse data.

	// Determine serializer.
	serializer := registry.DefaultSerializer()

	// Check if a custom serializer was specified.
	if name := request.GetContext().String("response-serializer"); name != "" {
		serializer = registry.Serializer(name)
		if serializer == nil {
			errResp := kit.NewErrorResponse("unknown_response_serializer", true)
			data, _ := serializer.MustSerializeResponse(errResp)
			errResp.SetData(data)
			return errResp, false
		}
	}

	// Set format in metadata.
	meta := response.GetMeta()
	if meta == nil {
		meta = make(map[string]interface{})
	}

	meta["format"] = serializer.Name()
	response.SetMeta(meta)

	data, err := serializer.MustSerializeResponse(response)
	if err != nil {
		registry.Logger().Errorf("Response serialization error: %v (%+v)", err, response)
	}
	response.SetData(data)

	return nil, false
}
コード例 #8
0
ファイル: api.go プロジェクト: app-kit/go-appkit
func notFoundHandler(registry kit.Registry, r kit.Request) (kit.Response, bool) {
	httpRequest := r.GetHttpRequest()
	apiPrefix := "/" + registry.Config().UString("api.prefix", "api")
	isApiRequest := strings.HasPrefix(httpRequest.URL.Path, apiPrefix)

	// Try to render the page on the server, if enabled.
	if !isApiRequest {
		renderEnabled := registry.Config().UBool("serverRenderer.enabled", false)
		noRender := strings.Contains(httpRequest.URL.String(), "no-server-render")

		if renderEnabled && !noRender {
			return serverRenderer(registry, r), false
		}
	}

	// For non-api requests, render the default template.
	if !isApiRequest {
		tpl, err := getIndexTpl(registry)
		if err != nil {
			return kit.NewErrorResponse(err), false
		}
		return &kit.AppResponse{
			RawData: tpl,
		}, false
	}

	// For api requests, render the api not found error.
	return &kit.AppResponse{
		Error: &apperror.Err{
			Code:    "not_found",
			Message: "This api route does not exist",
		},
	}, false
}
コード例 #9
0
ファイル: handlers.go プロジェクト: app-kit/go-appkit
func HandleUpdate(registry kit.Registry, request kit.Request) (kit.Response, bool) {
	response, err := Update(registry, request)
	if err != nil {
		return kit.NewErrorResponse(err), false
	}

	return response, false
}
コード例 #10
0
ファイル: api.go プロジェクト: app-kit/go-appkit
func UnserializeRequestMiddleware(registry kit.Registry, request kit.Request) (kit.Response, bool) {
	// Try to parse json in body. Ignore error since body might not contain json.
	contentType := request.GetHttpRequest().Header.Get("Content-Type")
	if strings.Contains(contentType, "json") {
		// Only read the HTTP body automatically for json content type requests,
		// since some handlers might need to read it themselfes (see the files package resource).
		if err := request.ReadHttpBody(); err != nil {
			return kit.NewErrorResponse(err, "http_body_read_error"), false
		} else {
			if request.GetRawData() != nil {
				if err := request.ParseJsonData(); err != nil {
					return kit.NewErrorResponse(err, "invalid_json_body", true), false
				}

				if request.GetData() != nil {
					// Successfully parsed json body.

					// Now try to unserialize.

					// Determine serializer.
					serializer := registry.DefaultSerializer()

					// Check if a custom serializer was specified.
					if name := request.GetContext().String("request-serializer"); name != "" {
						serializer = registry.Serializer(name)
					}

					if serializer == nil {
						return kit.NewErrorResponse("unknown_serializer", fmt.Sprintf("The specified request serializer does not exist")), false
					} else {
						if err := request.Unserialize(serializer); err != nil {
							return kit.NewErrorResponse(err, "request_unserialize_error", true), false
						}
					}
				}
			}
		}
	}

	return nil, false
}
コード例 #11
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
func (PageResource) Methods(res kit.Resource) []kit.Method {

	publish := &methods.Method{
		Name:     "cms.page.publish",
		Blocking: true,
		Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
			user := r.GetUser()
			if user == nil || !user.HasRole("admin") {
				return kit.NewErrorResponse("permission_denied")
			}

			id := utils.GetMapStringKey(r.GetData(), "id")

			if id == "" {
				return kit.NewErrorResponse("no_id_in_data", "Expected 'id' key in data.")
			}

			rawPage, err := res.Backend().FindOne("pages", id)
			if err != nil {
				return kit.NewErrorResponse("db_error", err)
			} else if rawPage == nil {
				return kit.NewErrorResponse("not_found", "The specified page id does not exist.")
			}

			err = res.ModelInfo().UpdateModelFromData(rawPage, map[string]interface{}{
				"published":    true,
				"published_at": time.Now(),
			})

			if err != nil {
				return kit.NewErrorResponse("db_error", err)
			}

			return &kit.AppResponse{
				Data: map[string]interface{}{"success": true},
			}
		},
	}

	return []kit.Method{publish}
}
コード例 #12
0
ファイル: handlers.go プロジェクト: app-kit/go-appkit
func HandleDelete(registry kit.Registry, request kit.Request) (kit.Response, bool) {
	collection := request.GetContext().MustString("collection")
	id := request.GetContext().MustString("id")

	res := registry.Resource(collection)
	if res == nil || !res.IsPublic() {
		resp := kit.NewErrorResponse("unknown_resource", fmt.Sprintf("The resource '%v' does not exist", collection))
		return resp, false
	}

	return res.ApiDelete(id, request), false
}
コード例 #13
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (res *Resource) ApiDelete(id string, r kit.Request) kit.Response {
	if deleteHook, ok := res.hooks.(ApiDeleteHook); ok {
		return deleteHook.ApiDelete(res, id, r)
	}

	oldObj, err := res.FindOne(id)
	if err != nil {
		return kit.NewErrorResponse(err)
	} else if oldObj == nil {
		return kit.NewErrorResponse("not_found", "")
	}

	user := r.GetUser()
	if err := res.Delete(oldObj, user); err != nil {
		return kit.NewErrorResponse(err)
	}

	return &kit.AppResponse{
		Data: oldObj,
	}
}
コード例 #14
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
// Creating a session is equivalent to logging in.
func (hooks SessionResourceHooks) ApiCreate(res kit.Resource, obj kit.Model, r kit.Request) kit.Response {
	userService := res.Registry().UserService()

	meta := r.GetMeta()

	isAnonymous, _ := meta.Bool("anonymous")

	// Find user.
	userIdentifier := meta.String("user")
	adaptor := meta.String("adaptor")
	data, _ := meta.Map("authData")

	var user kit.User
	if !isAnonymous {
		if adaptor == "" {
			return kit.NewErrorResponse("adaptor_missing", "Expected 'adaptor' in metadata.", true)
		}

		if data == nil {
			kit.NewErrorResponse("no_or_invalid_auth_data", "Expected 'authData' dictionary in metadata.")
		}

		var err apperror.Error
		user, err = userService.AuthenticateUser(userIdentifier, adaptor, data)
		if err != nil {
			return kit.NewErrorResponse(err)
		}
	}

	session, err := userService.StartSession(user, r.GetFrontend())
	if err != nil {
		return kit.NewErrorResponse(err)
	}

	responseMeta := make(map[string]interface{})

	if !isAnonymous {
		userData, err := res.Backend().ModelToMap(user, true, false)
		if err != nil {
			return kit.NewErrorResponse("marshal_error", err)
		}
		responseMeta["user"] = userData

		if user.GetProfile() != nil {
			profileData, err := res.Backend().ModelToMap(user.GetProfile(), true, false)
			if err != nil {
				return kit.NewErrorResponse("marshal_error", err)
			}
			responseMeta["profile"] = profileData
		}
	}

	return &kit.AppResponse{
		Data: session,
		Meta: responseMeta,
	}
}
コード例 #15
0
ファイル: wamp.go プロジェクト: app-kit/go-appkit
func UnserializerMiddleware(registry kit.Registry, request kit.Request) (kit.Response, bool) {
	serializer := registry.DefaultSerializer()

	// Try to find custom serializer.
	data, ok := request.GetData().(map[string]interface{})
	if ok {
		name, ok := data["request_serializer"].(string)
		if ok {
			s := registry.Serializer(name)
			if s == nil {
				resp := kit.NewErrorResponse("unknown_request_serializer", fmt.Sprintf("The given request serializer %v does not exist", name))
				return resp, false
			} else {
				serializer = s
			}
		}
	}

	if err := serializer.UnserializeRequest(request.GetData(), request); err != nil {
		return kit.NewErrorResponse(err), false
	}

	return nil, false
}
コード例 #16
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (res *Resource) ApiFindOne(rawId string, r kit.Request) kit.Response {
	hook, ok := res.hooks.(ApiFindOneHook)
	if ok {
		return hook.ApiFindOne(res, rawId, r)
	}

	result, err := res.FindOne(rawId)
	if err != nil {
		return kit.NewErrorResponse(err)
	} else if result == nil {
		return kit.NewErrorResponse("not_found", "")
	}

	user := r.GetUser()
	if allowFind, ok := res.hooks.(AllowFindHook); ok {
		if !allowFind.AllowFind(res, result, user) {
			return kit.NewErrorResponse("permission_denied", "")
		}
	}

	return &kit.AppResponse{
		Data: result,
	}
}
コード例 #17
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (res *Resource) ApiPartialUpdate(obj kit.Model, r kit.Request) kit.Response {
	if updateHook, ok := res.hooks.(ApiUpdateHook); ok {
		return updateHook.ApiUpdate(res, obj, r)
	}

	user := r.GetUser()
	err := res.PartialUpdate(obj, user)
	if err != nil {
		return kit.NewErrorResponse(err)
	}

	return &kit.AppResponse{
		Data: obj,
	}
}
コード例 #18
0
ファイル: methods.go プロジェクト: app-kit/go-appkit
}

type ResourceMethodData struct {
	Resource kit.Resource
	Objects  []kit.Model
	Ids      []string
	Query    db.Query
}

var createMethod kit.Method = &Method{
	Name:     "create",
	Blocking: true,
	Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
		models := r.GetTransferData().GetModels()
		if len(models) == 0 {
			return kit.NewErrorResponse("no_model", "No model was found in the request.")
		} else if len(models) > 1 {
			return kit.NewErrorResponse("multiple_models", "Request contained more than one model.")
		}

		res := registry.Resource(models[0].Collection())
		if res == nil || !res.IsPublic() {
			return kit.NewErrorResponse("unknown_collection", fmt.Sprintf("The collection %v does not exist", models[0].Collection()))
		}

		return res.ApiCreate(models[0], r)
	},
}

var updateMethod kit.Method = &Method{
	Name:     "update",
コード例 #19
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
func (UserResourceHooks) Methods(res kit.Resource) []kit.Method {
	sendConfirmationEmail := &methods.Method{
		Name:     "users.send-confirmation-email",
		Blocking: false,
		Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
			user := r.GetUser()
			if user == nil {
				return kit.NewErrorResponse("not_authenticated", "")
			}

			if user.IsEmailConfirmed() {
				return kit.NewErrorResponse("email_already_confirmed", "The users email address is already confirmed")
			}

			err := registry.UserService().SendConfirmationEmail(user)
			if err != nil {
				return kit.NewErrorResponse("confirm_failed", "Could not confirm email")
			}

			return &kit.AppResponse{
				Data: map[string]interface{}{"success": true},
			}
		},
	}

	confirmEmail := &methods.Method{
		Name:     "users.confirm-email",
		Blocking: false,
		Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
			data, ok := r.GetData().(map[string]interface{})
			if !ok {
				return kit.NewErrorResponse("invalid_data", "Expected data dict with 'token' key")
			}
			token, ok := data["token"].(string)
			if !ok {
				return kit.NewErrorResponse("invalid_data", "Expected 'token' string key in data")
			}
			if token == "" {
				return kit.NewErrorResponse("empty_token", "")
			}

			_, err := registry.UserService().ConfirmEmail(token)
			if err != nil {
				return kit.NewErrorResponse("confirm_failed", "Could not confirm email")
			}

			return &kit.AppResponse{
				Data: map[string]interface{}{"success": true},
			}
		},
	}

	requestPwReset := &methods.Method{
		Name:     "users.request-password-reset",
		Blocking: false,
		Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
			data, ok := r.GetData().(map[string]interface{})
			if !ok {
				return kit.NewErrorResponse("invalid_data", "Expected data dict with 'user' key", true)
			}

			userIdentifier, ok := data["user"].(string)
			if !ok {
				return kit.NewErrorResponse("invalid_data", "Expected data dict with 'user' string key", true)
			}

			rawUser, err := res.Q().Filter("email", userIdentifier).Or("username", userIdentifier).First()
			if err != nil {
				return kit.NewErrorResponse(err)
			}
			if rawUser == nil {
				return kit.NewErrorResponse("unknown_user", fmt.Sprintf("The user %v does not exist", userIdentifier), true)
			}

			user := rawUser.(kit.User)

			err = registry.UserService().SendPasswordResetEmail(user)
			if err != nil {
				registry.Logger().Errorf("Could not send password reset email for user %v: %v", user, err)
				return kit.NewErrorResponse("reset_email_send_failed", "Could not send the reset password mail.", true)
			}

			return &kit.AppResponse{
				Data: map[string]interface{}{"success": true},
			}
		},
	}

	pwReset := &methods.Method{
		Name:     "users.password-reset",
		Blocking: false,
		Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
			// Verify that token is in data.
			data, ok := r.GetData().(map[string]interface{})
			if !ok {
				return kit.NewErrorResponse("invalid_data", "Expected 'token' key in data", true)
			}
			token, ok := data["token"].(string)
			if !ok {
				return kit.NewErrorResponse("invalid_data", "Expected 'token' string key in data", true)
			}
			if token == "" {
				return kit.NewErrorResponse("empty_token", "", true)
			}

			// Verify that password is in data.
			newPw, ok := data["password"].(string)
			if !ok {
				return kit.NewErrorResponse("invalid_passord", "Expected 'password' string key in data", true)
			}
			if newPw == "" {
				return kit.NewErrorResponse("empty_password", "Password may not be empty", true)
			}

			user, err := registry.UserService().ResetPassword(token, newPw)
			if err != nil {
				if err.IsPublic() {
					return kit.NewErrorResponse(err)
				} else {
					return kit.NewErrorResponse("password_reset_failed", "Could not reset the password.", true)
				}
			}

			return &kit.AppResponse{
				Data: map[string]interface{}{
					"success":   true,
					"userId":    user.GetId(),
					"userEmail": user.GetEmail(),
				},
			}
		},
	}

	changePassword := &methods.Method{
		Name:     "users.change-password",
		Blocking: false,
		Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
			// Get userId and password from request.
			userId := utils.GetMapStringKey(r.GetData(), "userId")
			if userId == "" {
				return kit.NewErrorResponse("no_userid", "Expected userId key in data", true)
			}
			password := utils.GetMapStringKey(r.GetData(), "password")
			if password == "" {
				return kit.NewErrorResponse("no_password", "Expected password key in data", true)
			}

			// Permission check.
			user := r.GetUser()
			if user == nil {
				return kit.NewErrorResponse("permission_denied", true)
			}

			// Users can only change their own password, unless they are admins.
			if userId != user.GetStrId() {
				if !(user.HasRole("admin") || user.HasPermission("users.change_passwords")) {
					return kit.NewErrorResponse("permission_denied", true)
				}
			}

			// User has the right permissions.
			userService := registry.UserService()

			// Find the user.
			rawUser, err := userService.UserResource().FindOne(userId)
			if err != nil {
				return kit.NewErrorResponse("db_error", true, err)
			}
			if rawUser == nil {
				return kit.NewErrorResponse("user_does_not_exist", true)
			}

			targetUser := rawUser.(kit.User)

			if err := userService.ChangePassword(targetUser, password); err != nil {
				return kit.NewErrorResponse(err)
			}

			// Everything worked fine.
			return &kit.AppResponse{
				Data: map[string]interface{}{"success": true},
			}
		},
	}

	return []kit.Method{
		AuthenticateMethod,
		ResumeSessionMethod,
		UnAuthenticateMethod,

		sendConfirmationEmail,
		confirmEmail,
		requestPwReset,
		pwReset, changePassword,
	}
}
コード例 #20
0
ファイル: methods.go プロジェクト: app-kit/go-appkit
package tasks

import (
	kit "github.com/app-kit/go-appkit"
	"github.com/app-kit/go-appkit/app/methods"
)

var RetryTaskMethod = &methods.Method{
	Name:     "task.retry",
	Blocking: false,
	Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
		user := r.GetUser()
		if user == nil {
			return kit.NewErrorResponse("not_authenticated", true)
		}

		taskId := r.GetData()
		if taskId == nil {
			return kit.NewErrorResponse("invalid_task_id", "Expected 'data' to be the task Id.", true)
		}

		backend := registry.DefaultBackend()
		rawTask, err := backend.FindOne("tasks", taskId)
		if err != nil {
			return kit.NewErrorResponse(err)
		} else if rawTask == nil {
			return kit.NewErrorResponse("not_found", "Task does not exist.")
		}

		task := rawTask.(kit.Task)
コード例 #21
0
ファイル: wamp.go プロジェクト: app-kit/go-appkit
func (f *Frontend) registerMethod(method kit.Method) {
	f.client.Register(method.GetName(), func(args []interface{}, kwargs map[string]interface{}, details map[string]interface{}) (result *turnpike.CallResult) {
		methodName := method.GetName()
		fmt.Printf("WAMP method %v |\n data: %v |\n details: %v\n", methodName, kwargs, details)

		request := kit.NewRequest()
		request.SetFrontend("wamp")
		request.SetPath("/method/" + methodName)
		request.SetData(kwargs)

		var response kit.Response

		// Find session.
		sessionId := uint(details["session_id"].(turnpike.ID))
		session := f.sessions[sessionId]
		if session == nil {
			s, err := f.registry.UserService().StartSession(nil, "wamp")
			if err != nil {
				response = kit.NewErrorResponse(err)
			} else {
				f.sessions[sessionId] = s
				session = s
			}
		}

		request.SetSession(session)
		if session.GetUser() != nil {
			request.SetUser(session.GetUser())
		}

		// Run before middlewares.
		for _, middleware := range f.beforeMiddlewares {
			resp, skip := middleware(f.registry, request)
			if skip {
				panic("WAMP frontend middlewares do not support skipping.")
			} else if resp != nil {
				response = resp
				break
			}
		}

		// Run the method.
		if response == nil {
			responder := func(r kit.Response) {
				response = r
			}

			finishedChannel, err := f.registry.App().RunMethod(methodName, request, responder, true)
			if err != nil {
				response = kit.NewErrorResponse(err)
			} else {
				<-finishedChannel
			}
		}

		// Run after middlewares.
		for _, middleware := range f.afterMiddlewares {
			resp, skip := middleware(f.registry, request, response)
			if skip {
				panic("WAMP frontend middlewares do not support skipping.")
			}
			if resp != nil {
				response = resp
			}
		}

		return &turnpike.CallResult{Kwargs: response.GetData().(map[string]interface{})}
	}, nil)
}
コード例 #22
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (hooks FilesResource) HttpRoutes(res kit.Resource) []kit.HttpRoute {
	maxRunning := res.Registry().Config().UInt("files.thumbGenerator.maxRunning", 10)
	maxPerIPPerMinute := res.Registry().Config().UInt("files.thumbGenerator.maxPerIPPerMinute", 100)
	maxQueueSize := res.Registry().Config().UInt("files.thumbGenerator.maxQueueSize", 100)
	hooks.thumbnailRateLimiter = newRateLimiter(maxRunning, maxPerIPPerMinute, maxQueueSize)

	routes := make([]kit.HttpRoute, 0)

	// Upload route.
	uploadOptionsHandler := func(registry kit.Registry, r kit.Request) (kit.Response, bool) {
		header := r.GetHttpResponseWriter().Header()

		allowedOrigins := registry.Config().UString("fileHandler.allowedOrigins", "*")
		header.Set("Access-Control-Allow-Origin", allowedOrigins)

		header.Set("Access-Control-Allow-Methods", "OPTIONS, POST")

		allowedHeaders := registry.Config().UString("accessControl.allowedHeaders")
		if allowedHeaders == "" {
			allowedHeaders = "Authentication, Content-Type, Content-Range, Content-Disposition"
		} else {
			allowedHeaders += ", Authentication, Content-Type, Content-Range, Content-Disposition"
		}
		header.Set("Access-Control-Allow-Headers", allowedHeaders)

		return &kit.AppResponse{
			HttpStatus: 200,
			RawData:    []byte{},
		}, true
	}

	uploadOptionsRoute := kit.NewHttpRoute("/api/file-upload", "OPTIONS", uploadOptionsHandler)
	routes = append(routes, uploadOptionsRoute)

	tmpPath := getTmpPath(res)
	if tmpPath == "" {
		panic("Empty tmp path")
	}

	uploadHandler := func(registry kit.Registry, r kit.Request) (kit.Response, bool) {
		if registry.Config().UBool("fileHandler.requiresAuth", false) {
			if r.GetUser() == nil {
				return kit.NewErrorResponse("permission_denied", ""), false
			}
		}

		var files []string
		var err apperror.Error

		if err == nil {
			files, err = handleUpload(registry, tmpPath, r.GetHttpRequest())
			if err != nil {
				return kit.NewErrorResponse(err), false
			}
		}

		data := map[string]interface{}{
			"data": files,
		}

		return &kit.AppResponse{Data: data}, false
	}
	uploadRoute := kit.NewHttpRoute("/api/file-upload", "POST", uploadHandler)
	routes = append(routes, uploadRoute)

	serveFileHandler := func(registry kit.Registry, r kit.Request) (kit.Response, bool) {
		file, err := registry.FileService().FindOne(r.GetContext().String("id"))

		if err != nil {
			return kit.NewErrorResponse(err), false
		}

		if file == nil {
			return &kit.AppResponse{
				HttpStatus: 404,
				RawData:    []byte("File not found"),
			}, false
		}

		reader, err := file.Reader()
		if err != nil {
			return kit.NewErrorResponse(err), false
		}
		defer reader.Close()

		w := r.GetHttpResponseWriter()

		err = serveFile(w, r.GetHttpRequest(), file.GetMime(), file.GetSize(), reader)
		reader.Close()

		if err != nil {
			registry.Logger().Errorf("Error while serving file %v(%v): %v", file.GetId(), file.GetBackendId(), err)
		}

		return nil, true
	}
	serveFileRoute := kit.NewHttpRoute("/files/:id/*rest", "GET", serveFileHandler)
	routes = append(routes, serveFileRoute)

	serveImageHandler := func(registry kit.Registry, r kit.Request) (kit.Response, bool) {
		file, err := registry.FileService().FindOne(r.GetContext().String("id"))
		if err != nil {
			return kit.NewErrorResponse(err), false
		}

		if file == nil {
			return &kit.AppResponse{
				HttpStatus: 404,
				RawData:    []byte("File not found"),
			}, false
		}

		if !file.GetIsImage() {
			return &kit.AppResponse{
				Error: &apperror.Err{
					Code:    "file_is_no_image",
					Message: "The requested file is not an image",
				},
			}, false
		}

		httpRequest := r.GetHttpRequest()

		query := httpRequest.URL.Query()
		rawWidth := query.Get("width")
		rawHeight := query.Get("height")

		var width, height int64

		if rawWidth != "" {
			width, _ = strconv.ParseInt(rawWidth, 10, 64)
		}
		if rawHeight != "" {
			height, _ = strconv.ParseInt(rawHeight, 10, 64)
		}

		rawFilters := query.Get("filters")
		filters := strings.Split(rawFilters, ",")

		thumbDir := registry.Config().UString("thumbnailDir")
		if thumbDir == "" {
			thumbDir = tmpPath + string(os.PathSeparator) + "thumbnails"
		}

		ip := strings.Split(httpRequest.RemoteAddr, ":")[0]
		if ip == "" {
			ip = httpRequest.Header.Get("X-Forwarded-For")
		}

		reader, size, err := hooks.getImageReader(registry, thumbDir, file, width, height, filters, ip)
		if err != nil {
			return kit.NewErrorResponse(err), false
		}

		w := r.GetHttpResponseWriter()

		err = serveFile(w, httpRequest, file.GetMime(), size, reader)
		reader.Close()

		if err != nil {
			registry.Logger().Errorf("Error while serving image %v(%v): %v", file.GetId(), file.GetBackendId(), err)
		}

		return nil, true
	}
	serveImageRoute := kit.NewHttpRoute("/images/:id/*rest", "GET", serveImageHandler)
	routes = append(routes, serveImageRoute)

	return routes
}
コード例 #23
0
ファイル: methods.go プロジェクト: app-kit/go-appkit
package users

import (
	//"github.com/theduke/go-apperror"
	kit "github.com/app-kit/go-appkit"
	"github.com/app-kit/go-appkit/app/methods"
)

var AuthenticateMethod kit.Method = &methods.Method{
	Name:     "users.authenticate",
	Blocking: true,
	Handler: func(registry kit.Registry, r kit.Request, unblock func()) kit.Response {
		if r.GetUser() != nil {
			return kit.NewErrorResponse("already_authenticated", "Can't authenticate a session which is already authenticated", true)
		}

		data, ok := r.GetData().(map[string]interface{})
		if !ok {
			return kit.NewErrorResponse("invalid_data", "Invalid data: expected dict", true)
		}

		// Find user.

		userIdentifier, _ := data["user"].(string)

		adaptor, _ := data["adaptor"].(string)
		if adaptor == "" {
			return kit.NewErrorResponse("adaptor_missing", "Expected 'adaptor' in metadata.", true)
		}

		authData, _ := data["authData"].(map[string]interface{})
コード例 #24
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (res *Resource) ApiFind(query *db.Query, r kit.Request) kit.Response {
	// If query is empty, query for all records.
	if query == nil {
		query = res.Q()
	}

	apiFindHook, ok := res.hooks.(ApiFindHook)
	if ok {
		return apiFindHook.ApiFind(res, query, r)
	}

	if alterQuery, ok := res.hooks.(ApiAlterQueryHook); ok {
		alterQuery.ApiAlterQuery(res, query, r)
	}

	result, err := res.Query(query)
	if err != nil {
		return kit.NewErrorResponse(err)
	}

	user := r.GetUser()
	if allowFind, ok := res.hooks.(AllowFindHook); ok {
		finalItems := make([]kit.Model, 0)
		for _, item := range result {
			if allowFind.AllowFind(res, item, user) {
				finalItems = append(finalItems, item)
			}
		}
		result = finalItems
	}

	response := &kit.AppResponse{
		Data: result,
	}

	// If a limit was set, count the total number of results
	// and set count parameter in metadata.
	limit := query.GetLimit()
	if limit > 0 {
		query.Limit(0).Offset(0)
		count, err := res.backend.Count(query)
		if err != nil {
			return &kit.AppResponse{
				Error: apperror.Wrap(err, "count_error", ""),
			}
		}

		response.SetMeta(map[string]interface{}{
			"count":       count,
			"total_pages": math.Ceil(float64(count) / float64(limit)),
		})
	}

	if hook, ok := res.hooks.(ApiAfterFindHook); ok {
		if err := hook.ApiAfterFind(res, result, r, response); err != nil {
			return kit.NewErrorResponse(err)
		}
	}

	return response
}
コード例 #25
0
ファイル: api.go プロジェクト: app-kit/go-appkit
func serverRenderer(registry kit.Registry, r kit.Request) kit.Response {
	url := r.GetHttpRequest().URL

	// Build the url to query.
	if url.Scheme == "" {
		url.Scheme = "http"
	}
	if url.Host == "" {
		url.Host = registry.Config().UString("host", "localhost") + ":" + registry.Config().UString("port", "8000")
	}

	q := url.Query()
	q.Set("no-server-render", "1")
	url.RawQuery = q.Encode()

	strUrl := url.String()

	cacheKey := "serverrenderer_" + strUrl
	cacheName := registry.Config().UString("serverRenderer.cache")
	var cache kit.Cache

	// If a cache is specified, try to retrieve it.
	if cacheName != "" {
		cache = registry.Cache(cacheName)
		if cache == nil {
			registry.Logger().Errorf("serverRenderer.cache is set to %v, but the cache is not registered with app", cacheName)
		}
	}

	// If a cache was found, try to retrieve cached response.
	if cache != nil {
		item, err := cache.Get(cacheKey)
		if err != nil {
			registry.Logger().Errorf("serverRenderer: cache retrieval error: %v", err)
		} else if item != nil {
			// Cache item found, return response with cache item.
			status, _ := strconv.ParseInt(item.GetTags()[0], 10, 64)
			data, _ := item.ToString()

			return &kit.AppResponse{
				HttpStatus: int(status),
				RawData:    []byte(data),
			}
		}
	}

	// Either no cache or url not yet cached, so render it.

	// First, ensure that the tmp directory exists.
	tmpDir := path.Join(registry.Config().TmpDir(), "phantom")
	if ok, _ := utils.FileExists(tmpDir); !ok {
		if err := os.MkdirAll(tmpDir, 0777); err != nil {
			return &kit.AppResponse{
				Error: &apperror.Err{
					Code:    "create_tmp_dir_failed",
					Message: fmt.Sprintf("Could not create the tmp directory at %v: %v", tmpDir, err),
				},
			}
		}
	}

	// Build a unique file name.
	filePath := path.Join(tmpDir, utils.UUIdv4()+".html")

	// Execute phantom js.

	// Find path of phantom script.
	_, filename, _, _ := runtime.Caller(1)
	scriptPath := path.Join(path.Dir(path.Dir(filename)), "phantom", "render.js")

	start := time.Now()

	phantomPath := registry.Config().UString("serverRenderer.phantomJsPath", "phantomjs")

	args := []string{
		"--web-security=false",
		"--local-to-remote-url-access=true",
		scriptPath,
		"10",
		strUrl,
		filePath,
	}
	result, err := exec.Command(phantomPath, args...).CombinedOutput()
	if err != nil {
		registry.Logger().Errorf("Phantomjs execution error: %v", string(result))

		return &kit.AppResponse{
			Error: apperror.Wrap(err, "phantom_execution_failed"),
		}
	}

	// Get time taken as milliseconds.
	timeTaken := int(time.Now().Sub(start) / time.Millisecond)
	registry.Logger().WithFields(log.Fields{
		"action":       "phantomjs_render",
		"milliseconds": timeTaken,
	}).Debugf("Rendered url %v with phantomjs", url)

	content, err2 := utils.ReadFile(filePath)
	if err2 != nil {
		return kit.NewErrorResponse(err2)
	}

	// Find http status code.
	status := 200
	res := regexp.MustCompile("http_status_code\\=(\\d+)").FindStringSubmatch(string(content))
	if res != nil {
		s, _ := strconv.ParseInt(res[1], 10, 64)
		status = int(s)
	}

	// Save to cache.
	if cache != nil {
		lifetime := registry.Config().UInt("serverRenderer.cacheLiftetime", 3600)

		err := cache.Set(&caches.StrItem{
			Key:       cacheKey,
			Value:     string(content),
			Tags:      []string{strconv.FormatInt(int64(status), 10)},
			ExpiresAt: time.Now().Add(time.Duration(lifetime) * time.Second),
		})
		if err != nil {
			registry.Logger().Errorf("serverRenderer: Cache persist error: %v", err)
		}
	}

	return &kit.AppResponse{
		HttpStatus: status,
		RawData:    content,
	}
}