You've already forked golang-saas-starter-kit
mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-08-08 22:36:41 +02:00
issue #28 - renamed project to checklist
This commit is contained in:
@ -6,50 +6,50 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/checklist"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/datatable"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/project"
|
||||
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/DataDog/dd-trace-go.v1/contrib/go-redis/redis"
|
||||
)
|
||||
|
||||
// Projects represents the Projects API method handler set.
|
||||
type Projects struct {
|
||||
ProjectRepo *project.Repository
|
||||
Redis *redis.Client
|
||||
Renderer web.Renderer
|
||||
// Checklists represents the Checklists API method handler set.
|
||||
type Checklists struct {
|
||||
ChecklistRepo *checklist.Repository
|
||||
Redis *redis.Client
|
||||
Renderer web.Renderer
|
||||
}
|
||||
|
||||
func urlProjectsIndex() string {
|
||||
return fmt.Sprintf("/projects")
|
||||
func urlChecklistsIndex() string {
|
||||
return fmt.Sprintf("/checklists")
|
||||
}
|
||||
|
||||
func urlProjectsCreate() string {
|
||||
return fmt.Sprintf("/projects/create")
|
||||
func urlChecklistsCreate() string {
|
||||
return fmt.Sprintf("/checklists/create")
|
||||
}
|
||||
|
||||
func urlProjectsView(projectID string) string {
|
||||
return fmt.Sprintf("/projects/%s", projectID)
|
||||
func urlChecklistsView(checklistID string) string {
|
||||
return fmt.Sprintf("/checklists/%s", checklistID)
|
||||
}
|
||||
|
||||
func urlProjectsUpdate(projectID string) string {
|
||||
return fmt.Sprintf("/projects/%s/update", projectID)
|
||||
func urlChecklistsUpdate(checklistID string) string {
|
||||
return fmt.Sprintf("/checklists/%s/update", checklistID)
|
||||
}
|
||||
|
||||
// Index handles listing all the projects for the current account.
|
||||
func (h *Projects) Index(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
// Index handles listing all the checklists for the current account.
|
||||
func (h *Checklists) Index(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
|
||||
claims, err := auth.ClaimsFromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
statusOpts := web.NewEnumResponse(ctx, nil, project.ProjectStatus_ValuesInterface()...)
|
||||
statusOpts := web.NewEnumResponse(ctx, nil, checklist.ChecklistStatus_ValuesInterface()...)
|
||||
|
||||
statusFilterItems := []datatable.FilterOptionItem{}
|
||||
for _, opt := range statusOpts.Options {
|
||||
@ -61,13 +61,13 @@ func (h *Projects) Index(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
|
||||
fields := []datatable.DisplayField{
|
||||
datatable.DisplayField{Field: "id", Title: "ID", Visible: false, Searchable: true, Orderable: true, Filterable: false},
|
||||
datatable.DisplayField{Field: "name", Title: "Project", Visible: true, Searchable: true, Orderable: true, Filterable: true, FilterPlaceholder: "filter Name"},
|
||||
datatable.DisplayField{Field: "name", Title: "Checklist", Visible: true, Searchable: true, Orderable: true, Filterable: true, FilterPlaceholder: "filter Name"},
|
||||
datatable.DisplayField{Field: "status", Title: "Status", Visible: true, Searchable: true, Orderable: true, Filterable: true, FilterPlaceholder: "All Statuses", FilterItems: statusFilterItems},
|
||||
datatable.DisplayField{Field: "updated_at", Title: "Last Updated", Visible: true, Searchable: true, Orderable: true, Filterable: false},
|
||||
datatable.DisplayField{Field: "created_at", Title: "Created", Visible: true, Searchable: true, Orderable: true, Filterable: false},
|
||||
}
|
||||
|
||||
mapFunc := func(q *project.Project, cols []datatable.DisplayField) (resp []datatable.ColumnValue, err error) {
|
||||
mapFunc := func(q *checklist.Checklist, cols []datatable.DisplayField) (resp []datatable.ColumnValue, err error) {
|
||||
for i := 0; i < len(cols); i++ {
|
||||
col := cols[i]
|
||||
var v datatable.ColumnValue
|
||||
@ -76,17 +76,17 @@ func (h *Projects) Index(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
v.Value = fmt.Sprintf("%s", q.ID)
|
||||
case "name":
|
||||
v.Value = q.Name
|
||||
v.Formatted = fmt.Sprintf("<a href='%s'>%s</a>", urlProjectsView(q.ID), v.Value)
|
||||
v.Formatted = fmt.Sprintf("<a href='%s'>%s</a>", urlChecklistsView(q.ID), v.Value)
|
||||
case "status":
|
||||
v.Value = q.Status.String()
|
||||
|
||||
var subStatusClass string
|
||||
var subStatusIcon string
|
||||
switch q.Status {
|
||||
case project.ProjectStatus_Active:
|
||||
case checklist.ChecklistStatus_Active:
|
||||
subStatusClass = "text-green"
|
||||
subStatusIcon = "far fa-dot-circle"
|
||||
case project.ProjectStatus_Disabled:
|
||||
case checklist.ChecklistStatus_Disabled:
|
||||
subStatusClass = "text-orange"
|
||||
subStatusIcon = "far fa-circle"
|
||||
}
|
||||
@ -110,7 +110,7 @@ func (h *Projects) Index(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
loadFunc := func(ctx context.Context, sorting string, fields []datatable.DisplayField) (resp [][]datatable.ColumnValue, err error) {
|
||||
res, err := h.ProjectRepo.Find(ctx, claims, project.ProjectFindRequest{
|
||||
res, err := h.ChecklistRepo.Find(ctx, claims, checklist.ChecklistFindRequest{
|
||||
Where: "account_id = ?",
|
||||
Args: []interface{}{claims.Audience},
|
||||
Order: strings.Split(sorting, ","),
|
||||
@ -122,7 +122,7 @@ func (h *Projects) Index(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
for _, a := range res {
|
||||
l, err := mapFunc(a, fields)
|
||||
if err != nil {
|
||||
return resp, errors.Wrapf(err, "Failed to map project for display.")
|
||||
return resp, errors.Wrapf(err, "Failed to map checklist for display.")
|
||||
}
|
||||
|
||||
resp = append(resp, l)
|
||||
@ -148,15 +148,15 @@ func (h *Projects) Index(ctx context.Context, w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"datatable": dt.Response(),
|
||||
"urlProjectsCreate": urlProjectsCreate(),
|
||||
"datatable": dt.Response(),
|
||||
"urlChecklistsCreate": urlChecklistsCreate(),
|
||||
}
|
||||
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "projects-index.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "checklists-index.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
}
|
||||
|
||||
// Create handles creating a new project for the account.
|
||||
func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
// Create handles creating a new checklist for the account.
|
||||
func (h *Checklists) Create(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
|
||||
ctxValues, err := webcontext.ContextValues(ctx)
|
||||
if err != nil {
|
||||
@ -169,7 +169,7 @@ func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
//
|
||||
req := new(project.ProjectCreateRequest)
|
||||
req := new(checklist.ChecklistCreateRequest)
|
||||
data := make(map[string]interface{})
|
||||
f := func() (bool, error) {
|
||||
if r.Method == http.MethodPost {
|
||||
@ -186,7 +186,7 @@ func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
req.AccountID = claims.Audience
|
||||
|
||||
usr, err := h.ProjectRepo.Create(ctx, claims, *req, ctxValues.Now)
|
||||
usr, err := h.ChecklistRepo.Create(ctx, claims, *req, ctxValues.Now)
|
||||
if err != nil {
|
||||
switch errors.Cause(err) {
|
||||
default:
|
||||
@ -199,12 +199,12 @@ func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
}
|
||||
|
||||
// Display a success message to the project.
|
||||
// Display a success message to the checklist.
|
||||
webcontext.SessionFlashSuccess(ctx,
|
||||
"Project Created",
|
||||
"Project successfully created.")
|
||||
"Checklist Created",
|
||||
"Checklist successfully created.")
|
||||
|
||||
return true, web.Redirect(ctx, w, r, urlProjectsView(usr.ID), http.StatusFound)
|
||||
return true, web.Redirect(ctx, w, r, urlChecklistsView(usr.ID), http.StatusFound)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
@ -219,17 +219,17 @@ func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
|
||||
data["form"] = req
|
||||
|
||||
if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(project.ProjectCreateRequest{})); ok {
|
||||
if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(checklist.ChecklistCreateRequest{})); ok {
|
||||
data["validationDefaults"] = verr.(*weberror.Error)
|
||||
}
|
||||
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "projects-create.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "checklists-create.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
}
|
||||
|
||||
// View handles displaying a project.
|
||||
func (h *Projects) View(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
// View handles displaying a checklist.
|
||||
func (h *Checklists) View(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
|
||||
projectID := params["project_id"]
|
||||
checklistID := params["checklist_id"]
|
||||
|
||||
ctxValues, err := webcontext.ContextValues(ctx)
|
||||
if err != nil {
|
||||
@ -251,18 +251,18 @@ func (h *Projects) View(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
|
||||
switch r.PostForm.Get("action") {
|
||||
case "archive":
|
||||
err = h.ProjectRepo.Archive(ctx, claims, project.ProjectArchiveRequest{
|
||||
ID: projectID,
|
||||
err = h.ChecklistRepo.Archive(ctx, claims, checklist.ChecklistArchiveRequest{
|
||||
ID: checklistID,
|
||||
}, ctxValues.Now)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
webcontext.SessionFlashSuccess(ctx,
|
||||
"Project Archive",
|
||||
"Project successfully archive.")
|
||||
"Checklist Archive",
|
||||
"Checklist successfully archive.")
|
||||
|
||||
return true, web.Redirect(ctx, w, r, urlProjectsIndex(), http.StatusFound)
|
||||
return true, web.Redirect(ctx, w, r, urlChecklistsIndex(), http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,21 +276,21 @@ func (h *Projects) View(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
return nil
|
||||
}
|
||||
|
||||
prj, err := h.ProjectRepo.ReadByID(ctx, claims, projectID)
|
||||
prj, err := h.ChecklistRepo.ReadByID(ctx, claims, checklistID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["project"] = prj.Response(ctx)
|
||||
data["urlProjectsView"] = urlProjectsView(projectID)
|
||||
data["urlProjectsUpdate"] = urlProjectsUpdate(projectID)
|
||||
data["checklist"] = prj.Response(ctx)
|
||||
data["urlChecklistsView"] = urlChecklistsView(checklistID)
|
||||
data["urlChecklistsUpdate"] = urlChecklistsUpdate(checklistID)
|
||||
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "projects-view.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "checklists-view.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
}
|
||||
|
||||
// Update handles updating a project for the account.
|
||||
func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
// Update handles updating a checklist for the account.
|
||||
func (h *Checklists) Update(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||
|
||||
projectID := params["project_id"]
|
||||
checklistID := params["checklist_id"]
|
||||
|
||||
ctxValues, err := webcontext.ContextValues(ctx)
|
||||
if err != nil {
|
||||
@ -303,7 +303,7 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
//
|
||||
req := new(project.ProjectUpdateRequest)
|
||||
req := new(checklist.ChecklistUpdateRequest)
|
||||
data := make(map[string]interface{})
|
||||
f := func() (bool, error) {
|
||||
if r.Method == http.MethodPost {
|
||||
@ -318,9 +318,9 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
if err := decoder.Decode(req, r.PostForm); err != nil {
|
||||
return false, err
|
||||
}
|
||||
req.ID = projectID
|
||||
req.ID = checklistID
|
||||
|
||||
err = h.ProjectRepo.Update(ctx, claims, *req, ctxValues.Now)
|
||||
err = h.ChecklistRepo.Update(ctx, claims, *req, ctxValues.Now)
|
||||
if err != nil {
|
||||
switch errors.Cause(err) {
|
||||
default:
|
||||
@ -333,12 +333,12 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
}
|
||||
|
||||
// Display a success message to the project.
|
||||
// Display a success message to the checklist.
|
||||
webcontext.SessionFlashSuccess(ctx,
|
||||
"Project Updated",
|
||||
"Project successfully updated.")
|
||||
"Checklist Updated",
|
||||
"Checklist successfully updated.")
|
||||
|
||||
return true, web.Redirect(ctx, w, r, urlProjectsView(req.ID), http.StatusFound)
|
||||
return true, web.Redirect(ctx, w, r, urlChecklistsView(req.ID), http.StatusFound)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
@ -351,13 +351,13 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
return nil
|
||||
}
|
||||
|
||||
prj, err := h.ProjectRepo.ReadByID(ctx, claims, projectID)
|
||||
prj, err := h.ChecklistRepo.ReadByID(ctx, claims, checklistID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data["project"] = prj.Response(ctx)
|
||||
data["checklist"] = prj.Response(ctx)
|
||||
|
||||
data["urlProjectsView"] = urlProjectsView(projectID)
|
||||
data["urlChecklistsView"] = urlChecklistsView(checklistID)
|
||||
|
||||
if req.ID == "" {
|
||||
req.Name = &prj.Name
|
||||
@ -365,9 +365,9 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
data["form"] = req
|
||||
|
||||
if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(project.ProjectUpdateRequest{})); ok {
|
||||
if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(checklist.ChecklistUpdateRequest{})); ok {
|
||||
data["validationDefaults"] = verr.(*weberror.Error)
|
||||
}
|
||||
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "projects-update.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
return h.Renderer.Render(ctx, w, r, TmplLayoutBase, "checklists-update.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
|
||||
}
|
@ -19,9 +19,9 @@ import (
|
||||
|
||||
// Root represents the Root API method handler set.
|
||||
type Root struct {
|
||||
Renderer web.Renderer
|
||||
Sitemap *stm.Sitemap
|
||||
ProjectRoute webroute.ProjectRoute
|
||||
Renderer web.Renderer
|
||||
Sitemap *stm.Sitemap
|
||||
WebRoute webroute.WebRoute
|
||||
}
|
||||
|
||||
// Index determines if the user has authentication and loads the associated page.
|
||||
@ -56,7 +56,7 @@ func (h *Root) SitePage(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
tmpName = "site-api.gohtml"
|
||||
|
||||
// http://127.0.0.1:3001/docs/doc.json
|
||||
swaggerJsonUrl := h.ProjectRoute.ApiDocsJson(true)
|
||||
swaggerJsonUrl := h.WebRoute.ApiDocsJson(true)
|
||||
|
||||
// Load the json file from the API service.
|
||||
res, err := pester.Get(swaggerJsonUrl)
|
||||
@ -92,8 +92,8 @@ func (h *Root) SitePage(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
data["urlApiBaseUri"] = h.ProjectRoute.WebApiUrl(doc.BasePath)
|
||||
data["urlApiDocs"] = h.ProjectRoute.ApiDocs()
|
||||
data["urlApiBaseUri"] = h.WebRoute.WebApiUrl(doc.BasePath)
|
||||
data["urlApiDocs"] = h.WebRoute.ApiDocs()
|
||||
|
||||
case "/pricing":
|
||||
tmpName = "site-pricing.gohtml"
|
||||
@ -122,7 +122,7 @@ func (h *Root) RobotTxt(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
return web.RespondText(ctx, w, txt, http.StatusOK)
|
||||
}
|
||||
|
||||
sitemapUrl := h.ProjectRoute.WebAppUrl("/sitemap.xml")
|
||||
sitemapUrl := h.WebRoute.WebAppUrl("/sitemap.xml")
|
||||
|
||||
txt := fmt.Sprintf("User-agent: *\nDisallow: /ping\nDisallow: /status\nDisallow: /debug/\nSitemap: %s", sitemapUrl)
|
||||
return web.RespondText(ctx, w, txt, http.StatusOK)
|
||||
|
@ -11,19 +11,19 @@ import (
|
||||
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/account"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/account/account_preference"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/checklist"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/geonames"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/mid"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/project"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/webroute"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/signup"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user_account/invite"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user_auth"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/webroute"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/ikeikeikeike/go-sitemap-generator/v2/stm"
|
||||
@ -50,13 +50,13 @@ type AppContext struct {
|
||||
AuthRepo *user_auth.Repository
|
||||
SignupRepo *signup.Repository
|
||||
InviteRepo *invite.Repository
|
||||
ProjectRepo *project.Repository
|
||||
ChecklistRepo *checklist.Repository
|
||||
GeoRepo *geonames.Repository
|
||||
Authenticator *auth.Authenticator
|
||||
StaticDir string
|
||||
TemplateDir string
|
||||
Renderer web.Renderer
|
||||
ProjectRoute webroute.ProjectRoute
|
||||
WebRoute webroute.WebRoute
|
||||
PreAppMiddleware []web.Middleware
|
||||
PostAppMiddleware []web.Middleware
|
||||
AwsSession *session.Session
|
||||
@ -105,7 +105,7 @@ func APP(shutdown chan os.Signal, appCtx *AppContext) http.Handler {
|
||||
// Build a sitemap.
|
||||
sm := stm.NewSitemap(1)
|
||||
sm.SetVerbose(false)
|
||||
sm.SetDefaultHost(appCtx.ProjectRoute.WebAppUrl(""))
|
||||
sm.SetDefaultHost(appCtx.WebRoute.WebAppUrl(""))
|
||||
sm.Create()
|
||||
|
||||
smLocAddModified := func(loc stm.URL, filename string) {
|
||||
@ -121,19 +121,19 @@ func APP(shutdown chan os.Signal, appCtx *AppContext) http.Handler {
|
||||
sm.Add(loc)
|
||||
}
|
||||
|
||||
// Register project management pages.
|
||||
p := Projects{
|
||||
ProjectRepo: appCtx.ProjectRepo,
|
||||
Redis: appCtx.Redis,
|
||||
Renderer: appCtx.Renderer,
|
||||
// Register checklist management pages.
|
||||
p := Checklists{
|
||||
ChecklistRepo: appCtx.ChecklistRepo,
|
||||
Redis: appCtx.Redis,
|
||||
Renderer: appCtx.Renderer,
|
||||
}
|
||||
app.Handle("POST", "/projects/:project_id/update", p.Update, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/projects/:project_id/update", p.Update, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("POST", "/projects/:project_id", p.View, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/projects/:project_id", p.View, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasAuth())
|
||||
app.Handle("POST", "/projects/create", p.Create, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/projects/create", p.Create, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/projects", p.Index, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasAuth())
|
||||
app.Handle("POST", "/checklists/:checklist_id/update", p.Update, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/checklists/:checklist_id/update", p.Update, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("POST", "/checklists/:checklist_id", p.View, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/checklists/:checklist_id", p.View, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasAuth())
|
||||
app.Handle("POST", "/checklists/create", p.Create, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/checklists/create", p.Create, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasRole(auth.RoleAdmin))
|
||||
app.Handle("GET", "/checklists", p.Index, mid.AuthenticateSessionRequired(appCtx.Authenticator), mid.HasAuth())
|
||||
|
||||
// Register user management pages.
|
||||
us := Users{
|
||||
@ -231,9 +231,9 @@ func APP(shutdown chan os.Signal, appCtx *AppContext) http.Handler {
|
||||
|
||||
// Register root
|
||||
r := Root{
|
||||
Renderer: appCtx.Renderer,
|
||||
ProjectRoute: appCtx.ProjectRoute,
|
||||
Sitemap: sm,
|
||||
Renderer: appCtx.Renderer,
|
||||
WebRoute: appCtx.WebRoute,
|
||||
Sitemap: sm,
|
||||
}
|
||||
app.Handle("GET", "/api", r.SitePage)
|
||||
app.Handle("GET", "/pricing", r.SitePage)
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"geeks-accelerator/oss/saas-starter-kit/cmd/web-app/handlers"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/account"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/account/account_preference"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/checklist"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/geonames"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/mid"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
|
||||
@ -33,13 +34,12 @@ import (
|
||||
template_renderer "geeks-accelerator/oss/saas-starter-kit/internal/platform/web/tmplrender"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/project"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/webroute"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/signup"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user_account/invite"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/user_auth"
|
||||
"geeks-accelerator/oss/saas-starter-kit/internal/webroute"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
@ -440,20 +440,20 @@ func main() {
|
||||
// =========================================================================
|
||||
// Init repositories and AppContext
|
||||
|
||||
projectRoute, err := webroute.New(cfg.Project.WebApiBaseUrl, cfg.Service.BaseUrl)
|
||||
webRoute, err := webroute.New(cfg.Project.WebApiBaseUrl, cfg.Service.BaseUrl)
|
||||
if err != nil {
|
||||
log.Fatalf("main : project routes : %+v", cfg.Service.BaseUrl, err)
|
||||
log.Fatalf("main : checklist routes : %+v", cfg.Service.BaseUrl, err)
|
||||
}
|
||||
|
||||
usrRepo := user.NewRepository(masterDb, projectRoute.UserResetPassword, notifyEmail, cfg.Project.SharedSecretKey)
|
||||
usrRepo := user.NewRepository(masterDb, webRoute.UserResetPassword, notifyEmail, cfg.Project.SharedSecretKey)
|
||||
usrAccRepo := user_account.NewRepository(masterDb)
|
||||
accRepo := account.NewRepository(masterDb)
|
||||
geoRepo := geonames.NewRepository(masterDb)
|
||||
accPrefRepo := account_preference.NewRepository(masterDb)
|
||||
authRepo := user_auth.NewRepository(masterDb, authenticator, usrRepo, usrAccRepo, accPrefRepo)
|
||||
signupRepo := signup.NewRepository(masterDb, usrRepo, usrAccRepo, accRepo)
|
||||
inviteRepo := invite.NewRepository(masterDb, usrRepo, usrAccRepo, accRepo, projectRoute.UserInviteAccept, notifyEmail, cfg.Project.SharedSecretKey)
|
||||
prjRepo := project.NewRepository(masterDb)
|
||||
inviteRepo := invite.NewRepository(masterDb, usrRepo, usrAccRepo, accRepo, webRoute.UserInviteAccept, notifyEmail, cfg.Project.SharedSecretKey)
|
||||
chklstRepo := checklist.NewRepository(masterDb)
|
||||
|
||||
appCtx := &handlers.AppContext{
|
||||
Log: log,
|
||||
@ -463,7 +463,7 @@ func main() {
|
||||
Redis: redisClient,
|
||||
TemplateDir: cfg.Service.TemplateDir,
|
||||
StaticDir: cfg.Service.StaticFiles.Dir,
|
||||
ProjectRoute: projectRoute,
|
||||
WebRoute: webRoute,
|
||||
UserRepo: usrRepo,
|
||||
UserAccountRepo: usrAccRepo,
|
||||
AccountRepo: accRepo,
|
||||
@ -472,7 +472,7 @@ func main() {
|
||||
GeoRepo: geoRepo,
|
||||
SignupRepo: signupRepo,
|
||||
InviteRepo: inviteRepo,
|
||||
ProjectRepo: prjRepo,
|
||||
ChecklistRepo: chklstRepo,
|
||||
Authenticator: authenticator,
|
||||
AwsSession: awsSession,
|
||||
}
|
||||
@ -525,13 +525,14 @@ func main() {
|
||||
staticS3UrlFormatter = func(p string) string {
|
||||
// When the path starts with a forward slash its referencing a local file,
|
||||
// make sure the static file prefix is included
|
||||
if strings.HasPrefix(p, "/") || !strings.HasPrefix(p, "://") {
|
||||
if (strings.HasPrefix(p, "/") || !strings.HasPrefix(p, "://")) && !strings.HasPrefix(p, cfg.Service.StaticFiles.S3Prefix) {
|
||||
p = filepath.Join(cfg.Service.StaticFiles.S3Prefix, p)
|
||||
}
|
||||
|
||||
return s3UrlFormatter(p)
|
||||
}
|
||||
} else {
|
||||
staticS3UrlFormatter = projectRoute.WebAppUrl
|
||||
staticS3UrlFormatter = webRoute.WebAppUrl
|
||||
}
|
||||
|
||||
// staticUrlFormatter is a help function used by template functions defined below.
|
||||
@ -920,11 +921,12 @@ func main() {
|
||||
tmplFuncs["S3ImgUrl"] = func(ctx context.Context, p string, size int) string {
|
||||
imgUrl := imgUrlFormatter(p)
|
||||
if cfg.Service.StaticFiles.ImgResizeEnabled {
|
||||
|
||||
var rerr error
|
||||
imgUrl, rerr = img_resize.S3ImgUrl(ctx, redisClient, staticS3UrlFormatter, awsSession, cfg.Aws.S3BucketPublic, imgResizeS3KeyPrefix, imgUrl, size)
|
||||
if rerr != nil {
|
||||
imgUrl = "error"
|
||||
log.Printf("main : S3ImgUrl : %s - %s\n", p, rerr)
|
||||
log.Printf("main : S3ImgUrl : %s - %+v\n", p, rerr)
|
||||
}
|
||||
}
|
||||
return imgUrl
|
||||
|
@ -1,4 +1,4 @@
|
||||
{{define "title"}}Create Project{{end}}
|
||||
{{define "title"}}Create Checklist{{end}}
|
||||
{{define "style"}}
|
||||
|
||||
{{end}}
|
||||
@ -6,13 +6,13 @@
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/projects">Projects</a></li>
|
||||
<li class="breadcrumb-item"><a href="/checklists">Checklists</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Create</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">Create Project</h1>
|
||||
<h1 class="h3 mb-0 text-gray-800">Create Checklist</h1>
|
||||
</div>
|
||||
|
||||
<form class="user" method="post" novalidate>
|
||||
@ -23,10 +23,10 @@
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="inputName">Project Name</label>
|
||||
<label for="inputName">Checklist Name</label>
|
||||
<input type="text" id="inputName"
|
||||
class="form-control {{ ValidationFieldClass $.validationErrors "Name" }}"
|
||||
placeholder="Enter name for your project" name="Name"value="{{ .form.Name }}" required>
|
||||
placeholder="Enter name for your checklist" name="Name"value="{{ .form.Name }}" required>
|
||||
{{template "invalid-feedback" dict "fieldName" "Name" "validationDefaults" $.validationDefaults "validationErrors" $.validationErrors }}
|
||||
</div>
|
||||
</div>
|
||||
@ -37,7 +37,7 @@
|
||||
<div class="row mt-4">
|
||||
<div class="col">
|
||||
<input id="btnSubmit" type="submit" name="action" value="Save" class="btn btn-primary"/>
|
||||
<a href="/projects" class="ml-2 btn btn-secondary" >Cancel</a>
|
||||
<a href="/checklists" class="ml-2 btn btn-secondary" >Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,19 +1,19 @@
|
||||
{{define "title"}}Projects{{end}}
|
||||
{{define "title"}}Checklists{{end}}
|
||||
{{define "content"}}
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/projects">Projects</a></li>
|
||||
<li class="breadcrumb-item"><a href="/checklists">Checklists</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Index</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
|
||||
<h1 class="h3 mb-0 text-gray-800">Projects</h1>
|
||||
<h1 class="h3 mb-0 text-gray-800">Checklists</h1>
|
||||
{{ if HasRole $._Ctx "admin" }}
|
||||
<a href="{{ .urlProjectsCreate }}" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm">
|
||||
<i class="fas fa-folder-plus fa-sm text-white-50 mr-1"></i>Create Project</a>
|
||||
<a href="{{ .urlChecklistsCreate }}" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm">
|
||||
<i class="fas fa-folder-plus fa-sm text-white-50 mr-1"></i>Create Checklist</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{{define "title"}}Update Project - {{ .project.Name }}{{end}}
|
||||
{{define "title"}}Update Checklist - {{ .checklist.Name }}{{end}}
|
||||
{{define "style"}}
|
||||
|
||||
{{end}}
|
||||
@ -6,14 +6,14 @@
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/projects">Projects</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ .urlProjectsView }}">{{ .form.Name }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/checklists">Checklists</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ .urlChecklistsView }}">{{ .form.Name }}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Update</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">Update Project</h1>
|
||||
<h1 class="h3 mb-0 text-gray-800">Update Checklist</h1>
|
||||
</div>
|
||||
|
||||
<form class="user" method="post" novalidate>
|
||||
@ -22,7 +22,7 @@
|
||||
<div class="row mb-2">
|
||||
<div class="col-12">
|
||||
|
||||
<h4 class="card-title">Project Details</h4>
|
||||
<h4 class="card-title">Checklist Details</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
<label for="selectStatus">Status</label>
|
||||
<select class="form-control {{ ValidationFieldClass $.validationErrors "Status" }}"
|
||||
id="selectStatus" name="Status">
|
||||
{{ range $t := .project.Status.Options }}
|
||||
{{ range $t := .checklist.Status.Options }}
|
||||
<option value="{{ $t.Value }}" {{ if $t.Selected }}selected="selected"{{ end }}>{{ $t.Title }}</option>
|
||||
{{ end }}
|
||||
</select>
|
@ -1,4 +1,4 @@
|
||||
{{define "title"}}Project - {{ .project.Name }}{{end}}
|
||||
{{define "title"}}Checklist - {{ .checklist.Name }}{{end}}
|
||||
{{define "style"}}
|
||||
|
||||
{{end}}
|
||||
@ -6,29 +6,29 @@
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/projects">Projects</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ .urlProjectsView }}">{{ .project.Name }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="/checklists">Checklists</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ .urlChecklistsView }}">{{ .checklist.Name }}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">View</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">{{ .project.Name }}</h1>
|
||||
<!-- a href="{{ .urlProjectsUpdate }}" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i class="far fa-edit fa-sm text-white-50 mr-1"></i>Edit Details</a -->
|
||||
<h1 class="h3 mb-0 text-gray-800">{{ .checklist.Name }}</h1>
|
||||
<!-- a href="{{ .urlChecklistsUpdate }}" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i class="far fa-edit fa-sm text-white-50 mr-1"></i>Edit Details</a -->
|
||||
</div>
|
||||
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 font-weight-bold text-dark">Project Details</h6>
|
||||
<h6 class="m-0 font-weight-bold text-dark">Checklist Details</h6>
|
||||
<div class="dropdown no-arrow show">
|
||||
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink" x-placement="bottom-end" style="position: absolute; transform: translate3d(-156px, 19px, 0px); top: 0px; left: 0px; will-change: transform;">
|
||||
<div class="dropdown-header">Actions</div>
|
||||
<a class="dropdown-item" href="{{ .urlProjectsUpdate }}">Update Details</a>
|
||||
<a class="dropdown-item" href="{{ .urlChecklistsUpdate }}">Update Details</a>
|
||||
{{ if HasRole $._Ctx "admin" }}
|
||||
<form method="post"><input type="hidden" name="action" value="archive" /><input type="submit" value="Archive Project" class="dropdown-item"></form>
|
||||
<form method="post"><input type="hidden" name="action" value="archive" /><input type="submit" value="Archive Checklist" class="dropdown-item"></form>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
@ -38,16 +38,16 @@
|
||||
<div class="col-md-6">
|
||||
<p>
|
||||
<small>Name</small><br/>
|
||||
<b>{{ .project.Name }}</b>
|
||||
<b>{{ .checklist.Name }}</b>
|
||||
</p>
|
||||
<p>
|
||||
<small>Status</small><br/>
|
||||
{{ if .project }}
|
||||
{{ if .checklist }}
|
||||
<b>
|
||||
{{ if eq .project.Status.Value "active" }}
|
||||
<span class="text-green"><i class="fas fa-circle mr-1"></i>{{ .project.Status.Title }}</span>
|
||||
{{ if eq .checklist.Status.Value "active" }}
|
||||
<span class="text-green"><i class="fas fa-circle mr-1"></i>{{ .checklist.Status.Title }}</span>
|
||||
{{else}}
|
||||
<span class="text-orange"><i class="fas fa-circle-notch mr-1"></i>{{.project.Status.Title }}</span>
|
||||
<span class="text-orange"><i class="fas fa-circle-notch mr-1"></i>{{.checklist.Status.Title }}</span>
|
||||
{{end}}
|
||||
</b>
|
||||
{{ end }}
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="col-md-6">
|
||||
<p>
|
||||
<small>ID</small><br/>
|
||||
<b>{{ .project.ID }}</b>
|
||||
<b>{{ .checklist.ID }}</b>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
@ -10,7 +10,7 @@
|
||||
|
||||
<p>AWS credentials must be set and then the following configs be set as well.</p>
|
||||
<pre>
|
||||
export WEB_APP_SERVICE_S3_BUCKET_PUBLIC=example-bucket-public
|
||||
export WEB_APP_AWS_S3_BUCKET_PUBLIC=example-bucket-public
|
||||
export WEB_APP_SERVICE_STATICFILES_IMG_RESIZE_ENABLED=1
|
||||
</pre>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="sidebar-brand-icon rotate-n-15">
|
||||
<i class="fas fa-dragon"></i>
|
||||
</div>
|
||||
<div class="sidebar-brand-text mx-3">Example Project</div>
|
||||
<div class="sidebar-brand-text mx-3">Example Checklist</div>
|
||||
</a>
|
||||
|
||||
{{ if HasAuth $._Ctx }}
|
||||
@ -32,13 +32,13 @@
|
||||
|
||||
<!-- Nav Item - Pages Collapse Menu -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#navSectionProjects" aria-expanded="true" aria-controls="navSectionProjects">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#navSectionChecklists" aria-expanded="true" aria-controls="navSectionChecklists">
|
||||
<i class="fas fa-fw fa-layer-group"></i>
|
||||
<span>Projects</span>
|
||||
<span>Checklists</span>
|
||||
</a>
|
||||
<div id="navSectionProjects" class="collapse" data-parent="#accordionSidebar">
|
||||
<div id="navSectionChecklists" class="collapse" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<a class="collapse-item" href="/projects">Manage Projects</a>
|
||||
<a class="collapse-item" href="/checklists">Manage Checklists</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
Reference in New Issue
Block a user