M accounts/processors.go => accounts/processors.go +88 -0
@@ 2,15 2,103 @@ package accounts
import (
"context"
+ "fmt"
+ "links"
"links/models"
"strings"
+ "git.sr.ht/~emersion/gqlclient"
work "git.sr.ht/~sircmpwn/dowork"
+ sq "github.com/Masterminds/squirrel"
sendy "hg.code.netlandish.com/~netlandish/sendygo"
"netlandish.com/x/gobwebs"
+ "netlandish.com/x/gobwebs/crypto"
+ "netlandish.com/x/gobwebs/database"
"netlandish.com/x/gobwebs/server"
+ "netlandish.com/x/gobwebs/timezone"
)
+func addWelcomeLink(ctx context.Context, user gobwebs.User) error {
+ opts := &database.FilterOptions{
+ Filter: sq.And{
+ sq.Eq{"o.owner_id": user.GetID()},
+ sq.Eq{"o.org_type": models.OrgTypeUser},
+ },
+ Limit: 1,
+ }
+ orgs, err := models.GetOrganizations(ctx, opts)
+ if err != nil {
+ return err
+ }
+ if len(orgs) == 0 {
+ // Should never be reached
+ return fmt.Errorf("User has no organizations")
+ }
+
+ type GraphQLResponse struct {
+ Link models.OrgLink `json:"addLink"`
+ }
+
+ var result GraphQLResponse
+ q := `mutation AddLink($title: String!, $url: String!, $description: String,
+ $visibility: LinkVisibility!, $unread: Boolean!, $starred: Boolean!,
+ $archive: Boolean! $slug: String!, $tags: String, $override: Boolean!) {
+ addLink(input: {
+ title: $title,
+ url: $url,
+ description: $description,
+ visibility: $visibility,
+ unread: $unread,
+ starred: $starred,
+ archive: $archive,
+ orgSlug: $slug,
+ tags: $tags,
+ override: $override}) {
+ id
+ }
+ }`
+ op := gqlclient.NewOperation(q)
+ op.Var("title", "Welcome to LinkTaco! Getting Started Guide")
+ op.Var("url", "https://man.code.netlandish.com/~netlandish/links/getting-started.md")
+ op.Var("description", "Welcome! This is your getting started guide for LinkTaco. Please click the link to read it and start saving your links right away!")
+ op.Var("visibility", models.OrgLinkVisibilityPrivate)
+ op.Var("tags", "help, linktaco, documentation, getting started")
+ op.Var("unread", true)
+ op.Var("starred", true)
+ op.Var("archive", false)
+ op.Var("slug", orgs[0].Slug)
+ op.Var("override", true)
+
+ return links.Execute(ctx, op, &result)
+}
+
+func AddWelcomeLinkTask(user gobwebs.User, gctx *server.Context) *work.Task {
+ return work.NewTask(func(ctx context.Context) error {
+ // If ever there was a use case for context merge functionality
+ // https://github.com/golang/go/issues/36503
+ ctx = crypto.Context(ctx, crypto.ForContext(gctx.Request().Context()))
+ ctx = server.ServerContext(ctx, gctx.Server)
+ ctx = database.Context(ctx, gctx.Server.DB)
+ ctx = timezone.Context(ctx, "UTC")
+ return addWelcomeLink(ctx, user)
+ }).Retries(3).Before(func(ctx context.Context, task *work.Task) {
+ gobwebs.TaskIDWork(task)
+ gctx.Server.Logger().Printf(
+ "Running task AddWelcomeLinkTask %s for the %d attempt.",
+ task.Metadata["id"], task.Attempts())
+ }).After(func(ctx context.Context, task *work.Task) {
+ if task.Result() == nil {
+ gctx.Server.Logger().Printf(
+ "Completed task AddWelcomeLinkTask %s after %d attempts.",
+ task.Metadata["id"], task.Attempts())
+ } else {
+ gctx.Server.Logger().Printf(
+ "Failed task AddWelcomeLinkTask %s after %d attempts: %v",
+ task.Metadata["id"], task.Attempts(), task.Result())
+ }
+ })
+}
+
func sendSendySubscribe(ctx context.Context, user gobwebs.User, gctx *server.Context) error {
u := user.(*models.User)
file := gctx.Server.Config.File
M accounts/userfetch.go => accounts/userfetch.go +11 -63
@@ 7,11 7,8 @@ import (
"links/internal/localizer"
"links/models"
- "git.sr.ht/~emersion/gqlclient"
- sq "github.com/Masterminds/squirrel"
"github.com/labstack/echo/v4"
"netlandish.com/x/gobwebs"
- "netlandish.com/x/gobwebs/database"
"netlandish.com/x/gobwebs/messages"
"netlandish.com/x/gobwebs/server"
)
@@ 165,15 162,23 @@ func (u *UserFetch) ProcessSuccessfulEmailUpdate(c echo.Context) error {
return nil
}
-// ProcessSuccessfulEmailConfirmation handle tasks after user is logged in
+// ProcessSuccessfulEmailConfirmation handle tasks after user confirms their email address
func (u *UserFetch) ProcessSuccessfulEmailConfirmation(c echo.Context) error {
lt := localizer.GetSessionLocalizer(c)
// Sendy users list. Log on error
user := c.Get("user").(*models.User)
gctx := c.(*server.Context)
- err := gctx.Server.QueueTask("general", SendySubscribeTask(user, gctx))
+
+ // Add welcome link
+ err := gctx.Server.QueueTask("general", AddWelcomeLinkTask(user, gctx))
if err != nil {
- gctx.Server.Logger().Printf("Error queueing sendSendySubscribeTask: %v", err)
+ gctx.Server.Logger().Printf("Error queueing AddWelcomeLinkTask: %v", err)
+ }
+
+ // Sendy
+ err = gctx.Server.QueueTask("general", SendySubscribeTask(user, gctx))
+ if err != nil {
+ gctx.Server.Logger().Printf("Error queueing SendySubscribeTask: %v", err)
}
messages.Success(c, lt.Translate("You've successfully confirmed your email address."))
return nil
@@ 230,63 235,6 @@ func (u *UserFetch) ProcessSuccessfulLogin(c echo.Context, user gobwebs.User) er
lt := localizer.GetSessionLocalizer(c)
messages.Success(c, lt.Translate("Successful login."))
- if !lUser.LastLogin.Valid {
- // User's first time logging in. Let's set them a welcome link to the getting started doc
- opts := &database.FilterOptions{
- Filter: sq.And{
- sq.Eq{"o.owner_id": user.GetID()},
- sq.Eq{"o.org_type": models.OrgTypeUser},
- },
- Limit: 1,
- }
- orgs, err := models.GetOrganizations(c.Request().Context(), opts)
- if err != nil {
- return err
- }
- if len(orgs) == 0 {
- // Should never be reached
- return fmt.Errorf("User has no organizations")
- }
-
- type GraphQLResponse struct {
- Link models.OrgLink `json:"addLink"`
- }
-
- var result GraphQLResponse
- q := `mutation AddLink($title: String!, $url: String!, $description: String,
- $visibility: LinkVisibility!, $unread: Boolean!, $starred: Boolean!,
- $archive: Boolean! $slug: String!, $tags: String, $override: Boolean!) {
- addLink(input: {
- title: $title,
- url: $url,
- description: $description,
- visibility: $visibility,
- unread: $unread,
- starred: $starred,
- archive: $archive,
- orgSlug: $slug,
- tags: $tags,
- override: $override}) {
- id
- }
- }`
- op := gqlclient.NewOperation(q)
- op.Var("title", "Welcome to LinkTaco! Getting Started Guide")
- op.Var("url", "https://man.code.netlandish.com/~netlandish/links/getting-started.md")
- op.Var("description", "Welcome! This is your getting started guide for LinkTaco. Please click the link to read it and start saving your links right away!")
- op.Var("visibility", models.OrgLinkVisibilityPrivate)
- op.Var("tags", "help, linktaco, documentation, getting started")
- op.Var("unread", true)
- op.Var("starred", true)
- op.Var("archive", false)
- op.Var("slug", orgs[0].Slug)
- op.Var("override", true)
-
- err = links.Execute(c.Request().Context(), op, &result)
- if err != nil {
- return err
- }
- }
return nil
}