| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- package user
- import (
- "errors"
- "net/http"
- "github.com/porter-dev/porter/internal/analytics"
- "github.com/porter-dev/porter/internal/telemetry"
- "gorm.io/gorm"
- "github.com/porter-dev/porter/api/server/shared/apierrors"
- "github.com/porter-dev/porter/internal/models"
- "github.com/porter-dev/porter/api/server/handlers"
- "github.com/porter-dev/porter/api/server/shared"
- "github.com/porter-dev/porter/api/server/shared/config"
- )
- // OryUserCreateHandler is the handler for user creation triggered by an ory action
- type OryUserCreateHandler struct {
- handlers.PorterHandlerReadWriter
- }
- // NewOryUserCreateHandler generates a new OryUserCreateHandler
- func NewOryUserCreateHandler(
- config *config.Config,
- decoderValidator shared.RequestDecoderValidator,
- writer shared.ResultWriter,
- ) *OryUserCreateHandler {
- return &OryUserCreateHandler{
- PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
- }
- }
- // CreateOryUserRequest is the expected request body for user creation triggered by an ory action
- type CreateOryUserRequest struct {
- OryId string `json:"ory_id"`
- Email string `json:"email"`
- Referral string `json:"referral"`
- }
- // ServeHTTP handles the user creation triggered by an ory action
- func (u *OryUserCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- ctx, span := telemetry.NewSpan(r.Context(), "serve-create-ory-user")
- defer span.End()
- // this endpoint is not authenticated through middleware; instead, we check
- // for the presence of an ory action cookie that matches env
- oryActionCookie, err := r.Cookie("ory_action")
- if err != nil {
- err = telemetry.Error(ctx, span, err, "invalid ory action cookie")
- u.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusForbidden))
- return
- }
- if oryActionCookie.Value != u.Config().OryActionKey {
- err = telemetry.Error(ctx, span, nil, "cookie does not match")
- u.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusForbidden))
- return
- }
- request := &CreateOryUserRequest{}
- ok := u.DecodeAndValidate(w, r, request)
- if !ok {
- err = telemetry.Error(ctx, span, nil, "invalid request")
- u.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
- return
- }
- telemetry.WithAttributes(span,
- telemetry.AttributeKV{Key: "email", Value: request.Email},
- telemetry.AttributeKV{Key: "ory-id", Value: request.OryId},
- telemetry.AttributeKV{Key: "referral", Value: request.Referral},
- )
- if request.Email == "" {
- err = telemetry.Error(ctx, span, nil, "email is required")
- u.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
- return
- }
- if request.OryId == "" {
- err = telemetry.Error(ctx, span, nil, "ory_id is required")
- u.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
- return
- }
- user := &models.User{
- Model: gorm.Model{},
- Email: request.Email,
- EmailVerified: false,
- AuthProvider: models.AuthProvider_Ory,
- ExternalId: request.OryId,
- }
- existingUser, err := u.Repo().User().ReadUserByEmail(user.Email)
- if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
- err = telemetry.Error(ctx, span, err, "error reading user by email")
- u.HandleAPIError(w, r, apierrors.NewErrInternal(err))
- return
- }
- if existingUser == nil || existingUser.ID == 0 {
- user, err = u.Repo().User().CreateUser(user)
- if err != nil {
- err = telemetry.Error(ctx, span, err, "error creating user")
- u.HandleAPIError(w, r, apierrors.NewErrInternal(err))
- return
- }
- _ = u.Config().AnalyticsClient.Identify(analytics.CreateSegmentIdentifyUser(user))
- _ = u.Config().AnalyticsClient.Track(analytics.UserCreateTrack(&analytics.UserCreateTrackOpts{
- UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
- Email: user.Email,
- FirstName: user.FirstName,
- LastName: user.LastName,
- CompanyName: user.CompanyName,
- ReferralMethod: request.Referral,
- }))
- } else {
- existingUser.AuthProvider = models.AuthProvider_Ory
- existingUser.ExternalId = request.OryId
- _, err = u.Repo().User().UpdateUser(existingUser)
- if err != nil {
- err = telemetry.Error(ctx, span, err, "error updating user")
- u.HandleAPIError(w, r, apierrors.NewErrInternal(err))
- return
- }
- }
- }
|