Files
probo/pkg/server/api/console/v1/cookie_banner_resolvers.go
Émile Ré 4147239fbc Add consent records tab to cookie banner config
Exposes the cookie consent record audit trail through a new
"Consent Records" tab on the cookie banner configuration page.
The full stack includes: extended coredata filter (visitor ID,
banner version), GraphQL schema/types/resolvers, and a React
page with SortableTable (size 50) and three compliance filters
(action, visitor ID, banner version).

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-28 15:28:17 +04:00

871 lines
31 KiB
Go

package console_v1
// This file will be automatically regenerated based on the schema, any resolver
// implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.87
import (
"context"
"encoding/json"
"errors"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/cookiebanner"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
"go.probo.inc/probo/pkg/server/api/console/v1/types"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/validator"
)
// CookieCategory is the resolver for the cookieCategory field.
func (r *cookieResolver) CookieCategory(ctx context.Context, obj *types.Cookie) (*types.CookieCategory, error) {
return obj.CookieCategory, nil
}
// Permission is the resolver for the permission field.
func (r *cookieResolver) Permission(ctx context.Context, obj *types.Cookie, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
}
// Organization is the resolver for the organization field.
func (r *cookieBannerResolver) Organization(ctx context.Context, obj *types.CookieBanner) (*types.Organization, error) {
return obj.Organization, nil
}
// Categories is the resolver for the categories field.
func (r *cookieBannerResolver) Categories(ctx context.Context, obj *types.CookieBanner, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.CookieCategoryOrderBy) (*types.CookieCategoryConnection, error) {
if err := r.authorize(ctx, obj.ID, probo.ActionCookieCategoryList); err != nil {
return nil, err
}
pageOrderBy := page.OrderBy[coredata.CookieCategoryOrderField]{
Field: coredata.CookieCategoryOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.CookieCategoryOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
scope := coredata.NewScopeFromObjectID(obj.ID)
categories, err := r.cookieBanner.ListCookieCategoriesForBanner(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list cookie categories", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
p := page.NewPage(categories, cursor)
return types.NewCookieCategoryConnection(p, r, obj.ID), nil
}
// Translations is the resolver for the translations field.
func (r *cookieBannerResolver) Translations(ctx context.Context, obj *types.CookieBanner) ([]*types.CookieBannerTranslation, error) {
scope := coredata.NewScopeFromObjectID(obj.ID)
translations, err := r.cookieBanner.ListCookieBannerTranslations(ctx, scope, obj.ID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list cookie banner translations", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
result := make([]*types.CookieBannerTranslation, len(translations))
for i, t := range translations {
result[i] = types.NewCookieBannerTranslation(t)
}
return result, nil
}
// LatestVersion is the resolver for the latestVersion field.
func (r *cookieBannerResolver) LatestVersion(ctx context.Context, obj *types.CookieBanner) (*types.CookieBannerVersion, error) {
if err := r.authorize(ctx, obj.ID, probo.ActionCookieBannerVersionList); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(obj.ID)
cursor := &page.Cursor[coredata.CookieBannerVersionOrderField]{
Size: 1,
Position: page.Head,
OrderBy: page.OrderBy[coredata.CookieBannerVersionOrderField]{
Field: coredata.CookieBannerVersionOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
},
}
versions, err := r.cookieBanner.ListCookieBannerVersionsForBanner(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load latest cookie banner version", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if len(versions) == 0 {
return nil, nil
}
v := versions[0]
return &types.CookieBannerVersion{
ID: v.ID,
Version: v.Version,
State: string(v.State),
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
}, nil
}
// ConsentRecords is the resolver for the consentRecords field.
func (r *cookieBannerResolver) ConsentRecords(ctx context.Context, obj *types.CookieBanner, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.CookieConsentRecordOrderBy, filter *types.CookieConsentRecordFilter) (*types.CookieConsentRecordConnection, error) {
if err := r.authorize(ctx, obj.ID, probo.ActionCookieConsentRecordList); err != nil {
return nil, err
}
pageOrderBy := page.OrderBy[coredata.CookieConsentRecordOrderField]{
Field: coredata.CookieConsentRecordOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.CookieConsentRecordOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
scope := coredata.NewScopeFromObjectID(obj.ID)
var (
action *coredata.CookieConsentAction
visitorID *string
cookieBannerVersionID *gid.GID
)
if filter != nil {
action = filter.Action
visitorID = filter.VisitorID
cookieBannerVersionID = filter.CookieBannerVersionID
}
coredataFilter := coredata.NewCookieConsentRecordFilter(action, visitorID, cookieBannerVersionID)
records, err := r.cookieBanner.ListCookieConsentRecordsForBanner(ctx, scope, obj.ID, cursor, coredataFilter)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list consent records", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
p := page.NewPage(records, cursor)
return types.NewCookieConsentRecordConnection(p, r, obj.ID, coredataFilter), nil
}
// Permission is the resolver for the permission field.
func (r *cookieBannerResolver) Permission(ctx context.Context, obj *types.CookieBanner, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
}
// TotalCount is the resolver for the totalCount field.
func (r *cookieBannerConnectionResolver) TotalCount(ctx context.Context, obj *types.CookieBannerConnection) (int, error) {
if err := r.authorize(ctx, obj.ParentID, probo.ActionCookieBannerList); err != nil {
return 0, err
}
scope := coredata.NewScopeFromObjectID(obj.ParentID)
count, err := r.cookieBanner.CountCookieBannersForOrganization(ctx, scope, obj.ParentID, coredata.NewCookieBannerFilter(nil))
if err != nil {
r.logger.ErrorCtx(ctx, "cannot count cookie banners", log.Error(err))
return 0, gqlutils.Internal(ctx)
}
return count, nil
}
// CookieBanner is the resolver for the cookieBanner field.
func (r *cookieCategoryResolver) CookieBanner(ctx context.Context, obj *types.CookieCategory) (*types.CookieBanner, error) {
return obj.CookieBanner, nil
}
// Cookies is the resolver for the cookies field.
func (r *cookieCategoryResolver) Cookies(ctx context.Context, obj *types.CookieCategory, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.CookieOrderBy) (*types.CookieConnection, error) {
if err := r.authorize(ctx, obj.ID, probo.ActionCookieList); err != nil {
return nil, err
}
pageOrderBy := page.OrderBy[coredata.CookieOrderField]{
Field: coredata.CookieOrderFieldCreatedAt,
Direction: page.OrderDirectionAsc,
}
if orderBy != nil {
pageOrderBy = page.OrderBy[coredata.CookieOrderField]{
Field: orderBy.Field,
Direction: orderBy.Direction,
}
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
scope := coredata.NewScopeFromObjectID(obj.ID)
cookies, err := r.cookieBanner.ListCookiesForCategory(ctx, scope, obj.ID, cursor)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list cookies", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
p := page.NewPage(cookies, cursor)
return types.NewCookieConnection(p, r, obj.ID), nil
}
// Permission is the resolver for the permission field.
func (r *cookieCategoryResolver) Permission(ctx context.Context, obj *types.CookieCategory, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
}
// TotalCount is the resolver for the totalCount field.
func (r *cookieCategoryConnectionResolver) TotalCount(ctx context.Context, obj *types.CookieCategoryConnection) (int, error) {
if err := r.authorize(ctx, obj.ParentID, probo.ActionCookieCategoryList); err != nil {
return 0, err
}
scope := coredata.NewScopeFromObjectID(obj.ParentID)
count, err := r.cookieBanner.CountCookieCategoriesForBanner(ctx, scope, obj.ParentID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot count cookie categories", log.Error(err))
return 0, gqlutils.Internal(ctx)
}
return count, nil
}
// TotalCount is the resolver for the totalCount field.
func (r *cookieConnectionResolver) TotalCount(ctx context.Context, obj *types.CookieConnection) (int, error) {
if err := r.authorize(ctx, obj.ParentID, probo.ActionCookieList); err != nil {
return 0, err
}
scope := coredata.NewScopeFromObjectID(obj.ParentID)
count, err := r.cookieBanner.CountCookiesForCategory(ctx, scope, obj.ParentID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot count cookies", log.Error(err))
return 0, gqlutils.Internal(ctx)
}
return count, nil
}
// CreateCookieBanner is the resolver for the createCookieBanner field.
func (r *mutationResolver) CreateCookieBanner(ctx context.Context, input types.CreateCookieBannerInput) (*types.CreateCookieBannerPayload, error) {
if err := r.authorize(ctx, input.OrganizationID, probo.ActionCookieBannerCreate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
banner, err := r.cookieBanner.CreateCookieBanner(
ctx,
scope,
cookiebanner.CreateCookieBannerRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Origin: input.Origin,
PrivacyPolicyURL: input.PrivacyPolicyURL,
CookiePolicyURL: input.CookiePolicyURL,
ConsentExpiryDays: input.ConsentExpiryDays,
ConsentMode: input.ConsentMode,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrOriginAlreadyInUse) {
return nil, gqlutils.Conflict(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot create cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.CreateCookieBannerPayload{
CookieBannerEdge: types.NewCookieBannerEdge(banner, coredata.CookieBannerOrderFieldCreatedAt),
}, nil
}
// UpdateCookieBanner is the resolver for the updateCookieBanner field.
func (r *mutationResolver) UpdateCookieBanner(ctx context.Context, input types.UpdateCookieBannerInput) (*types.UpdateCookieBannerPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerUpdate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
banner, err := r.cookieBanner.UpdateCookieBanner(
ctx,
scope,
cookiebanner.UpdateCookieBannerRequest{
CookieBannerID: input.CookieBannerID,
Name: input.Name,
PrivacyPolicyURL: input.PrivacyPolicyURL,
CookiePolicyURL: input.CookiePolicyURL,
ConsentExpiryDays: input.ConsentExpiryDays,
ConsentMode: input.ConsentMode,
DefaultLanguage: input.DefaultLanguage,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrBannerNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot update cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.UpdateCookieBannerPayload{
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// DeleteCookieBanner is the resolver for the deleteCookieBanner field.
func (r *mutationResolver) DeleteCookieBanner(ctx context.Context, input types.DeleteCookieBannerInput) (*types.DeleteCookieBannerPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerDelete); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
err := r.cookieBanner.DeleteCookieBanner(ctx, scope, input.CookieBannerID)
if err != nil {
if errors.Is(err, cookiebanner.ErrBannerNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot delete cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeleteCookieBannerPayload{
DeletedCookieBannerID: input.CookieBannerID,
}, nil
}
// ActivateCookieBanner is the resolver for the activateCookieBanner field.
func (r *mutationResolver) ActivateCookieBanner(ctx context.Context, input types.ActivateCookieBannerInput) (*types.ActivateCookieBannerPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerActivate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
banner, err := r.cookieBanner.ActivateCookieBanner(ctx, scope, input.CookieBannerID)
if err != nil {
if errors.Is(err, cookiebanner.ErrBannerNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if errors.Is(err, cookiebanner.ErrBannerAlreadyActive) {
return nil, gqlutils.Conflict(ctx, err)
}
if errors.Is(err, cookiebanner.ErrOriginAlreadyInUse) {
return nil, gqlutils.Conflict(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot activate cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.ActivateCookieBannerPayload{
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// DeactivateCookieBanner is the resolver for the deactivateCookieBanner field.
func (r *mutationResolver) DeactivateCookieBanner(ctx context.Context, input types.DeactivateCookieBannerInput) (*types.DeactivateCookieBannerPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerDeactivate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
banner, err := r.cookieBanner.DeactivateCookieBanner(ctx, scope, input.CookieBannerID)
if err != nil {
if errors.Is(err, cookiebanner.ErrBannerNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if errors.Is(err, cookiebanner.ErrBannerAlreadyInactive) {
return nil, gqlutils.Conflict(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot deactivate cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeactivateCookieBannerPayload{
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// PublishCookieBannerVersion is the resolver for the publishCookieBannerVersion field.
func (r *mutationResolver) PublishCookieBannerVersion(ctx context.Context, input types.PublishCookieBannerVersionInput) (*types.PublishCookieBannerVersionPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerVersionPublish); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
version, err := r.cookieBanner.PublishCookieBannerVersion(ctx, scope, input.CookieBannerID)
if err != nil {
if errors.Is(err, cookiebanner.ErrNoDraftVersion) {
return nil, gqlutils.Conflict(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot publish cookie banner version", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
banner, err := r.cookieBanner.GetCookieBanner(ctx, scope, input.CookieBannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.PublishCookieBannerVersionPayload{
CookieBannerVersion: &types.CookieBannerVersion{
ID: version.ID,
Version: version.Version,
State: string(version.State),
CreatedAt: version.CreatedAt,
UpdatedAt: version.UpdatedAt,
},
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// CreateCookieCategory is the resolver for the createCookieCategory field.
func (r *mutationResolver) CreateCookieCategory(ctx context.Context, input types.CreateCookieCategoryInput) (*types.CreateCookieCategoryPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieCategoryCreate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
category, err := r.cookieBanner.CreateCookieCategory(
ctx,
scope,
cookiebanner.CreateCookieCategoryRequest{
CookieBannerID: input.CookieBannerID,
Name: input.Name,
Slug: input.Slug,
Description: input.Description,
Rank: input.Rank,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrBannerNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if errors.Is(err, cookiebanner.ErrCategorySlugAlreadyExists) {
return nil, gqlutils.Conflict(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot create cookie category", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
banner, err := r.cookieBanner.GetCookieBanner(ctx, scope, input.CookieBannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.CreateCookieCategoryPayload{
CookieCategoryEdge: types.NewCookieCategoryEdge(category, coredata.CookieCategoryOrderFieldRank),
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// UpdateCookieCategory is the resolver for the updateCookieCategory field.
func (r *mutationResolver) UpdateCookieCategory(ctx context.Context, input types.UpdateCookieCategoryInput) (*types.UpdateCookieCategoryPayload, error) {
if err := r.authorize(ctx, input.CookieCategoryID, probo.ActionCookieCategoryUpdate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieCategoryID)
var gcmConsentTypes *[]string
if input.GcmConsentTypes != nil {
gcmConsentTypes = &input.GcmConsentTypes
}
category, err := r.cookieBanner.UpdateCookieCategory(
ctx,
scope,
cookiebanner.UpdateCookieCategoryRequest{
CookieCategoryID: input.CookieCategoryID,
Name: input.Name,
Slug: input.Slug,
Description: input.Description,
GCMConsentTypes: gcmConsentTypes,
PostHogConsent: input.PosthogConsent,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrCategoryNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if errors.Is(err, cookiebanner.ErrCategorySlugAlreadyExists) {
return nil, gqlutils.Conflict(ctx, err)
}
if errors.Is(err, cookiebanner.ErrPostHogConsentKindInvalid) {
return nil, gqlutils.Invalid(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot update cookie category", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerScope := coredata.NewScopeFromObjectID(category.CookieBannerID)
banner, err := r.cookieBanner.GetCookieBanner(ctx, bannerScope, category.CookieBannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.UpdateCookieCategoryPayload{
CookieCategory: types.NewCookieCategory(category),
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// DeleteCookieCategory is the resolver for the deleteCookieCategory field.
func (r *mutationResolver) DeleteCookieCategory(ctx context.Context, input types.DeleteCookieCategoryInput) (*types.DeleteCookieCategoryPayload, error) {
if err := r.authorize(ctx, input.CookieCategoryID, probo.ActionCookieCategoryDelete); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieCategoryID)
category, err := r.cookieBanner.GetCookieCategory(ctx, scope, input.CookieCategoryID)
if err != nil {
if errors.Is(err, cookiebanner.ErrCategoryNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot get cookie category", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerID := category.CookieBannerID
err = r.cookieBanner.DeleteCookieCategory(ctx, scope, input.CookieCategoryID)
if err != nil {
if errors.Is(err, cookiebanner.ErrCategoryNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if errors.Is(err, cookiebanner.ErrCannotDeleteSystemCategory) {
return nil, gqlutils.Conflict(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot delete cookie category", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerScope := coredata.NewScopeFromObjectID(bannerID)
banner, err := r.cookieBanner.GetCookieBanner(ctx, bannerScope, bannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeleteCookieCategoryPayload{
DeletedCookieCategoryID: input.CookieCategoryID,
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// ReorderCookieCategory is the resolver for the reorderCookieCategory field.
func (r *mutationResolver) ReorderCookieCategory(ctx context.Context, input types.ReorderCookieCategoryInput) (*types.ReorderCookieCategoryPayload, error) {
if err := r.authorize(ctx, input.CookieCategoryID, probo.ActionCookieCategoryUpdate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieCategoryID)
banner, err := r.cookieBanner.ReorderCookieCategory(
ctx,
scope,
cookiebanner.ReorderCookieCategoryRequest{
CookieCategoryID: input.CookieCategoryID,
Rank: input.Rank,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrCategoryNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot reorder cookie category", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.ReorderCookieCategoryPayload{
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// MoveCookieToCategory is the resolver for the moveCookieToCategory field.
func (r *mutationResolver) MoveCookieToCategory(ctx context.Context, input types.MoveCookieToCategoryInput) (*types.MoveCookieToCategoryPayload, error) {
if err := r.authorize(ctx, input.CookieID, probo.ActionCookieUpdate); err != nil {
return nil, err
}
if err := r.authorize(ctx, input.TargetCookieCategoryID, probo.ActionCookieCategoryUpdate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieID)
result, err := r.cookieBanner.MoveCookieToCategory(
ctx,
scope,
cookiebanner.MoveCookieToCategoryRequest{
CookieID: input.CookieID,
TargetCookieCategoryID: input.TargetCookieCategoryID,
},
)
if err != nil {
switch {
case errors.Is(err, cookiebanner.ErrCategoryNotFound):
return nil, gqlutils.NotFound(ctx, err)
case errors.Is(err, cookiebanner.ErrCookieNotFound):
return nil, gqlutils.NotFound(ctx, err)
case errors.Is(err, cookiebanner.ErrCategoriesBannerMismatch):
return nil, gqlutils.NotFoundf(ctx, "cookie or target category not found")
default:
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot move cookie to category", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
return &types.MoveCookieToCategoryPayload{
Cookie: types.NewCookie(result.Cookie),
CookieBanner: types.NewCookieBanner(result.Banner),
}, nil
}
// CreateCookie is the resolver for the createCookie field.
func (r *mutationResolver) CreateCookie(ctx context.Context, input types.CreateCookieInput) (*types.CreateCookiePayload, error) {
if err := r.authorize(ctx, input.CookieCategoryID, probo.ActionCookieCreate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieCategoryID)
cookie, err := r.cookieBanner.CreateCookie(
ctx,
scope,
cookiebanner.CreateCookieRequest{
CookieCategoryID: input.CookieCategoryID,
Name: input.Name,
Duration: input.Duration,
Description: input.Description,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrCookieNameAlreadyExists) {
return nil, gqlutils.Conflict(ctx, err)
}
if errors.Is(err, cookiebanner.ErrCategoryNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot create cookie", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerScope := coredata.NewScopeFromObjectID(cookie.CookieBannerID)
banner, err := r.cookieBanner.GetCookieBanner(ctx, bannerScope, cookie.CookieBannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.CreateCookiePayload{
CookieEdge: types.NewCookieEdge(cookie, coredata.CookieOrderFieldCreatedAt),
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// UpdateCookie is the resolver for the updateCookie field.
func (r *mutationResolver) UpdateCookie(ctx context.Context, input types.UpdateCookieInput) (*types.UpdateCookiePayload, error) {
if err := r.authorize(ctx, input.CookieID, probo.ActionCookieUpdate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieID)
cookie, err := r.cookieBanner.UpdateCookie(
ctx,
scope,
cookiebanner.UpdateCookieRequest{
CookieID: input.CookieID,
Name: input.Name,
Duration: input.Duration,
Description: input.Description,
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrCookieNameAlreadyExists) {
return nil, gqlutils.Conflict(ctx, err)
}
if errors.Is(err, cookiebanner.ErrCookieNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot update cookie", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerScope := coredata.NewScopeFromObjectID(cookie.CookieBannerID)
banner, err := r.cookieBanner.GetCookieBanner(ctx, bannerScope, cookie.CookieBannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.UpdateCookiePayload{
Cookie: types.NewCookie(cookie),
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// DeleteCookie is the resolver for the deleteCookie field.
func (r *mutationResolver) DeleteCookie(ctx context.Context, input types.DeleteCookieInput) (*types.DeleteCookiePayload, error) {
if err := r.authorize(ctx, input.CookieID, probo.ActionCookieDelete); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieID)
cookie, err := r.cookieBanner.GetCookie(ctx, scope, input.CookieID)
if err != nil {
if errors.Is(err, cookiebanner.ErrCookieNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot get cookie", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerID := cookie.CookieBannerID
err = r.cookieBanner.DeleteCookie(ctx, scope, input.CookieID)
if err != nil {
if errors.Is(err, cookiebanner.ErrCookieNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot delete cookie", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
bannerScope := coredata.NewScopeFromObjectID(bannerID)
banner, err := r.cookieBanner.GetCookieBanner(ctx, bannerScope, bannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeleteCookiePayload{
DeletedCookieID: input.CookieID,
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// UpsertCookieBannerTranslation is the resolver for the upsertCookieBannerTranslation field.
func (r *mutationResolver) UpsertCookieBannerTranslation(ctx context.Context, input types.UpsertCookieBannerTranslationInput) (*types.UpsertCookieBannerTranslationPayload, error) {
if err := r.authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerUpdate); err != nil {
return nil, err
}
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
translation, err := r.cookieBanner.UpsertCookieBannerTranslation(
ctx,
scope,
cookiebanner.UpsertCookieBannerTranslationRequest{
CookieBannerID: input.CookieBannerID,
Language: input.Language,
Translations: json.RawMessage(input.Translations),
},
)
if err != nil {
if errors.Is(err, cookiebanner.ErrBannerNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot upsert cookie banner translation", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
banner, err := r.cookieBanner.GetCookieBanner(ctx, scope, input.CookieBannerID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load cookie banner", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.UpsertCookieBannerTranslationPayload{
CookieBannerTranslation: types.NewCookieBannerTranslation(translation),
CookieBanner: types.NewCookieBanner(banner),
}, nil
}
// Cookie returns schema.CookieResolver implementation.
func (r *Resolver) Cookie() schema.CookieResolver { return &cookieResolver{r} }
// CookieBanner returns schema.CookieBannerResolver implementation.
func (r *Resolver) CookieBanner() schema.CookieBannerResolver { return &cookieBannerResolver{r} }
// CookieBannerConnection returns schema.CookieBannerConnectionResolver implementation.
func (r *Resolver) CookieBannerConnection() schema.CookieBannerConnectionResolver {
return &cookieBannerConnectionResolver{r}
}
// CookieCategory returns schema.CookieCategoryResolver implementation.
func (r *Resolver) CookieCategory() schema.CookieCategoryResolver { return &cookieCategoryResolver{r} }
// CookieCategoryConnection returns schema.CookieCategoryConnectionResolver implementation.
func (r *Resolver) CookieCategoryConnection() schema.CookieCategoryConnectionResolver {
return &cookieCategoryConnectionResolver{r}
}
// CookieConnection returns schema.CookieConnectionResolver implementation.
func (r *Resolver) CookieConnection() schema.CookieConnectionResolver {
return &cookieConnectionResolver{r}
}
type cookieResolver struct{ *Resolver }
type cookieBannerResolver struct{ *Resolver }
type cookieBannerConnectionResolver struct{ *Resolver }
type cookieCategoryResolver struct{ *Resolver }
type cookieCategoryConnectionResolver struct{ *Resolver }
type cookieConnectionResolver struct{ *Resolver }