Beispiel #1
0
// Retrieve retrieves a single form from the store.
// 200 Success, 400 Bad Request, 404 Not Found, 500 Internal
func (formHandle) Retrieve(c *web.Context) error {
	id := c.Params["id"]

	f, err := form.Retrieve(c.SessionID, c.Ctx["DB"].(*db.DB), id)
	if err != nil {
		return err
	}

	c.Respond(f, http.StatusOK)
	return nil
}
Beispiel #2
0
// Create creates a new FormSubmission based on the payload of replies and the
// formID that is being submitted.
// 200 Success, 400 Bad Request, 404 Not Found, 500 Internal
func (formSubmissionHandle) Create(c *web.Context) error {
	var payload struct {
		Recaptcha string                   `json:"recaptcha"`
		Answers   []submission.AnswerInput `json:"replies"`
	}
	if err := json.NewDecoder(c.Request.Body).Decode(&payload); err != nil {
		return err
	}

	formID := c.Params["form_id"]

	// We should check to see if the form has a recaptcha property.
	f, err := form.Retrieve(c.SessionID, c.Ctx["DB"].(*db.DB), formID)
	if err != nil {
		return err
	}

	// If the recaptcha is enabled on the form, then we should check that the
	// response contains the data we need and if it's valid.
	if enabled, ok := f.Settings["recaptcha"].(bool); ok && enabled {
		if len(payload.Recaptcha) <= 0 {
			log.Error(c.SessionID, "FormSubmission : Create", ErrInvalidCaptcha, "Payload empty")
			return ErrInvalidCaptcha
		}

		// Check to see if Recaptcha has been enabled on the server.
		if recaptchaSecret, ok := c.Web.Ctx["recaptcha"].(string); ok {

			// Communicate with the Google Recaptcha Web Service to validate the
			// request.
			if err := ValidateReacaptchaResponse(c, recaptchaSecret, payload.Recaptcha); err != nil {
				log.Error(c.SessionID, "FormSubmission : Create", err, "Recaptcha validation failed")
				return ErrInvalidCaptcha
			}
		} else {
			log.Dev(c.SessionID, "FormSubmission : Create", "Recaptcha disabled, will not check")
		}

	}

	s, err := ask.CreateSubmission(c.SessionID, c.Ctx["DB"].(*db.DB), formID, payload.Answers)
	if err != nil {
		return err
	}

	c.Respond(s, http.StatusOK)

	return nil
}
Beispiel #3
0
// CreateSubmission creates a form submission based on a given form with a set
// of answers related to it.
func CreateSubmission(context interface{}, db *db.DB, formID string, answers []submission.AnswerInput) (*submission.Submission, error) {
	log.Dev(context, "CreateSubmission", "Started : Form[%s]", formID)

	if !bson.IsObjectIdHex(formID) {
		log.Error(context, "CreateSubmission", ErrInvalidID, "Completed")
		return nil, ErrInvalidID
	}

	for _, answer := range answers {
		if err := answer.Validate(); err != nil {
			log.Error(context, "CreateSubmission", err, "Completed")
			return nil, err
		}
	}

	f, err := form.Retrieve(context, db, formID)
	if err != nil {
		log.Error(context, "CreateSubmission", err, "Completed")
		return nil, err
	}

	sub := submission.Submission{
		ID:          bson.NewObjectId(),
		FormID:      bson.ObjectIdHex(formID),
		Header:      f.Header,
		Footer:      f.Footer,
		Answers:     make([]submission.Answer, 0),
		DateCreated: time.Now(),
		DateUpdated: time.Now(),
	}

	// For each answer, merge in the widget details from the Form.
	for _, answer := range answers {
		var found bool

		for _, step := range f.Steps {

			for _, widget := range step.Widgets {

				if answer.WidgetID == widget.ID {

					sub.Answers = append(sub.Answers, submission.Answer{
						WidgetID: widget.ID,
						Answer:   answer.Answer,
						Identity: widget.Identity,
						Question: widget.Title,
						Props:    widget.Props,
					})

					found = true

					break
				}
			}

			if found {

				// The answer was already found above, so we don't need to keep looping!

				break
			}
		}
	}

	if err := submission.Create(context, db, formID, &sub); err != nil {
		log.Error(context, "CreateSubmission", err, "Completed")
		return nil, err
	}

	if _, err := form.UpdateStats(context, db, formID); err != nil {
		log.Error(context, "CreateSubmission", err, "Completed")
		return nil, err
	}

	log.Dev(context, "CreateSubmission", "Completed")
	return &sub, nil
}
Beispiel #4
0
// Digest returns a form digest.
// 200 Success, 400 Bad Request, 404 Not Found, 500 Internal
func (aggregationHandle) Digest(c *web.Context) error {
	formID := c.Params["form_id"]

	// Load the form requested.
	f, err := form.Retrieve(c.SessionID, c.Ctx["DB"].(*db.DB), formID)
	if err == mgo.ErrNotFound {
		c.Respond(nil, http.StatusBadRequest)
	}
	if err != nil {
		return err
	}

	// Create a container for the question digests.
	questions := make(map[string]FormQuestionDigest)

	// Order is a counter to set the order questions in the form.
	order := 1

	// Loop through to form's steps/widgets to find the questions.
	for _, step := range f.Steps {
		for _, widget := range step.Widgets {

			// Unpack the question properties.
			props := widget.Props.(bson.M)

			// We are looking to only include submissions with includeInGroups or groupSubmissions.
			gs, gsok := props["groupSubmissions"]
			iig, iigok := props["includeInGroups"]

			// Skip other questions, and do it verbosely to protect against messy data.
			if (gs == nil || !gsok || gs == false) && (iig == nil || !iigok || iig == false) {
				continue
			}

			// Include options for MultipleChoice questions.
			options := []FormQuestionOptionDigest{}
			if widget.Component == "MultipleChoice" {

				// Step outside the safety of the type system...
				opts := props["options"].([]interface{})

				for _, opt := range opts {
					option := opt.(bson.M)

					// Hash the answer text for a unique key, as no actual key exists.
					hasher := md5.New()
					hasher.Write([]byte(option["title"].(string)))
					optKeyStr := hex.EncodeToString(hasher.Sum(nil))

					// Add this option to the array.
					options = append(options, FormQuestionOptionDigest{
						ID:    optKeyStr,
						Value: option["title"].(string),
					})
				}
			}

			// Add the question to the digest.
			questions[widget.ID] = FormQuestionDigest{
				ID:      widget.ID,
				Type:    widget.Component,
				Title:   widget.Title,
				GroupBy: gsok,
				Options: options,
				Order:   order,
			}

			// Increment the order counter.
			order = order + 1

		}
	}

	digest := FormDigest{
		Questions: questions,
	}

	c.Respond(digest, http.StatusOK)

	return nil
}
Beispiel #5
0
func TestUpsertDelete(t *testing.T) {
	fms, db := setupForms(t, "form")
	defer teardownForms(t, db)

	t.Log("Given the need to upsert and delete forms.")
	{
		t.Log("\tWhen starting from an empty forms collection")
		{
			//----------------------------------------------------------------------
			// Upsert the form.

			if err := form.Upsert(tests.Context, db, &fms[0]); err != nil {
				t.Fatalf("\t%s\tShould be able to upsert a form : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to upsert a form.", tests.Success)

			//----------------------------------------------------------------------
			// Get the form.

			fm, err := form.Retrieve(tests.Context, db, fms[0].ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to get the form by id : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to get the form by id.", tests.Success)

			//----------------------------------------------------------------------
			// Check that we got the form we expected.

			if fms[0].ID.Hex() != fm.ID.Hex() {
				t.Fatalf("\t%s\tShould be able to get back the same form.", tests.Failed)
			}
			t.Logf("\t%s\tShould be able to get back the same form.", tests.Success)

			//----------------------------------------------------------------------
			// Delete the form.

			if err := form.Delete(tests.Context, db, fms[0].ID.Hex()); err != nil {
				t.Fatalf("\t%s\tShould be able to delete the form : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to delete the form.", tests.Success)

			//----------------------------------------------------------------------
			// Get the form.

			_, err = form.Retrieve(tests.Context, db, fms[0].ID.Hex())
			if err == nil {
				t.Fatalf("\t%s\tShould generate an error when getting a form with the deleted id : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould generate an error when getting a form with the deleted id.", tests.Success)

			//----------------------------------------------------------------------
			// Create a new fresh form.

			fms[0].ID = ""

			if err := form.Upsert(tests.Context, db, &fms[0]); err != nil {
				t.Fatalf("\t%s\tShould be able to upsert a form : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to upsert a form.", tests.Success)

			//----------------------------------------------------------------------
			// Ensure that an ID was set.

			if fms[0].ID == "" {
				t.Fatalf("\t%s\tShould be able to add an ID when upserting a new form : ID was not assigned", tests.Failed)
			}
			t.Logf("\t%s\tShould be able to add an ID when upserting a new form.", tests.Success)

			//----------------------------------------------------------------------
			// Get the form.

			fm, err = form.Retrieve(tests.Context, db, fms[0].ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to get the form by id : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to get the form by id.", tests.Success)

			//----------------------------------------------------------------------
			// Check that we got the form we expected.

			if fms[0].ID.Hex() != fm.ID.Hex() {
				t.Fatalf("\t%s\tShould be able to get back the same form.", tests.Failed)
			}
			t.Logf("\t%s\tShould be able to get back the same form.", tests.Success)

			//----------------------------------------------------------------------
			// Delete the form.

			if err := form.Delete(tests.Context, db, fms[0].ID.Hex()); err != nil {
				t.Fatalf("\t%s\tShould be able to delete the form : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to delete the form.", tests.Success)

			//----------------------------------------------------------------------
			// Get the form.

			_, err = form.Retrieve(tests.Context, db, fms[0].ID.Hex())
			if err == nil {
				t.Fatalf("\t%s\tShould generate an error when getting a form with the deleted id : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould generate an error when getting a form with the deleted id.", tests.Success)
		}
	}
}
Beispiel #6
0
func TestUpdateStatus(t *testing.T) {
	fms, db := setupForms(t, "form")
	defer teardownForms(t, db)

	t.Log("Given the need to upsert and delete forms.")
	{
		t.Log("\tWhen starting from an empty forms collection")
		{

			//----------------------------------------------------------------------
			// Upsert the form.

			if err := form.Upsert(tests.Context, db, &fms[0]); err != nil {
				t.Fatalf("\t%s\tShould be able to upsert a form : %s", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to upsert a form.", tests.Success)

			//----------------------------------------------------------------------
			// Update it's status.

			newStatus := "updated_" + time.Now().String()

			fm, err := form.UpdateStatus(tests.Context, db, fms[0].ID.Hex(), newStatus)
			if err != nil {
				t.Logf("\t%s\tShould be able to update a forms status without error : %s", tests.Success, err.Error())
			}
			t.Logf("\t%s\tShould be able to update a forms status without error.", tests.Success)

			//----------------------------------------------------------------------
			// Check we got the right form.

			if fm.ID.Hex() != fms[0].ID.Hex() {
				t.Fatalf("\t%s\tShould be able to retrieve a form given it's id : ID's of retrieved forms do not match", tests.Success)
			}
			t.Logf("\t%s\tShould be able to retrieve a form given it's id.", tests.Success)

			//----------------------------------------------------------------------
			// Check that it's status is changed.

			if fm.Status != newStatus {
				t.Fatalf("\t%s\tShould be able to set the status on the returned form : Expected %s, got %s", tests.Success, newStatus, fm.Status)
			}
			t.Logf("\t%s\tShould be able to set the status on the returned form.", tests.Success)

			//----------------------------------------------------------------------
			// Get a copy from the DB.

			rfm, err := form.Retrieve(tests.Context, db, fm.ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve a form given it's id : %s", tests.Success, err.Error())
			}
			t.Logf("\t%s\tShould be able to retrieve a form given it's id.", tests.Success)

			//----------------------------------------------------------------------
			// Check that the DB copy has it's status changed.

			if rfm.Status != newStatus {
				t.Fatalf("\t%s\tShould be able to update a form's status in the database : Expected %s, got %s", tests.Failed, newStatus, rfm.Status)
			}
			t.Logf("\t%s\tShould be able to update a form's status in the database.", tests.Success)
		}
	}
}
Beispiel #7
0
func Test_UpsertForm(t *testing.T) {
	db := setup(t)
	defer teardown(t, db)

	t.Log("Given the need to upsert a form.")
	{

		//----------------------------------------------------------------------
		// Get the form fixture.

		fms, err := formfix.Get("ask_form")
		if err != nil {
			t.Fatalf("%s\tShould be able to get the form fixture : %v", tests.Failed, err)
		}
		t.Logf("%s\tShould be able to get the form fixture", tests.Success)

		//----------------------------------------------------------------------
		// Select a specific form.

		fm := fms[0]

		//----------------------------------------------------------------------
		// Update it's ID to a new one to ensure we aren't updating.

		fm.ID = bson.ObjectId("")

		t.Log("\tWhen starting from an empty forms collection")
		{
			//----------------------------------------------------------------------
			// Upsert the form.
			if err := ask.UpsertForm(tests.Context, db, &fm); err != nil {
				t.Fatalf("\t%s\tShould be able to upsert the form : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to upsert the form", tests.Success)

			if fm.ID.Hex() == "" {
				t.Fatalf("\t%s\tShould be able to update the ID when upserted as a new record : ID was not updated", tests.Failed)
			}
			t.Logf("\t%s\tShould be able to update the ID when upserted as a new record", tests.Success)

			//----------------------------------------------------------------------
			// Retrieve the form to ensure it was created.

			if _, err := form.Retrieve(tests.Context, db, fm.ID.Hex()); err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve the form : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to retrieve the form", tests.Success)

			//----------------------------------------------------------------------
			// Retrieve the gallery to ensure it was created.

			gs, err := gallery.List(tests.Context, db, fm.ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve the gallery : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to retrieve the gallery", tests.Success)

			//----------------------------------------------------------------------
			// Cleanup the galleries created.

			defer func(gs []gallery.Gallery) {
				for _, g := range gs {
					if err := gallery.Delete(tests.Context, db, g.ID.Hex()); err != nil {
						t.Fatalf("\t%s\tShould be able to remove the created galleries : %v", tests.Failed, err)
					}
				}
				t.Logf("\t%s\tShould be able to remove the created galleries.", tests.Success)
			}(gs)

		}

		t.Log("\tWhen starting from an non-empty forms collection")
		{
			//----------------------------------------------------------------------
			// Update the form.

			newFooter := bson.M{"key": "value"}

			fm.Footer = newFooter

			//----------------------------------------------------------------------
			// Upsert the form.
			if err := ask.UpsertForm(tests.Context, db, &fm); err != nil {
				t.Fatalf("\t%s\tShould be able to upsert the form : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to upsert the form", tests.Success)

			if fm.ID.Hex() == "" {
				t.Fatalf("\t%s\tShould be able to update the ID when upserted as a new record : ID was not updated", tests.Failed)
			}
			t.Logf("\t%s\tShould be able to update the ID when upserted as a new record", tests.Success)

			//----------------------------------------------------------------------
			// Retrieve the form to ensure it was created.

			rf, err := form.Retrieve(tests.Context, db, fm.ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve the form : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to retrieve the form", tests.Success)

			rFooter, ok := rf.Footer.(bson.M)
			if !ok {
				t.Fatalf("\t%s\tShould have a bson document in the footer value : Does not", tests.Failed)
			}
			t.Logf("\t%s\tShould have a bson document in the footer value", tests.Success)

			value, ok := rFooter["key"]
			if !ok {
				t.Fatalf("\t%s\tShould have a bson key in the footer value : Does not", tests.Failed)
			}
			t.Logf("\t%s\tShould have a bson key in the footer value", tests.Success)

			if value != "value" {
				t.Fatalf("\t%s\tShould have expected value : Expected \"%s\", got \"%v\"", tests.Failed, "value", value)
			}
			t.Logf("\t%s\tShould have expected value", tests.Success)
		}
	}
}
Beispiel #8
0
func Test_CreateDeleteSubmission(t *testing.T) {
	db := setup(t)
	defer teardown(t, db)

	// CreateSubmission(context interface{}, db *db.DB, formID string, answers []submission.AnswerInput) (*submission.Submission, error)

	t.Log("Given the need to add a submission.")
	{

		//----------------------------------------------------------------------
		// Get the form fixture.

		fms, err := formfix.Get("ask_form")
		if err != nil {
			t.Fatalf("%s\tShould be able to get the form fixture : %v", tests.Failed, err)
		}
		t.Logf("%s\tShould be able to get the form fixture", tests.Success)

		if err := formfix.Add(tests.Context, db, fms); err != nil {
			t.Fatalf("%s\tShould be able to add the form fixture : %v", tests.Failed, err)
		}
		t.Logf("%s\tShould be able to add the form fixture", tests.Success)

		fm := fms[0]

		t.Log("\tWhen starting from an empty submission collection")
		{

			var answers []submission.AnswerInput

			// Create the answers based on the form layout.

			answer := time.Now().Unix()

			for _, step := range fm.Steps {
				for _, widget := range step.Widgets {
					answers = append(answers, submission.AnswerInput{
						WidgetID: widget.ID,
						Answer:   answer,
					})
				}
			}

			// Create the submission.

			sub, err := ask.CreateSubmission(tests.Context, db, fm.ID.Hex(), answers)
			if err != nil {
				t.Fatalf("\t%s\tShould be able to create a submission : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to create a submission.", tests.Success)

			// Ensure that the answers match.

			matchSubmissionsAndAnswers(t, sub, fm, answers)

			// Get the submission from the database.

			rsub, err := submission.Retrieve(tests.Context, db, sub.ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve a created submission : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to retrieve a created submission.", tests.Success)

			// Ensure that their answers match.

			matchSubmissionsAndAnswers(t, rsub, fm, answers)

			// Ensure that the form's stats were updated.

			rfm, err := form.Retrieve(tests.Context, db, fm.ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve a form : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to retrieve a form.", tests.Success)

			if rfm.Stats.Responses != 1 {
				t.Fatalf("\t%s\tShould be able to update the stats on a form : Expected %d, got %d", tests.Failed, 1, rfm.Stats.Responses)
			}
			t.Logf("\t%s\tShould be able to update the stats on a form", tests.Success)

			// Delete the submission.

			if err := ask.DeleteSubmission(tests.Context, db, sub.ID.Hex(), fm.ID.Hex()); err != nil {
				t.Fatalf("\t%s\tShould be able to delete a submission : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to delete a submission.", tests.Success)

			// Ensure that it is deleted.

			if _, err := submission.Retrieve(tests.Context, db, sub.ID.Hex()); err == nil {
				t.Fatalf("\t%s\tShould return not found when trying to retrieve a deleted submission : No error", tests.Failed)
			} else if err != mgo.ErrNotFound {
				t.Fatalf("\t%s\tShould return not found when trying to retrieve a deleted submission : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould return not found when trying to retrieve a deleted submission.", tests.Success)

			// Ensure that the form's stats were updated.

			rfm, err = form.Retrieve(tests.Context, db, fm.ID.Hex())
			if err != nil {
				t.Fatalf("\t%s\tShould be able to retrieve a form : %v", tests.Failed, err)
			}
			t.Logf("\t%s\tShould be able to retrieve a form.", tests.Success)

			if rfm.Stats.Responses != 0 {
				t.Fatalf("\t%s\tShould be able to update the stats on a form : Expected %d, got %d", tests.Failed, 0, rfm.Stats.Responses)
			}
			t.Logf("\t%s\tShould be able to update the stats on a form", tests.Success)
		}
	}
}