func (s *WalkthroughService) walkthroughListHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		db := ab.GetDB(r)
		loadFunc := LoadAllWalkthrough
		abort := false
		start := 0
		limit := 25
		if page := r.URL.Query().Get("page"); page != "" {
			pagenum, err := strconv.Atoi(page)
			ab.MaybeFail(r, http.StatusBadRequest, err)
			start = (pagenum - 1) * limit
		}

		loadFunc = beforeWalkthroughListHandler()

		if abort {
			return
		}

		entities, err := loadFunc(db, start, limit)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, walkthroughDBErrorConverter))

		// HOOK: afterWalkthroughListHandler()

		if abort {
			return
		}

		ab.Render(r).JSON(entities)
	})
}
func (s *WalkthroughService) walkthroughDeleteHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := hitch.Params(r).ByName("id")
		db := ab.GetDB(r)
		abort := false
		loadFunc := LoadWalkthrough

		loadFunc = beforeWalkthroughDeleteHandler()

		if abort {
			return
		}

		entity, err := loadFunc(db, id)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, walkthroughDBErrorConverter))
		if entity == nil {
			ab.Fail(r, http.StatusNotFound, nil)
		}

		insideWalkthroughDeleteHandler(r, entity, db)

		if abort {
			return
		}

		err = entity.Delete(db)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, walkthroughDBErrorConverter))

		// HOOK: afterWalkthroughDeleteHandler()

		if abort {
			return
		}
	})
}
func (s *WalkthroughService) walkthroughPutHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := hitch.Params(r).ByName("id")

		entity := &Walkthrough{}
		ab.MustDecode(r, entity)

		if err := entity.Validate(); entity.UUID != id || err != nil {
			ab.Fail(r, http.StatusBadRequest, err)
		}

		db := ab.GetDB(r)
		abort := false

		beforeWalkthroughPutUpdateHandler(r, entity, db)

		if abort {
			return
		}

		err := entity.Update(db)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, walkthroughDBErrorConverter))

		afterWalkthroughPutUpdateHandler(s, entity)

		if abort {
			return
		}

		ab.Render(r).JSON(entity)
	})
}
func (s *WalkthroughService) walkthroughPostHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		entity := &Walkthrough{}
		ab.MustDecode(r, entity)

		abort := false

		walkthroughPostValidation(entity, r)

		if abort {
			return
		}

		if err := entity.Validate(); err != nil {
			ab.Fail(r, http.StatusBadRequest, err)
		}

		db := ab.GetDB(r)

		err := entity.Insert(db)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, walkthroughDBErrorConverter))

		afterWalkthroughPostInsertHandler(db, s, entity)

		if abort {
			return
		}

		ab.Render(r).SetCode(http.StatusCreated).JSON(entity)
	})
}
Example #5
0
func (s *UserService) userPutHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := hitch.Params(r).ByName("id")

		entity := &User{}
		ab.MustDecode(r, entity)

		if err := entity.Validate(); entity.UUID != id || err != nil {
			ab.Fail(r, http.StatusBadRequest, err)
		}

		db := ab.GetDB(r)
		abort := false

		// HOOK: beforeUserPutUpdateHandler()

		if abort {
			return
		}

		err := entity.Update(db)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, userDBErrorConverter))

		// HOOK: afterUserPutUpdateHandler()

		if abort {
			return
		}

		ab.Render(r).JSON(entity)
	})
}
Example #6
0
func (s *UserService) userGetHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := hitch.Params(r).ByName("id")
		db := ab.GetDB(r)
		abort := false
		loadFunc := LoadUser

		// HOOK: beforeUserGetHandler()

		if abort {
			return
		}

		entity, err := loadFunc(db, id)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, userDBErrorConverter))
		if entity == nil {
			ab.Fail(r, http.StatusNotFound, nil)
		}

		// HOOK: afterUserGetHandler()

		if abort {
			return
		}

		ab.Render(r).JSON(entity)
	})
}
Example #7
0
func (s *UserService) userPostHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		entity := &User{}
		ab.MustDecode(r, entity)

		abort := false

		// HOOK: userPostValidation()

		if abort {
			return
		}

		if err := entity.Validate(); err != nil {
			ab.Fail(r, http.StatusBadRequest, err)
		}

		db := ab.GetDB(r)

		err := entity.Insert(db)
		ab.MaybeFail(r, http.StatusInternalServerError, ab.ConvertDBError(err, userDBErrorConverter))

		// HOOK: afterUserPostInsertHandler()

		if abort {
			return
		}

		ab.Render(r).SetCode(http.StatusCreated).JSON(entity)
	})
}
func insideWalkthroughDeleteHandler(r *http.Request, entity *Walkthrough, db ab.DB) {
	uid := UserDelegate.CurrentUser(r)
	currentUser, err := LoadUser(db, uid)
	ab.MaybeFail(r, http.StatusBadRequest, err)
	if entity.UID != uid {
		if !currentUser.Admin {
			ab.Fail(r, http.StatusForbidden, nil)
		}
	}
}
Example #9
0
func afterUserServiceRegister(h *hitch.Hitch) {
	h.Get("/api/user", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		sess := ab.GetSession(r)
		if sess["uid"] != "" {
			db := ab.GetDB(r)

			user, err := LoadUser(db, sess["uid"])
			ab.MaybeFail(r, http.StatusInternalServerError, err)

			ab.Render(r).
				JSON(user)
		}
	}))
}
func beforeWalkthroughPutUpdateHandler(r *http.Request, entity *Walkthrough, db ab.DB) {
	uid := UserDelegate.CurrentUser(r)
	currentUser, err := LoadUser(db, uid)
	ab.MaybeFail(r, http.StatusBadRequest, err)
	if entity.UID != uid {
		if !currentUser.Admin {
			ab.Fail(r, http.StatusForbidden, nil)
		}
	}

	previousRevision, err := LoadActualRevision(db, entity.UUID)
	ab.MaybeFail(r, http.StatusBadRequest, err)
	if previousRevision == nil {
		ab.Fail(r, http.StatusNotFound, nil)
	}

	if previousRevision.UID != uid && !currentUser.Admin {
		ab.Fail(r, http.StatusForbidden, nil)
	}

	entity.Updated = time.Now()
	entity.Revision = ""
}
Example #11
0
func corsPreflightHandler(baseURL, httpOrigin string) http.Handler {
	baseurl, err := url.Parse(baseURL)
	if err != nil {
		panic(err)
	}

	httporigin, err := url.Parse(httpOrigin)
	if err != nil {
		panic(err)
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		origin := r.Header.Get("Origin")
		method := r.Header.Get("Access-Control-Request-Method")
		headers := r.Header.Get("Access-Control-Request-Headers")

		w.Header().Add("Vary", "Origin")
		w.Header().Add("Vary", "Access-Control-Request-Method")
		w.Header().Add("Vary", "Access-Control-Request-Headers")

		if origin == "" || method == "" {
			ab.Fail(r, http.StatusBadRequest, nil)
		}

		originurl, err := url.Parse(origin)
		ab.MaybeFail(r, http.StatusBadRequest, err)

		if originurl.Host != baseurl.Host && originurl.Host != httporigin.Host {
			ab.Fail(r, http.StatusForbidden, nil)
		}

		w.Header().Set("Access-Control-Allow-Origin", origin)
		w.Header().Set("Access-Control-Allow-Methods", method)
		w.Header().Set("Access-Control-Allow-Headers", headers)
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Max-Age", "0")

		ab.Render(r).SetCode(http.StatusOK)
	})
}
Example #12
0
func (s *LogService) Register(h *hitch.Hitch) error {
	walkthroughPlayed := prometheus.NewCounter(stdprometheus.CounterOpts{
		Namespace: "walkhub",
		Subsystem: "metrics",
		Name:      "walkthrough_played",
		Help:      "Number of walkthrough plays",
	}, []string{"uuid", "embedorigin"})

	walkthroughVisited := prometheus.NewCounter(stdprometheus.CounterOpts{
		Namespace: "walkhub",
		Subsystem: "metrics",
		Name:      "walkthrough_visited",
		Help:      "Number of walkthrough visits",
	}, []string{"uuid", "embedorigin"})

	h.Post("/api/log/helpcenteropened", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		l := helpCenterOpenedLog{}
		ab.MustDecode(r, &l)

		db := ab.GetDB(r)
		userid := getLogUserID(r)

		message := fmt.Sprintf("%s has opened the help center on %s", userid, l.URL)
		ab.MaybeFail(r, http.StatusInternalServerError, DBLog(db, "helpcenteropened", message))
	}))

	h.Post("/api/log/walkthroughplayed", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		l := walkthroughPlayedLog{}
		ab.MustDecode(r, &l)

		db := ab.GetDB(r)
		userid := getLogUserID(r)
		wt, err := LoadActualRevision(db, l.UUID)
		ab.MaybeFail(r, http.StatusBadRequest, err)
		if wt == nil {
			ab.Fail(r, http.StatusNotFound, nil)
		}

		message := ""

		embedPart := ""
		if l.EmbedOrigin != "" {
			embedPart = "from the help center on " + l.EmbedOrigin + " "
		}

		wturl := s.BaseURL + "walkthrough/" + wt.UUID

		if l.ErrorMessage == "" {
			message = fmt.Sprintf("%s has played the walkthrough %s<%s|%s>", userid, embedPart, wturl, wt.Name)
		} else {
			message = fmt.Sprintf("%s has failed to play the walkthrough %s<%s|%s> with the error message %s", userid, embedPart, wturl, wt.Name, l.ErrorMessage)
		}

		ab.MaybeFail(r, http.StatusInternalServerError, DBLog(db, "walkthroughplayed", message))

		walkthroughPlayed.
			With(metrics.Field{Key: "uuid", Value: l.UUID}).
			With(metrics.Field{Key: "embedorigin", Value: l.EmbedOrigin}).
			Add(1)
	}))

	h.Post("/api/log/walkthroughpagevisited", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		l := walkthroughPageVisitedLog{}
		ab.MustDecode(r, &l)

		db := ab.GetDB(r)
		userid := getLogUserID(r)
		wt, err := LoadActualRevision(db, l.UUID)
		ab.MaybeFail(r, http.StatusBadRequest, err)
		if wt == nil {
			ab.Fail(r, http.StatusNotFound, nil)
		}

		embedPart := ""
		if l.EmbedOrigin != "" {
			embedPart = "embedded on " + l.EmbedOrigin + " "
		}

		wturl := s.BaseURL + "walkthrough/" + wt.UUID

		message := fmt.Sprintf("%s has visited the walkthrough page %s<%s|%s>", userid, embedPart, wturl, wt.Name)

		ab.MaybeFail(r, http.StatusInternalServerError, DBLog(db, "walkthroughvisited", message))

		walkthroughVisited.
			With(metrics.Field{Key: "uuid", Value: l.UUID}).
			With(metrics.Field{Key: "embedorigin", Value: l.EmbedOrigin}).
			Add(1)
	}))

	return nil
}