def remote_server_post_analytics(request: HttpRequest, entity: Union[UserProfile, RemoteZulipServer], realm_counts: List[Dict[str, Any]]=REQ( validator=check_list(check_dict_only([ ('property', check_string), ('realm', check_int), ('id', check_int), ('end_time', check_float), ('subgroup', check_none_or(check_string)), ('value', check_int), ]))), installation_counts: List[Dict[str, Any]]=REQ( validator=check_list(check_dict_only([ ('property', check_string), ('id', check_int), ('end_time', check_float), ('subgroup', check_none_or(check_string)), ('value', check_int), ])))) -> HttpResponse: validate_entity(entity) server = cast(RemoteZulipServer, entity) validate_count_stats(server, RemoteRealmCount, realm_counts) validate_count_stats(server, RemoteInstallationCount, installation_counts) BATCH_SIZE = 1000 while len(realm_counts) > 0: batch = realm_counts[0:BATCH_SIZE] realm_counts = realm_counts[BATCH_SIZE:] objects_to_create = [] for item in batch: objects_to_create.append(RemoteRealmCount( property=item['property'], realm_id=item['realm'], remote_id=item['id'], server=server, end_time=datetime.datetime.fromtimestamp(item['end_time'], tz=timezone_utc), subgroup=item['subgroup'], value=item['value'])) RemoteRealmCount.objects.bulk_create(objects_to_create) while len(installation_counts) > 0: batch = installation_counts[0:BATCH_SIZE] installation_counts = installation_counts[BATCH_SIZE:] objects_to_create = [] for item in batch: objects_to_create.append(RemoteInstallationCount( property=item['property'], remote_id=item['id'], server=server, end_time=datetime.datetime.fromtimestamp(item['end_time'], tz=timezone_utc), subgroup=item['subgroup'], value=item['value'])) RemoteInstallationCount.objects.bulk_create(objects_to_create) return json_success()
def test_check_dict(self): # type: () -> None keys = [ ('names', check_list(check_string)), ('city', check_string), ] # type: List[Tuple[str, Validator]] x = { 'names': ['alice', 'bob'], 'city': 'Boston', } # type: Any error = check_dict(keys)('x', x) self.assertEqual(error, None) x = 999 error = check_dict(keys)('x', x) self.assertEqual(error, 'x is not a dict') x = {} error = check_dict(keys)('x', x) self.assertEqual(error, 'names key is missing from x') x = { 'names': ['alice', 'bob', {}] } error = check_dict(keys)('x', x) self.assertEqual(error, 'x["names"][2] is not a string') x = { 'names': ['alice', 'bob'], 'city': 5 } error = check_dict(keys)('x', x) self.assertEqual(error, 'x["city"] is not a string') # test dict_only x = { 'names': ['alice', 'bob'], 'city': 'Boston', } error = check_dict_only(keys)('x', x) self.assertEqual(error, None) x = { 'names': ['alice', 'bob'], 'city': 'Boston', 'state': 'Massachusetts', } error = check_dict_only(keys)('x', x) self.assertEqual(error, 'Unexpected arguments: state')
def check_events_dict( required_keys: Sequence[Tuple[str, Validator[object]]], optional_keys: Sequence[Tuple[str, Validator[object]]] = [], ) -> Validator[Dict[str, object]]: """ This is just a tiny wrapper on check_dict, but it provides some minor benefits: - mark clearly that the schema is for a Zulip event - make sure there's a type field - add id field automatically - sanity check that we have no duplicate keys (we should just make check_dict do that, eventually) """ rkeys = [key[0] for key in required_keys] okeys = [key[0] for key in optional_keys] keys = rkeys + okeys assert len(keys) == len(set(keys)) assert "type" in rkeys assert "id" not in keys return check_dict_only( required_keys=list(required_keys) + [("id", check_int)], optional_keys=optional_keys, )
def validate_external_account_field_data(field_data: ProfileFieldData) -> ProfileFieldData: field_validator = check_dict_only( [("subtype", check_required_string)], [("url_pattern", check_external_account_url_pattern)], ) field_validator("field_data", field_data) field_subtype = field_data.get("subtype") if field_subtype not in DEFAULT_EXTERNAL_ACCOUNTS.keys(): if field_subtype == "custom": if "url_pattern" not in field_data.keys(): raise ValidationError(_("Custom external account must define URL pattern")) else: raise ValidationError(_("Invalid external account type")) return field_data
def update_user_custom_profile_data( request: HttpRequest, user_profile: UserProfile, data: List[Dict[str, Union[int, ProfileDataElementValue]]] = REQ( json_validator=check_list( check_dict_only([ ("id", check_int), ("value", check_union([check_string, check_list(check_int)])), ]), )), ) -> HttpResponse: validate_user_custom_profile_data(user_profile.realm.id, data) do_update_user_custom_profile_data_if_changed(user_profile, data) # We need to call this explicitly otherwise constraints are not check return json_success()
def validate_external_account_field_data(field_data: ProfileFieldData) -> Optional[str]: field_validator = check_dict_only( [('subtype', check_required_string)], [('url_pattern', check_external_account_url_pattern)], ) error = field_validator('field_data', field_data) if error: return error field_subtype = field_data.get('subtype') if field_subtype not in DEFAULT_EXTERNAL_ACCOUNTS.keys(): if field_subtype == "custom": if 'url_pattern' not in field_data.keys(): return _("Custom external account must define url pattern") else: return _("Invalid external account type") return None
def add_subscriptions_backend( request: HttpRequest, user_profile: UserProfile, streams_raw: Iterable[Dict[str, str]]=REQ( "subscriptions", validator=check_list(check_dict_only( [('name', check_string)], optional_keys=[ ('color', check_color), ('description', check_capped_string(Stream.MAX_DESCRIPTION_LENGTH)), ]) )), invite_only: bool=REQ(validator=check_bool, default=False), is_announcement_only: bool=REQ(validator=check_bool, default=False), history_public_to_subscribers: Optional[bool]=REQ(validator=check_bool, default=None), announce: bool=REQ(validator=check_bool, default=False), principals: List[str]=REQ(validator=check_list(check_string), default=[]), authorization_errors_fatal: bool=REQ(validator=check_bool, default=True), ) -> HttpResponse: stream_dicts = [] color_map = {} for stream_dict in streams_raw: # 'color' field is optional # check for its presence in the streams_raw first if 'color' in stream_dict: color_map[stream_dict['name']] = stream_dict['color'] if 'description' in stream_dict: # We don't allow newline characters in stream descriptions. stream_dict['description'] = stream_dict['description'].replace("\n", " ") stream_dict_copy = {} # type: Dict[str, Any] for field in stream_dict: stream_dict_copy[field] = stream_dict[field] # Strip the stream name here. stream_dict_copy['name'] = stream_dict_copy['name'].strip() stream_dict_copy["invite_only"] = invite_only stream_dict_copy["is_announcement_only"] = is_announcement_only stream_dict_copy["history_public_to_subscribers"] = history_public_to_subscribers stream_dicts.append(stream_dict_copy) # Validation of the streams arguments, including enforcement of # can_create_streams policy and check_stream_name policy is inside # list_to_streams. existing_streams, created_streams = \ list_to_streams(stream_dicts, user_profile, autocreate=True) authorized_streams, unauthorized_streams = \ filter_stream_authorization(user_profile, existing_streams) if len(unauthorized_streams) > 0 and authorization_errors_fatal: return json_error(_("Unable to access stream (%s).") % unauthorized_streams[0].name) # Newly created streams are also authorized for the creator streams = authorized_streams + created_streams if len(principals) > 0: if user_profile.realm.is_zephyr_mirror_realm and not all(stream.invite_only for stream in streams): return json_error(_("You can only invite other Zephyr mirroring users to private streams.")) if not user_profile.can_subscribe_other_users(): return json_error(_("Your account is too new to modify other users' subscriptions.")) subscribers = set(principal_to_user_profile(user_profile, principal) for principal in principals) else: subscribers = set([user_profile]) (subscribed, already_subscribed) = bulk_add_subscriptions(streams, subscribers, acting_user=user_profile, color_map=color_map) # We can assume unique emails here for now, but we should eventually # convert this function to be more id-centric. email_to_user_profile = dict() # type: Dict[str, UserProfile] result = dict(subscribed=defaultdict(list), already_subscribed=defaultdict(list)) # type: Dict[str, Any] for (subscriber, stream) in subscribed: result["subscribed"][subscriber.email].append(stream.name) email_to_user_profile[subscriber.email] = subscriber for (subscriber, stream) in already_subscribed: result["already_subscribed"][subscriber.email].append(stream.name) bots = dict((subscriber.email, subscriber.is_bot) for subscriber in subscribers) newly_created_stream_names = {s.name for s in created_streams} # Inform the user if someone else subscribed them to stuff, # or if a new stream was created with the "announce" option. notifications = [] if len(principals) > 0 and result["subscribed"]: for email, subscribed_stream_names in result["subscribed"].items(): if email == user_profile.email: # Don't send a Zulip if you invited yourself. continue if bots[email]: # Don't send invitation Zulips to bots continue # For each user, we notify them about newly subscribed streams, except for # streams that were newly created. notify_stream_names = set(subscribed_stream_names) - newly_created_stream_names if not notify_stream_names: continue msg = you_were_just_subscribed_message( acting_user=user_profile, stream_names=notify_stream_names, ) sender = get_system_bot(settings.NOTIFICATION_BOT) notifications.append( internal_prep_private_message( realm=user_profile.realm, sender=sender, recipient_user=email_to_user_profile[email], content=msg)) if announce and len(created_streams) > 0 and settings.NOTIFICATION_BOT is not None: notifications_stream = user_profile.realm.get_notifications_stream() if notifications_stream is not None: if len(created_streams) > 1: stream_strs = ", ".join('#**%s**' % s.name for s in created_streams) stream_msg = "the following streams: %s" % (stream_strs,) else: stream_msg = "a new stream #**%s**." % created_streams[0].name msg = ("@_**%s|%d** just created %s" % (user_profile.full_name, user_profile.id, stream_msg)) sender = get_system_bot(settings.NOTIFICATION_BOT) topic = 'Streams' notifications.append( internal_prep_stream_message( realm=user_profile.realm, sender=sender, stream=notifications_stream, topic=topic, content=msg, ) ) if not user_profile.realm.is_zephyr_mirror_realm: for stream in created_streams: notifications.append(prep_stream_welcome_message(stream)) if len(notifications) > 0: do_send_messages(notifications) result["subscribed"] = dict(result["subscribed"]) result["already_subscribed"] = dict(result["already_subscribed"]) if not authorization_errors_fatal: result["unauthorized"] = [s.name for s in unauthorized_streams] return json_success(result)
user_profile: UserProfile, include_subscribers: bool=REQ(validator=check_bool, default=False), ) -> HttpResponse: subscribed, _ = gather_subscriptions( user_profile, include_subscribers=include_subscribers, ) return json_success({"subscriptions": subscribed}) FuncKwargPair = Tuple[Callable[..., HttpResponse], Dict[str, Union[int, Iterable[Any]]]] add_subscriptions_schema = check_list( check_dict_only( required_keys=[ ('name', check_string) ], optional_keys=[ ('color', check_color), ('description', check_capped_string(Stream.MAX_DESCRIPTION_LENGTH)), ], ), ) remove_subscriptions_schema = check_list(check_string) @has_request_variables def update_subscriptions_backend( request: HttpRequest, user_profile: UserProfile, delete: Iterable[str]=REQ(validator=remove_subscriptions_schema, default=[]), add: Iterable[Mapping[str, Any]]=REQ(validator=add_subscriptions_schema, default=[]), ) -> HttpResponse: if not add and not delete:
def remote_server_post_analytics( request: HttpRequest, entity: Union[UserProfile, RemoteZulipServer], realm_counts: List[Dict[str, Any]] = REQ(json_validator=check_list( check_dict_only([ ("property", check_string), ("realm", check_int), ("id", check_int), ("end_time", check_float), ("subgroup", check_none_or(check_string)), ("value", check_int), ]))), installation_counts: List[Dict[str, Any]] = REQ(json_validator=check_list( check_dict_only([ ("property", check_string), ("id", check_int), ("end_time", check_float), ("subgroup", check_none_or(check_string)), ("value", check_int), ]))), realmauditlog_rows: Optional[List[Dict[str, Any]]] = REQ( json_validator=check_list( check_dict_only([ ("id", check_int), ("realm", check_int), ("event_time", check_float), ("backfilled", check_bool), ("extra_data", check_none_or(check_string)), ("event_type", check_int), ])), default=None, ), ) -> HttpResponse: server = validate_entity(entity) validate_incoming_table_data(server, RemoteRealmCount, realm_counts, True) validate_incoming_table_data(server, RemoteInstallationCount, installation_counts, True) if realmauditlog_rows is not None: validate_incoming_table_data(server, RemoteRealmAuditLog, realmauditlog_rows) row_objects = [ RemoteRealmCount( property=row["property"], realm_id=row["realm"], remote_id=row["id"], server=server, end_time=datetime.datetime.fromtimestamp(row["end_time"], tz=datetime.timezone.utc), subgroup=row["subgroup"], value=row["value"], ) for row in realm_counts ] batch_create_table_data(server, RemoteRealmCount, row_objects) row_objects = [ RemoteInstallationCount( property=row["property"], remote_id=row["id"], server=server, end_time=datetime.datetime.fromtimestamp(row["end_time"], tz=datetime.timezone.utc), subgroup=row["subgroup"], value=row["value"], ) for row in installation_counts ] batch_create_table_data(server, RemoteInstallationCount, row_objects) if realmauditlog_rows is not None: row_objects = [ RemoteRealmAuditLog( realm_id=row["realm"], remote_id=row["id"], server=server, event_time=datetime.datetime.fromtimestamp( row["event_time"], tz=datetime.timezone.utc), backfilled=row["backfilled"], extra_data=row["extra_data"], event_type=row["event_type"], ) for row in realmauditlog_rows ] batch_create_table_data(server, RemoteRealmAuditLog, row_objects) return json_success()
allow_bots=True, for_admin=True) if target.is_bot: assert target.bot_type is not None check_bot_creation_policy(user_profile, target.bot_type) do_reactivate_user(target, acting_user=user_profile) return json_success() check_profile_data: Validator[List[Dict[str, Optional[Union[ int, str, List[int]]]]]] = check_list( check_dict_only([ ("id", check_int), ( "value", check_none_or( check_union( [check_int, check_string, check_list(check_int)]), ), ), ]), ) @has_request_variables def update_user_backend( request: HttpRequest, user_profile: UserProfile, user_id: int, full_name: Optional[str] = REQ(default=None, json_validator=check_string), role: Optional[int] = REQ( default=None, json_validator=check_int_in(UserProfile.ROLE_TYPES, ),
check_union, ) from zerver.models import Draft, UserProfile from zerver.tornado.django_api import send_event VALID_DRAFT_TYPES: Set[str] = {"", "private", "stream"} # A validator to verify if the structure (syntax) of a dictionary # meets the requirements to be a draft dictionary: draft_dict_validator = check_dict_only( required_keys=[ ("type", check_string_in(VALID_DRAFT_TYPES)), ("to", check_list(check_int) ), # The ID of the stream to send to, or a list of user IDs. ("topic", check_string ), # This string can simply be empty for private type messages. ("content", check_required_string), ], optional_keys=[ ("timestamp", check_union([check_int, check_float])), # A Unix timestamp. ], ) def further_validated_draft_dict(draft_dict: Dict[str, Any], user_profile: UserProfile) -> Dict[str, Any]: """Take a draft_dict that was already validated by draft_dict_validator then further sanitize, validate, and transform it. Ultimately return this "further validated" draft dict. It will have a slightly different set of keys the values for which can be used to directly create a Draft object."""
user_id, allow_deactivated=True, allow_bots=True) if target.is_bot: assert target.bot_type is not None check_bot_creation_policy(user_profile, target.bot_type) do_reactivate_user(target, acting_user=user_profile) return json_success() check_profile_data: Validator[List[Dict[str, Optional[Union[ int, str, List[int]]]]]] = check_list( check_dict_only([ ('id', check_int), ('value', check_none_or( check_union([check_int, check_string, check_list(check_int)]), )), ]), ) @has_request_variables def update_user_backend( request: HttpRequest, user_profile: UserProfile, user_id: int, full_name: Optional[str] = REQ(default=None, validator=check_string), role: Optional[int] = REQ(default=None, validator=check_int_in( UserProfile.ROLE_TYPES, )), profile_data: Optional[List[Dict[str, Optional[Union[
def add_subscriptions_backend( request: HttpRequest, user_profile: UserProfile, streams_raw: Iterable[Dict[str, str]] = REQ( "subscriptions", validator=check_list( check_dict_only([('name', check_string)], optional_keys=[ ('color', check_color), ('description', check_capped_string( Stream.MAX_DESCRIPTION_LENGTH)), ]), )), invite_only: bool = REQ(validator=check_bool, default=False), stream_post_policy: int = REQ(validator=check_int_in( Stream.STREAM_POST_POLICY_TYPES), default=Stream.STREAM_POST_POLICY_EVERYONE), history_public_to_subscribers: Optional[bool] = REQ(validator=check_bool, default=None), message_retention_days: Union[str, int] = REQ(validator=check_string_or_int, default="realm_default"), announce: bool = REQ(validator=check_bool, default=False), principals: Union[Sequence[str], Sequence[int]] = REQ(validator=check_union( [check_list(check_string), check_list(check_int)]), default=[]), authorization_errors_fatal: bool = REQ(validator=check_bool, default=True), ) -> HttpResponse: stream_dicts = [] color_map = {} for stream_dict in streams_raw: # 'color' field is optional # check for its presence in the streams_raw first if 'color' in stream_dict: color_map[stream_dict['name']] = stream_dict['color'] if 'description' in stream_dict: # We don't allow newline characters in stream descriptions. stream_dict['description'] = stream_dict['description'].replace( "\n", " ") stream_dict_copy: Dict[str, Any] = {} for field in stream_dict: stream_dict_copy[field] = stream_dict[field] # Strip the stream name here. stream_dict_copy['name'] = stream_dict_copy['name'].strip() stream_dict_copy["invite_only"] = invite_only stream_dict_copy["stream_post_policy"] = stream_post_policy stream_dict_copy[ "history_public_to_subscribers"] = history_public_to_subscribers stream_dict_copy[ "message_retention_days"] = parse_message_retention_days( message_retention_days) stream_dicts.append(stream_dict_copy) # Validation of the streams arguments, including enforcement of # can_create_streams policy and check_stream_name policy is inside # list_to_streams. existing_streams, created_streams = \ list_to_streams(stream_dicts, user_profile, autocreate=True) authorized_streams, unauthorized_streams = \ filter_stream_authorization(user_profile, existing_streams) if len(unauthorized_streams) > 0 and authorization_errors_fatal: return json_error( _("Unable to access stream ({stream_name}).").format( stream_name=unauthorized_streams[0].name, )) # Newly created streams are also authorized for the creator streams = authorized_streams + created_streams if len(principals) > 0: if user_profile.realm.is_zephyr_mirror_realm and not all( stream.invite_only for stream in streams): return json_error( _("You can only invite other Zephyr mirroring users to private streams." )) if not user_profile.can_subscribe_other_users(): if user_profile.realm.invite_to_stream_policy == Realm.POLICY_ADMINS_ONLY: return json_error( _("Only administrators can modify other users' subscriptions." )) # Realm.POLICY_MEMBERS_ONLY only fails if the # user is a guest, which happens in the decorator above. assert user_profile.realm.invite_to_stream_policy == \ Realm.POLICY_FULL_MEMBERS_ONLY return json_error( _("Your account is too new to modify other users' subscriptions." )) subscribers = { principal_to_user_profile(user_profile, principal) for principal in principals } else: subscribers = {user_profile} (subscribed, already_subscribed) = bulk_add_subscriptions(streams, subscribers, acting_user=user_profile, color_map=color_map) # We can assume unique emails here for now, but we should eventually # convert this function to be more id-centric. email_to_user_profile: Dict[str, UserProfile] = dict() result: Dict[str, Any] = dict(subscribed=defaultdict(list), already_subscribed=defaultdict(list)) for (subscriber, stream) in subscribed: result["subscribed"][subscriber.email].append(stream.name) email_to_user_profile[subscriber.email] = subscriber for (subscriber, stream) in already_subscribed: result["already_subscribed"][subscriber.email].append(stream.name) bots = {subscriber.email: subscriber.is_bot for subscriber in subscribers} newly_created_stream_names = {s.name for s in created_streams} # Inform the user if someone else subscribed them to stuff, # or if a new stream was created with the "announce" option. notifications = [] if len(principals) > 0 and result["subscribed"]: for email, subscribed_stream_names in result["subscribed"].items(): if email == user_profile.email: # Don't send a Zulip if you invited yourself. continue if bots[email]: # Don't send invitation Zulips to bots continue # For each user, we notify them about newly subscribed streams, except for # streams that were newly created. notify_stream_names = set( subscribed_stream_names) - newly_created_stream_names if not notify_stream_names: continue msg = you_were_just_subscribed_message( acting_user=user_profile, stream_names=notify_stream_names, ) sender = get_system_bot(settings.NOTIFICATION_BOT) notifications.append( internal_prep_private_message( realm=user_profile.realm, sender=sender, recipient_user=email_to_user_profile[email], content=msg)) if announce and len(created_streams) > 0: notifications_stream = user_profile.realm.get_notifications_stream() if notifications_stream is not None: if len(created_streams) > 1: content = _( "@_**%(user_name)s|%(user_id)d** created the following streams: %(stream_str)s." ) else: content = _( "@_**%(user_name)s|%(user_id)d** created a new stream %(stream_str)s." ) content = content % { 'user_name': user_profile.full_name, 'user_id': user_profile.id, 'stream_str': ", ".join(f'#**{s.name}**' for s in created_streams) } sender = get_system_bot(settings.NOTIFICATION_BOT) topic = _('new streams') notifications.append( internal_prep_stream_message( realm=user_profile.realm, sender=sender, stream=notifications_stream, topic=topic, content=content, ), ) if not user_profile.realm.is_zephyr_mirror_realm and len( created_streams) > 0: sender = get_system_bot(settings.NOTIFICATION_BOT) for stream in created_streams: notifications.append( internal_prep_stream_message( realm=user_profile.realm, sender=sender, stream=stream, topic=Realm.STREAM_EVENTS_NOTIFICATION_TOPIC, content=_('Stream created by @_**{user_name}|{user_id}**.' ).format( user_name=user_profile.full_name, user_id=user_profile.id, ), ), ) if len(notifications) > 0: do_send_messages(notifications, mark_as_read=[user_profile.id]) result["subscribed"] = dict(result["subscribed"]) result["already_subscribed"] = dict(result["already_subscribed"]) if not authorization_errors_fatal: result["unauthorized"] = [s.name for s in unauthorized_streams] return json_success(result)
def remote_server_post_analytics( request: HttpRequest, entity: Union[UserProfile, RemoteZulipServer], realm_counts: List[Dict[str, Any]] = REQ(validator=check_list( check_dict_only([ ('property', check_string), ('realm', check_int), ('id', check_int), ('end_time', check_float), ('subgroup', check_none_or(check_string)), ('value', check_int), ]))), installation_counts: List[Dict[str, Any]] = REQ(validator=check_list( check_dict_only([ ('property', check_string), ('id', check_int), ('end_time', check_float), ('subgroup', check_none_or(check_string)), ('value', check_int), ]))), realmauditlog_rows: Optional[List[Dict[str, Any]]] = REQ( validator=check_list( check_dict_only([ ('id', check_int), ('realm', check_int), ('event_time', check_float), ('backfilled', check_bool), ('extra_data', check_none_or(check_string)), ('event_type', check_int), ])), default=None) ) -> HttpResponse: server = validate_entity(entity) validate_incoming_table_data(server, RemoteRealmCount, realm_counts, True) validate_incoming_table_data(server, RemoteInstallationCount, installation_counts, True) if realmauditlog_rows is not None: validate_incoming_table_data(server, RemoteRealmAuditLog, realmauditlog_rows) row_objects = [ RemoteRealmCount(property=row['property'], realm_id=row['realm'], remote_id=row['id'], server=server, end_time=datetime.datetime.fromtimestamp( row['end_time'], tz=timezone_utc), subgroup=row['subgroup'], value=row['value']) for row in realm_counts ] batch_create_table_data(server, RemoteRealmCount, row_objects) row_objects = [ RemoteInstallationCount( property=row['property'], remote_id=row['id'], server=server, end_time=datetime.datetime.fromtimestamp(row['end_time'], tz=timezone_utc), subgroup=row['subgroup'], value=row['value']) for row in installation_counts ] batch_create_table_data(server, RemoteInstallationCount, row_objects) if realmauditlog_rows is not None: row_objects = [ RemoteRealmAuditLog( realm_id=row['realm'], remote_id=row['id'], server=server, event_time=datetime.datetime.fromtimestamp(row['event_time'], tz=timezone_utc), backfilled=row['backfilled'], extra_data=row['extra_data'], event_type=row['event_type']) for row in realmauditlog_rows ] batch_create_table_data(server, RemoteRealmAuditLog, row_objects) return json_success()
request: HttpRequest, user_profile: UserProfile, include_subscribers: bool = REQ(json_validator=check_bool, default=False), ) -> HttpResponse: subscribed, _ = gather_subscriptions( user_profile, include_subscribers=include_subscribers, ) return json_success({"subscriptions": subscribed}) add_subscriptions_schema = check_list( check_dict_only( required_keys=[("name", check_string)], optional_keys=[ ("color", check_color), ("description", check_capped_string(Stream.MAX_DESCRIPTION_LENGTH)), ], ), ) remove_subscriptions_schema = check_list(check_string) @has_request_variables def update_subscriptions_backend( request: HttpRequest, user_profile: UserProfile, delete: Sequence[str] = REQ(json_validator=remove_subscriptions_schema, default=[]), add: Sequence[Mapping[str, str]] = REQ(json_validator=add_subscriptions_schema,
] ) check_alert_words = check_events_dict( required_keys=[ # force vertical formatting ("type", equals("alert_words")), ("alert_words", check_list(check_string)), ] ) _check_custom_profile_field = check_dict_only( required_keys=[ ("id", check_int), ("type", check_int), ("name", check_string), ("hint", check_string), ("field_data", check_string), ("order", check_int), ] ) check_custom_profile_fields = check_events_dict( required_keys=[ ("type", equals("custom_profile_fields")), ("op", equals("add")), ("fields", check_list(_check_custom_profile_field)), ] ) check_invites_changed = check_events_dict( required_keys=[