func (h UpdatePreferencesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request, context stack.Context) {
	database := context.Get("database").(DatabaseInterface)
	connection := database.Connection()

	token := context.Get("token").(*jwt.Token)

	if _, ok := token.Claims["user_id"]; !ok {
		h.errorWriter.Write(w, webutil.MissingUserTokenError("Missing user_id from token claims."))
		return
	}

	userID := token.Claims["user_id"].(string)

	builder := services.NewPreferencesBuilder()
	validator := valiant.NewValidator(req.Body)
	err := validator.Validate(&builder)
	if err != nil {
		h.errorWriter.Write(w, webutil.ValidationError([]string{err.Error()}))
		return
	}

	preferences, err := builder.ToPreferences()
	if err != nil {
		h.errorWriter.Write(w, webutil.ValidationError([]string{err.Error()}))
		return
	}

	transaction := connection.Transaction()
	transaction.Begin()
	err = h.preferences.Update(transaction, preferences, builder.GlobalUnsubscribe, userID)
	if err != nil {
		transaction.Rollback()

		switch err.(type) {
		case services.MissingKindOrClientError, services.CriticalKindError:
			h.errorWriter.Write(w, webutil.ValidationError([]string{err.Error()}))
		default:
			h.errorWriter.Write(w, err)
		}
		return
	}

	err = transaction.Commit()
	if err != nil {
		h.errorWriter.Write(w, models.NewTransactionCommitError(err.Error()))
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
func NewTemplateParams(body io.ReadCloser) (TemplateParams, error) {
	defer body.Close()

	var template TemplateParams
	validator := valiant.NewValidator(body)

	err := validator.Validate(&template)
	if err != nil {
		switch err.(type) {
		case valiant.RequiredFieldError:
			return template, webutil.ValidationError([]string{err.Error()})
		default:
			return template, webutil.ParseError{}
		}
	}

	if template.Metadata == nil {
		template.Metadata = json.RawMessage("{}")
	}

	err = template.validateSyntax()
	if err != nil {
		return TemplateParams{}, err
	}

	template.setDefaults()

	return template, nil
}
func (h UpdateUserPreferencesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request, context stack.Context) {
	database := context.Get("database").(DatabaseInterface)
	connection := database.Connection()

	userGUID := regexp.MustCompile(".*/user_preferences/(.*)").FindStringSubmatch(req.URL.Path)[1]

	builder := services.NewPreferencesBuilder()
	validator := valiant.NewValidator(req.Body)
	err := validator.Validate(&builder)
	if err != nil {
		h.errorWriter.Write(w, webutil.ValidationError([]string{err.Error()}))
		return
	}

	preferences, err := builder.ToPreferences()
	if err != nil {
		h.errorWriter.Write(w, err)
		return
	}

	transaction := connection.Transaction()
	transaction.Begin()
	err = h.preferences.Update(transaction, preferences, builder.GlobalUnsubscribe, userGUID)
	if err != nil {
		transaction.Rollback()

		switch err.(type) {
		case services.MissingKindOrClientError, services.CriticalKindError:
			h.errorWriter.Write(w, webutil.ValidationError([]string{err.Error()}))
		default:
			h.errorWriter.Write(w, err)
		}
		return
	}

	err = transaction.Commit()
	if err != nil {
		h.errorWriter.Write(w, models.NewTransactionCommitError(err.Error()))
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
func NewNotificationParams(body io.Reader) (NotificationUpdateParams, error) {
	var params NotificationUpdateParams

	validator := valiant.NewValidator(body)
	err := validator.Validate(&params)
	if err != nil {
		switch err.(type) {
		case valiant.RequiredFieldError:
			return params, webutil.ValidationError([]string{err.Error()})
		default:
			return params, webutil.ParseError{}
		}
	}
	return params, nil
}
func (t TemplateParams) validateSyntax() error {
	toValidate := map[string]string{
		"Subject": t.Subject,
		"Text":    t.Text,
		"HTML":    t.HTML,
	}

	for field, contents := range toValidate {
		_, err := template.New("test").Parse(contents)
		if err != nil {
			return webutil.ValidationError([]string{field + " syntax is malformed please check your braces"})
		}
	}

	return nil
}
			Metadata: `{"hello": true}`,
		}))
	})

	Context("when the request is not valid", func() {
		It("indicates that fields are missing", func() {
			body := `{
				"name": "Defaultish Template",
				"subject": "{{.Subject}}",
				"metadata": {}
			}`
			request, err := http.NewRequest("PUT", "/default_template", strings.NewReader(body))
			Expect(err).NotTo(HaveOccurred())

			handler.ServeHTTP(writer, request, context)

			Expect(errorWriter.WriteCall.Receives.Error).To(BeAssignableToTypeOf(webutil.ValidationError([]string{})))
		})
	})

	Context("when the updater errors", func() {
		It("delegates the error handling to the error writer", func() {
			updater.UpdateCall.Returns.Error = errors.New("updating default template error")

			handler.ServeHTTP(writer, request, context)

			Expect(errorWriter.WriteCall.Receives.Error).To(MatchError(errors.New("updating default template error")))
		})
	})
})
						context.Set("token", token)

						handler.ServeHTTP(writer, request, context)
						Expect(errorWriter.WriteCall.Receives.Error).To(BeAssignableToTypeOf(webutil.MissingUserTokenError("")))
						Expect(transaction.BeginCall.WasCalled).To(BeFalse())
						Expect(transaction.CommitCall.WasCalled).To(BeFalse())
						Expect(transaction.RollbackCall.WasCalled).To(BeFalse())
					})
				})

				It("delegates MissingKindOrClientErrors as webutil.ValidationError to the ErrorWriter", func() {
					updater.ExecuteCall.Returns.Error = services.MissingKindOrClientError("BOOM!")

					handler.ServeHTTP(writer, request, context)

					Expect(errorWriter.WriteCall.Receives.Error).To(Equal(webutil.ValidationError([]string{"BOOM!"})))

					Expect(transaction.BeginCall.WasCalled).To(BeTrue())
					Expect(transaction.CommitCall.WasCalled).To(BeFalse())
					Expect(transaction.RollbackCall.WasCalled).To(BeTrue())
				})

				It("delegates CriticalKindErrors as webutil.ValidationError to the ErrorWriter", func() {
					updater.ExecuteCall.Returns.Error = services.CriticalKindError("BOOM!")

					handler.ServeHTTP(writer, request, context)

					Expect(errorWriter.WriteCall.Receives.Error).To(Equal(webutil.ValidationError([]string{"BOOM!"})))

					Expect(transaction.BeginCall.WasCalled).To(BeTrue())
					Expect(transaction.CommitCall.WasCalled).To(BeFalse())
				Expect(parameters.Subject).To(Equal("{{.Subject}}"))
				Expect(parameters.Metadata).To(Equal(json.RawMessage("{}")))
			})

			Context("when the template has invalid syntax", func() {
				Context("when subject template has invalid syntax", func() {
					It("returns a validation error", func() {
						body := buildTemplateRequestBody(templates.TemplateParams{
							Name:    "Template name",
							Text:    "Textual template",
							HTML:    "HTML template",
							Subject: "{{.bad}",
						})
						_, err := templates.NewTemplateParams(ioutil.NopCloser(body))
						Expect(err).To(HaveOccurred())
						Expect(err).To(BeAssignableToTypeOf(webutil.ValidationError([]string{})))
					})
				})

				Context("when text template has invalid syntax", func() {
					It("returns a validation error", func() {
						body := buildTemplateRequestBody(templates.TemplateParams{
							Name:    "Template name",
							Text:    "You should feel {{.BAD}",
							HTML:    "<h1> Amazing </h1>",
							Subject: "Great Subject",
						})
						_, err := templates.NewTemplateParams(ioutil.NopCloser(body))
						Expect(err).To(HaveOccurred())
						Expect(err).To(BeAssignableToTypeOf(webutil.ValidationError([]string{})))
					})
Exemple #9
0
func (h Notify) Execute(connection ConnectionInterface, req *http.Request, context stack.Context,
	guid string, strategy Dispatcher, validator ValidatorInterface, vcapRequestID string) ([]byte, error) {

	parameters, err := NewNotifyParams(req.Body)
	if err != nil {
		return []byte{}, err
	}

	if !validator.Validate(&parameters) {
		return []byte{}, webutil.ValidationError(parameters.Errors)
	}

	requestReceivedTime, ok := context.Get(RequestReceivedTime).(time.Time)
	if !ok {
		panic("programmer error: missing RequestReceivedTime in http context")
	}
	token := context.Get("token").(*jwt.Token) // TODO: (rm) get rid of the context object, just pass in the token
	clientID := token.Claims["client_id"].(string)

	tokenIssuerURL, err := url.Parse(token.Claims["iss"].(string))
	if err != nil {
		return []byte{}, errors.New("Token issuer URL invalid")
	}
	uaaHost := tokenIssuerURL.Scheme + "://" + tokenIssuerURL.Host

	client, kind, err := h.finder.ClientAndKind(context.Get("database").(DatabaseInterface), clientID, parameters.KindID)
	if err != nil {
		return []byte{}, err
	}

	if kind.Critical && !h.hasCriticalNotificationsWriteScope(token.Claims["scope"]) {
		return []byte{}, postal.NewCriticalNotificationError(kind.ID)
	}

	err = h.registrar.Register(connection, client, []models.Kind{kind})
	if err != nil {
		return []byte{}, err
	}

	var responses []services.Response

	responses, err = strategy.Dispatch(services.Dispatch{
		GUID:       guid,
		Connection: connection,
		Role:       parameters.Role,
		Client: services.DispatchClient{
			ID:          clientID,
			Description: client.Description,
		},
		Kind: services.DispatchKind{
			ID:          parameters.KindID,
			Description: kind.Description,
		},
		UAAHost: uaaHost,
		VCAPRequest: services.DispatchVCAPRequest{
			ID:          vcapRequestID,
			ReceiptTime: requestReceivedTime,
		},
		Message: services.DispatchMessage{
			To:      parameters.To,
			ReplyTo: parameters.ReplyTo,
			Subject: parameters.Subject,
			Text:    parameters.Text,
			HTML: services.HTML{
				BodyContent:    parameters.ParsedHTML.BodyContent,
				BodyAttributes: parameters.ParsedHTML.BodyAttributes,
				Head:           parameters.ParsedHTML.Head,
				Doctype:        parameters.ParsedHTML.Doctype,
			},
		},
	})
	if err != nil {
		return []byte{}, err
	}

	output, err := json.Marshal(responses)
	if err != nil {
		panic(err)
	}

	return output, nil
}
	It("returns a 400 when the request cannot be parsed due to syntatically invalid JSON", func() {
		writer.Write(recorder, webutil.ParseError{})

		Expect(recorder.Code).To(Equal(400))

		body := make(map[string]interface{})
		err := json.Unmarshal(recorder.Body.Bytes(), &body)
		if err != nil {
			panic(err)
		}

		Expect(body["errors"]).To(ContainElement("Request body could not be parsed"))
	})

	It("returns a 422 when the requests are not valid due to semantically invalid JSON", func() {
		writer.Write(recorder, webutil.ValidationError([]string{"something", "another"}))

		Expect(recorder.Code).To(Equal(422))

		body := make(map[string]interface{})
		err := json.Unmarshal(recorder.Body.Bytes(), &body)
		if err != nil {
			panic(err)
		}

		Expect(body["errors"]).To(ContainElement("something"))
		Expect(body["errors"]).To(ContainElement("another"))
	})

	It("returns a 422 when trying to send a critical notification without correct scope", func() {
		writer.Write(recorder, postal.NewCriticalNotificationError("raptors"))