def build_WagtailStreamFieldValidationError(): def resolve_block_errors(obj, info): result = [] for k, v in obj['params'].items(): assert isinstance(v, ErrorList) if k == '__all__': continue # non-block error result.append({'block_id': k, 'error': v}) return result def resolve_non_block_error(obj, info): error = obj['params'].get('__all__') if error is None: return None return str(error) return g.ObjectType( 'WagtailStreamFieldValidationError', g.fields({ 'block_errors': g.Field( g.NNList(WagtailStreamBlockValidationError), resolve=resolve_block_errors, ), 'non_block_error': g.Field(g.String, resolve=resolve_non_block_error), }), )
def myEmailUnsubscribe(_): @check_permissions([authenticated]) def resolve(_, info): member_from_info(info).set_status('unsubscribed', check_old_status='subscribed') return True return g.Field(g.Boolean, resolve=resolve)
def build_StructBlockValidationError(): FieldValidationError = g.ObjectType( 'WagtailStructBlockFieldValidationError', fields=lambda: g.fields({ 'name': str, 'error': WagtailBlockValidationError }), ) return g.ObjectType( 'WagtailStructBlockValidationError', fields=lambda: g.fields({ 'error_message': valdiation_error_message_field, 'errors': g.Field( g.NNList(FieldValidationError), resolve=lambda obj, info: [{ 'name': k, 'error': v } for k, v in obj.data[0].params.items()], ), }), interfaces=[WagtailBlockValidationError], )
def events(_): async def subscribe(obj, info): # check permissions await sync_to_async(permissions.manage_events, thread_sensitive=True)(obj, info) async for msg in channels.update_group.subscribe(): logger.debug('Event update: ' + str(msg)) yield msg @check_permissions([permissions.manage_events]) def resolve(msg, info): logger.debug(info.context) if not msg: # this can happen if we invoke subscription via HTTP due to incorrectly configured Apollo client & link logger.error('weird, msg is empty') return # this will cause an exception anyway since `events` result is non-nullable # It'd be better to yield event, but it's problematic because all other resolver are sync # and Django ORM can't be called in async context. return { 'type': msg['type'], 'id': msg['uuid'], } return g.Field(g.NN(EventNotification), resolve=resolve, subscribe=subscribe)
def mastermindDatingCreateCohort(helper): @check_permissions([staffonly]) def resolve(_, info): cohort = models.Cohort.objects.create() return {'cohort': cohort} return g.Field(g.NN(CohortMutationResult), resolve=resolve)
def build_comments_field(permissions: List[helpers.PermissionType]): def resolve(obj, info, **pager): assert isinstance(obj, models.Commentable) return obj.comments.all() result = g.NNList(types.Comment) return g.Field(result, resolve=check_permissions(permissions)(resolve))
def mastermindDatingCreateParticipant(_): @check_permissions([staffonly]) def resolve(_, info, cohort_id, email): KchUser = get_user_model() try: kocherga_user = KchUser.objects.get(email=email) except KchUser.DoesNotExist: kocherga_user = KchUser.objects.create_user(email) cohort = models.Cohort.objects.get(pk=cohort_id) (participant, _) = models.Participant.objects.get_or_create( user=kocherga_user, cohort=cohort, ) return {'participant': participant} return g.Field( g.NN(ParticipantMutationResult), args=g.arguments({ 'cohort_id': 'ID!', 'email': str }), resolve=resolve, )
def build_ValidationError(): ValidationErrorItem = g.ObjectType( 'ValidationErrorItem', fields=g.fields({ 'name': str, 'messages': g.NNList(g.String), }), ) def resolve_errors(obj, info): # note .error, obj is boxed with kocherga.django.errors.BoxedError return [{ 'name': k, 'messages': [str(e) for e in v] } for k, v in obj.error.message_dict.items()] return g.ObjectType( 'ValidationError', fields={ 'errors': g.Field( g.NNList(ValidationErrorItem), resolve=resolve_errors, ), }, )
def emailSubscribeChannelDelete(_): @check_permissions([staffonly]) def resolve(_, info, slug): models.SubscribeChannel.objects.get(slug=slug).delete() return True return g.Field(g.Boolean, args=g.arguments({'slug': str}), resolve=resolve)
def authPermissionsAll(helper): @check_permissions([user_perm("auth.audit")]) def resolve(_, info): return auth_models.Permission.objects.all() Result = g.NNList(types.AuthPermission) return g.Field(Result, resolve=resolve)
def staffGrantGooglePermissionsToMember(helper): @check_permissions([user_perm('staff.manage')]) def resolve(obj, info, id): member = models.Member.objects.get(pk=id) member.grant_google_permissions() return True return g.Field(g.Boolean, args=g.arguments({'id': 'ID!'}), resolve=resolve)
def vk_group_field(): def resolve(obj, info): if not obj.vk_group: return None return { 'name': obj.vk_group, } return g.Field(VkGroup, resolve=resolve)
def service_fields(account_type): return g.fields({ 'slug': str, 'accounts': g.Field( g.NNList(account_type), resolve=lambda obj, info: obj.list_accounts(), ), })
def emailSubscribeChannelAddEmail(_): @check_permissions([staffonly]) def resolve(_, info, slug, email): channel = models.SubscribeChannel.objects.get(slug=slug) channel.subscribe_email(email) return True return g.Field( g.Boolean, args=g.arguments({'slug': str, 'email': str}), resolve=resolve )
def membership(helper): @permissions.check_permissions([permissions.authenticated]) def resolve(_, info): user = info.context.user if not hasattr(user, 'customer'): return None # not all users have CM customer, that's fine return user.customer return g.Field(MyCmCustomer, resolve=resolve)
def instances_field(): @check_permissions([permissions.manage_events]) def resolve(obj, info, limit=None): return obj.instances(limit=limit) return g.Field( g.NNList(Event), args=g.arguments({'limit': Optional[int]}), resolve=resolve, )
def mastermindDatingCohortById(helper): @check_permissions([staffonly]) def resolve(_, info, id): return models.Cohort.objects.get(pk=id) return g.Field( g.NN(types.MastermindDatingCohort), args=g.arguments({'id': 'ID!'}), resolve=resolve, )
def wagtailPages(helper): def resolve(_, info): # page.specific is slow! # But we call wagtailPages only on getStaticPaths once per build, so that should be ok. return [ page.specific for page in get_page_queryset_for_request(info.context) ] return g.Field(g.NNList(types.WagtailPage), resolve=resolve)
def announcements_field(): from .announcements import EventsAnnouncements def resolve(obj, info): return { 'timepad': getattr(obj, 'timepad_announcement', None), 'vk': getattr(obj, 'vk_announcement', None), 'fb': getattr(obj, 'fb_announcement', None), } return g.Field(g.NN(EventsAnnouncements), resolve=resolve)
def description_field(): def resolve(obj, info, format=None): # PLAIN is default for now, for backward-compatibility if format == 'PLAIN' or format is None: return markup.Markup(obj.description).as_plain() elif format == 'SOURCE' or format is None: return obj.description else: raise Exception(f"Unknown markup format {format}") args = g.arguments({'format': EventsMarkupFormat}) return g.Field(g.NN(g.String), args=args, resolve=resolve)
def mastermindDatingActivateVoting(_): @check_permissions([staffonly]) def resolve(_, info, participant_id): obj = models.Participant.objects.get(pk=participant_id) obj.tinder_activate() return {'participant': obj} return g.Field( g.NN(ParticipantMutationResult), args=g.arguments({'participant_id': 'ID!'}), resolve=resolve, )
def mastermindDatingDeleteCohort(helper): @check_permissions([staffonly]) def resolve(_, info, cohort_id): obj = models.Cohort.objects.get(pk=cohort_id) obj.delete() return {'ok': True} return g.Field( g.NN(BasicResult), args=g.arguments({'cohort_id': 'ID!'}), resolve=resolve, )
def mastermindDatingCreateGroup(helper): @check_permissions([staffonly]) def resolve(_, info, cohort_id): cohort = models.Cohort.objects.get(pk=cohort_id) models.Group.objects.create_for_cohort(cohort) return {'cohort': cohort} return g.Field( g.NN(CohortMutationResult), args=g.arguments({'cohort_id': 'ID!'}), resolve=resolve, )
def my_ticket_field(): # note that there's no @auth decorator - we don't want any errors if user is not authenticated def resolve(obj, info): if not info.context.user.is_authenticated: return None # not authorized, no ticket, but that's ok ticket = obj.tickets.filter(user=info.context.user).first() return ticket # lazy import - avoiding circular dependency from .my_ticket import MyEventsTicket return g.Field(MyEventsTicket, resolve=resolve)
def mastermindDatingUnsetEventForCohort(_): @check_permissions([staffonly]) def resolve(_, info, cohort_id): cohort = models.Cohort.objects.get(pk=cohort_id) cohort.event = None cohort.save() return {'cohort': cohort} return g.Field( g.NN(CohortMutationResult), args=g.arguments({'cohort_id': 'ID!'}), resolve=resolve, )
def build_AnyBlockValidationError(): return g.ObjectType( 'WagtailAnyBlockValidationError', fields=lambda: g.fields({ 'error_message': g.Field( g.NN(g.String), resolve=lambda obj, info: getattr(obj.data[0], 'message', str(obj.data[0])), ), }), interfaces=[WagtailBlockValidationError], )
def richtext_field(model, field_name): # via https://github.com/wagtail/wagtail/issues/2695 - fixing <embed> in RichTextFields def resolve(obj, info): value = getattr(obj, field_name) return wagtail.core.rich_text.expand_db_html(value) # TODO - check that model field is nullable and don't wrap in g.NN if it's nullable? type_ = g.NN(g.String) assert isinstance(model._meta.get_field(field_name), wagtail.core.fields.RichTextField) return g.Field(type_, resolve=resolve)
def myPrivacyModeSet(helper): @permissions.check_permissions([permissions.authenticated]) def resolve(_, info, mode: str): if not hasattr(info.context.user, 'customer'): raise Exception("User doesn't have a customer profile") customer = info.context.user.customer customer.privacy_mode = mode customer.full_clean() customer.save() return True return g.Field(g.Boolean, args=g.arguments({'mode': str}), resolve=resolve)
def image_rendition_field(model, field_name, permissions: List[Any] = []): @check_permissions(permissions) def resolve(obj, info, spec): image = getattr(obj, field_name) if not image: return None return image.get_rendition(spec) field = model._meta.get_field(field_name) assert issubclass(field.related_model, wagtail.images.models.AbstractImage) Result = types.WagtailImageRendition if not field.null: Result = g.NN(Result) return g.Field(Result, args=g.arguments({'spec': str}), resolve=resolve)
def create_EventsListBlock(): def resolve_value(obj, info): qs = kocherga.events.models.Event.objects.public_only( ).filter_by_period(from_date=datetime.today()) return qs[:20] return g.ObjectType( 'EventsListBlock', interfaces=[WagtailBlock], fields=g.fields({ 'id': 'ID!', 'events': g.Field(g.NNList(event_types.Event), resolve=resolve_value), }), )