mirror of https://github.com/zulip/zulip.git
push_notifs: Rename PushDeviceToken.GCM to FCM.
This commit is contained in:
parent
4591202032
commit
00b8cce50e
|
@ -1380,13 +1380,13 @@ class TestLoggingCountStats(AnalyticsTestCase):
|
|||
token = "aaaa"
|
||||
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64(token),
|
||||
user_uuid=(hamlet.uuid),
|
||||
server=self.server,
|
||||
)
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64(token + "aa"),
|
||||
user_uuid=(hamlet.uuid),
|
||||
server=self.server,
|
||||
|
|
|
@ -396,7 +396,7 @@ def has_gcm_credentials() -> bool: # nocoverage
|
|||
def send_android_push_notification_to_user(
|
||||
user_profile: UserProfile, data: Dict[str, Any], options: Dict[str, Any]
|
||||
) -> None:
|
||||
devices = list(PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.GCM))
|
||||
devices = list(PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.FCM))
|
||||
send_android_push_notification(
|
||||
UserPushIdentityCompat(user_id=user_profile.id), devices, data, options
|
||||
)
|
||||
|
@ -527,7 +527,7 @@ def send_android_push_notification(
|
|||
# We remove all entries for this token (There
|
||||
# could be multiple for different Zulip servers).
|
||||
DeviceTokenClass._default_manager.filter(
|
||||
token=reg_id, kind=DeviceTokenClass.GCM
|
||||
token=reg_id, kind=DeviceTokenClass.FCM
|
||||
).delete()
|
||||
else:
|
||||
for reg_id in reg_ids:
|
||||
|
@ -610,7 +610,7 @@ def send_notifications_to_bouncer(
|
|||
sorted(apple_deleted_devices),
|
||||
)
|
||||
PushDeviceToken.objects.filter(
|
||||
kind=PushDeviceToken.GCM, token__in=android_deleted_devices
|
||||
kind=PushDeviceToken.FCM, token__in=android_deleted_devices
|
||||
).delete()
|
||||
PushDeviceToken.objects.filter(
|
||||
kind=PushDeviceToken.APNS, token__in=apple_deleted_devices
|
||||
|
@ -1246,7 +1246,7 @@ def handle_remove_push_notification(user_profile_id: int, message_ids: List[int]
|
|||
apns_payload = get_remove_payload_apns(user_profile, truncated_message_ids)
|
||||
|
||||
android_devices = list(
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.GCM).order_by("id")
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.FCM).order_by("id")
|
||||
)
|
||||
apple_devices = list(
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.APNS).order_by("id")
|
||||
|
@ -1416,7 +1416,7 @@ def handle_push_notification(user_profile_id: int, missed_message: Dict[str, Any
|
|||
logger.info("Sending push notifications to mobile clients for user %s", user_profile_id)
|
||||
|
||||
android_devices = list(
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.GCM).order_by("id")
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.FCM).order_by("id")
|
||||
)
|
||||
|
||||
apple_devices = list(
|
||||
|
@ -1462,7 +1462,7 @@ def send_test_push_notification_directly_to_devices(
|
|||
payload["event"] = "test"
|
||||
|
||||
apple_devices = [device for device in devices if device.kind == PushDeviceToken.APNS]
|
||||
android_devices = [device for device in devices if device.kind == PushDeviceToken.GCM]
|
||||
android_devices = [device for device in devices if device.kind == PushDeviceToken.FCM]
|
||||
# Let's make the payloads separate objects to make sure mutating to make e.g. Android
|
||||
# adjustments doesn't affect the Apple payload and vice versa.
|
||||
apple_payload = copy.deepcopy(payload)
|
||||
|
|
|
@ -2572,6 +2572,6 @@ class BouncerTestCase(ZulipTestCase):
|
|||
def get_generic_payload(self, method: str = "register") -> Dict[str, Any]:
|
||||
user_id = 10
|
||||
token = "111222"
|
||||
token_kind = PushDeviceToken.GCM
|
||||
token_kind = PushDeviceToken.FCM
|
||||
|
||||
return {"user_id": user_id, "token": token, "token_kind": token_kind}
|
||||
|
|
|
@ -9,11 +9,13 @@ from zerver.models.users import UserProfile
|
|||
|
||||
class AbstractPushDeviceToken(models.Model):
|
||||
APNS = 1
|
||||
GCM = 2
|
||||
FCM = 2
|
||||
|
||||
KINDS = (
|
||||
(APNS, "apns"),
|
||||
(GCM, "gcm"),
|
||||
# The string value in the database is "gcm" for legacy reasons.
|
||||
# TODO: We should migrate it.
|
||||
(FCM, "gcm"),
|
||||
)
|
||||
|
||||
kind = models.PositiveSmallIntegerField(choices=KINDS)
|
||||
|
@ -21,7 +23,7 @@ class AbstractPushDeviceToken(models.Model):
|
|||
# The token is a unique device-specific token that is
|
||||
# sent to us from each device:
|
||||
# - APNS token if kind == APNS
|
||||
# - GCM registration id if kind == GCM
|
||||
# - FCM registration id if kind == FCM
|
||||
token = models.CharField(max_length=4096, db_index=True)
|
||||
|
||||
# TODO: last_updated should be renamed date_created, since it is
|
||||
|
|
|
@ -417,7 +417,7 @@ class RateLimitTests(ZulipTestCase):
|
|||
server.save()
|
||||
|
||||
endpoint = "/api/v1/remotes/push/register"
|
||||
payload = {"user_id": 10, "token": "111222", "token_kind": PushDeviceToken.GCM}
|
||||
payload = {"user_id": 10, "token": "111222", "token_kind": PushDeviceToken.FCM}
|
||||
try:
|
||||
# Remote servers can only make requests to the root subdomain.
|
||||
original_default_subdomain = self.DEFAULT_SUBDOMAIN
|
||||
|
|
|
@ -137,7 +137,7 @@ class SendTestPushNotificationEndpointTest(BouncerTestCase):
|
|||
"user_uuid": str(user.uuid),
|
||||
"user_id": user.id,
|
||||
"token": "invalid",
|
||||
"token_kind": PushDeviceToken.GCM,
|
||||
"token_kind": PushDeviceToken.FCM,
|
||||
"base_payload": get_base_payload(user),
|
||||
}
|
||||
result = self.uuid_post(
|
||||
|
@ -154,7 +154,7 @@ class SendTestPushNotificationEndpointTest(BouncerTestCase):
|
|||
# server, but for some reason the server failed to register it with the bouncer.
|
||||
|
||||
token = "111222"
|
||||
token_kind = PushDeviceToken.GCM
|
||||
token_kind = PushDeviceToken.FCM
|
||||
# We create a PushDeviceToken object, but no RemotePushDeviceToken object, to simulate
|
||||
# a missing registration on the bouncer.
|
||||
PushDeviceToken.objects.create(user=user, token=token, kind=token_kind)
|
||||
|
@ -183,7 +183,7 @@ class SendTestPushNotificationEndpointTest(BouncerTestCase):
|
|||
user = self.example_user("cordelia")
|
||||
|
||||
android_token = "111222"
|
||||
android_token_kind = PushDeviceToken.GCM
|
||||
android_token_kind = PushDeviceToken.FCM
|
||||
apple_token = "111223"
|
||||
apple_token_kind = PushDeviceToken.APNS
|
||||
android_device = PushDeviceToken.objects.create(
|
||||
|
@ -302,7 +302,7 @@ class SendTestPushNotificationEndpointTest(BouncerTestCase):
|
|||
remote_realm = RemoteRealm.objects.get(server=server, uuid=user.realm.uuid)
|
||||
|
||||
token = "111222"
|
||||
token_kind = PushDeviceToken.GCM
|
||||
token_kind = PushDeviceToken.FCM
|
||||
PushDeviceToken.objects.create(user=user, token=token, kind=token_kind)
|
||||
remote_device = RemotePushDeviceToken.objects.create(
|
||||
server=server, user_uuid=str(user.uuid), token=token, kind=token_kind
|
||||
|
@ -344,7 +344,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
|
||||
def test_unregister_remote_push_user_params(self) -> None:
|
||||
token = "111222"
|
||||
token_kind = PushDeviceToken.GCM
|
||||
token_kind = PushDeviceToken.FCM
|
||||
|
||||
endpoint = "/api/v1/remotes/push/unregister"
|
||||
result = self.uuid_post(self.server_uuid, endpoint, {"token_kind": token_kind})
|
||||
|
@ -380,7 +380,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
def test_register_remote_push_user_params(self) -> None:
|
||||
token = "111222"
|
||||
user_id = 11
|
||||
token_kind = PushDeviceToken.GCM
|
||||
token_kind = PushDeviceToken.FCM
|
||||
|
||||
endpoint = "/api/v1/remotes/push/register"
|
||||
|
||||
|
@ -497,7 +497,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
result = self.uuid_post(
|
||||
self.server_uuid,
|
||||
endpoint,
|
||||
{**args, "token_kind": PushDeviceToken.GCM},
|
||||
{**args, "token_kind": PushDeviceToken.FCM},
|
||||
)
|
||||
self.assert_json_success(result)
|
||||
|
||||
|
@ -522,7 +522,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
token = "111222"
|
||||
user_id = hamlet.id
|
||||
user_uuid = str(hamlet.uuid)
|
||||
token_kind = PushDeviceToken.GCM
|
||||
token_kind = PushDeviceToken.FCM
|
||||
|
||||
endpoint = "/api/v1/remotes/push/register"
|
||||
|
||||
|
@ -581,7 +581,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
remote_realm = RemoteRealm.objects.get(server=server, uuid=hamlet.realm.uuid)
|
||||
|
||||
android_token = RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64("aaaa"),
|
||||
user_uuid=hamlet.uuid,
|
||||
server=server,
|
||||
|
@ -631,7 +631,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
for i in ["aa", "bb"]:
|
||||
android_tokens.append(
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64(token + i),
|
||||
user_id=hamlet.id,
|
||||
server=server,
|
||||
|
@ -643,7 +643,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
# and will delete the old, legacy registration.
|
||||
uuid_android_tokens.append(
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64(token + i),
|
||||
user_uuid=str(hamlet.uuid),
|
||||
server=server,
|
||||
|
@ -741,7 +741,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
hamlet = self.example_user("hamlet")
|
||||
remote_server = self.server
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64("aaaaaa"),
|
||||
user_id=hamlet.id,
|
||||
server=remote_server,
|
||||
|
@ -952,7 +952,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
def test_subsecond_timestamp_format(self) -> None:
|
||||
hamlet = self.example_user("hamlet")
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64("aaaaaa"),
|
||||
user_id=hamlet.id,
|
||||
server=self.server,
|
||||
|
@ -1164,7 +1164,7 @@ class PushBouncerNotificationTest(BouncerTestCase):
|
|||
RemotePushDeviceToken.APNS,
|
||||
{"appid": "org.zulip.Zulip"},
|
||||
),
|
||||
("/json/users/me/android_gcm_reg_id", "android-token", RemotePushDeviceToken.GCM, {}),
|
||||
("/json/users/me/android_gcm_reg_id", "android-token", RemotePushDeviceToken.FCM, {}),
|
||||
]
|
||||
|
||||
# Test error handling
|
||||
|
@ -2757,7 +2757,7 @@ class PushNotificationTest(BouncerTestCase):
|
|||
self.gcm_tokens = ["1111", "2222"]
|
||||
for token in self.gcm_tokens:
|
||||
PushDeviceToken.objects.create(
|
||||
kind=PushDeviceToken.GCM,
|
||||
kind=PushDeviceToken.FCM,
|
||||
token=hex_to_b64(token),
|
||||
user=self.user_profile,
|
||||
ios_app_id=None,
|
||||
|
@ -2766,13 +2766,13 @@ class PushNotificationTest(BouncerTestCase):
|
|||
self.remote_gcm_tokens = [("dddd", "eeee")]
|
||||
for id_token, uuid_token in self.remote_gcm_tokens:
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64(id_token),
|
||||
user_id=self.user_profile.id,
|
||||
server=self.server,
|
||||
)
|
||||
RemotePushDeviceToken.objects.create(
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
token=hex_to_b64(uuid_token),
|
||||
user_uuid=self.user_profile.uuid,
|
||||
server=self.server,
|
||||
|
@ -2835,7 +2835,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
]
|
||||
gcm_devices = [
|
||||
(b64_to_hex(device.token), device.ios_app_id, device.token)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.GCM)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.FCM)
|
||||
]
|
||||
mock_gcm.json_request.return_value = {
|
||||
"success": {device[2]: message.id for device in gcm_devices}
|
||||
|
@ -2995,7 +2995,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
]
|
||||
gcm_devices = [
|
||||
(b64_to_hex(device.token), device.ios_app_id, device.token)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.GCM)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.FCM)
|
||||
]
|
||||
|
||||
# Reset the local registrations for the user to make them compatible
|
||||
|
@ -3010,15 +3010,15 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.APNS)
|
||||
]
|
||||
PushDeviceToken.objects.filter(kind=PushDeviceToken.GCM).delete()
|
||||
PushDeviceToken.objects.filter(kind=PushDeviceToken.FCM).delete()
|
||||
[
|
||||
PushDeviceToken.objects.create(
|
||||
kind=PushDeviceToken.GCM,
|
||||
kind=PushDeviceToken.FCM,
|
||||
token=device.token,
|
||||
user=self.user_profile,
|
||||
ios_app_id=device.ios_app_id,
|
||||
)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.GCM)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.FCM)
|
||||
]
|
||||
|
||||
mock_gcm.json_request.return_value = {"success": {gcm_devices[0][2]: message.id}}
|
||||
|
@ -3085,7 +3085,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
with mock.patch("zerver.lib.push_notifications.gcm_client") as mock_gcm:
|
||||
gcm_devices = [
|
||||
(b64_to_hex(device.token), device.ios_app_id, device.token)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.GCM)
|
||||
for device in RemotePushDeviceToken.objects.filter(kind=PushDeviceToken.FCM)
|
||||
]
|
||||
mock_gcm.json_request.return_value = {"success": {gcm_devices[0][2]: message.id}}
|
||||
with self.assertRaises(PushNotificationBouncerRetryLaterError):
|
||||
|
@ -3249,7 +3249,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
"gcm_payload": {"gcm": True},
|
||||
"gcm_options": {},
|
||||
"android_devices": list(
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.GCM)
|
||||
PushDeviceToken.objects.filter(user=user_profile, kind=PushDeviceToken.FCM)
|
||||
.order_by("id")
|
||||
.values_list("token", flat=True)
|
||||
),
|
||||
|
@ -3283,7 +3283,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
)
|
||||
|
||||
android_devices = list(
|
||||
PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.GCM)
|
||||
PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.FCM)
|
||||
)
|
||||
|
||||
apple_devices = list(
|
||||
|
@ -3377,7 +3377,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
{"priority": "normal"},
|
||||
list(
|
||||
PushDeviceToken.objects.filter(
|
||||
user=user_profile, kind=PushDeviceToken.GCM
|
||||
user=user_profile, kind=PushDeviceToken.FCM
|
||||
).order_by("id")
|
||||
),
|
||||
list(
|
||||
|
@ -3404,7 +3404,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
)
|
||||
|
||||
android_devices = list(
|
||||
PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.GCM)
|
||||
PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.FCM)
|
||||
)
|
||||
|
||||
apple_devices = list(
|
||||
|
@ -3544,7 +3544,7 @@ class HandlePushNotificationTest(PushNotificationTest):
|
|||
}
|
||||
|
||||
android_devices = list(
|
||||
PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.GCM)
|
||||
PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.FCM)
|
||||
)
|
||||
|
||||
apple_devices = list(
|
||||
|
@ -4504,7 +4504,7 @@ class TestSendNotificationsToBouncer(PushNotificationTest):
|
|||
self.setup_apns_tokens()
|
||||
self.setup_gcm_tokens()
|
||||
|
||||
android_devices = PushDeviceToken.objects.filter(kind=PushDeviceToken.GCM)
|
||||
android_devices = PushDeviceToken.objects.filter(kind=PushDeviceToken.FCM)
|
||||
apple_devices = PushDeviceToken.objects.filter(kind=PushDeviceToken.APNS)
|
||||
|
||||
self.assertNotEqual(android_devices.count(), 0)
|
||||
|
@ -4560,7 +4560,7 @@ class TestSendNotificationsToBouncer(PushNotificationTest):
|
|||
)
|
||||
|
||||
self.assertEqual(PushDeviceToken.objects.filter(kind=PushDeviceToken.APNS).count(), 0)
|
||||
self.assertEqual(PushDeviceToken.objects.filter(kind=PushDeviceToken.GCM).count(), 0)
|
||||
self.assertEqual(PushDeviceToken.objects.filter(kind=PushDeviceToken.FCM).count(), 0)
|
||||
|
||||
# Now simulating getting "can_push" as False from the bouncer and verify
|
||||
# that we update the realm value.
|
||||
|
@ -4848,7 +4848,7 @@ class GCMSendTest(PushNotificationTest):
|
|||
|
||||
def get_count(hex_token: str) -> int:
|
||||
token = hex_to_b64(hex_token)
|
||||
return PushDeviceToken.objects.filter(token=token, kind=PushDeviceToken.GCM).count()
|
||||
return PushDeviceToken.objects.filter(token=token, kind=PushDeviceToken.FCM).count()
|
||||
|
||||
self.assertEqual(get_count("1111"), 1)
|
||||
|
||||
|
|
|
@ -64,8 +64,8 @@ def add_apns_device_token(
|
|||
def add_android_reg_id(
|
||||
request: HttpRequest, user_profile: UserProfile, *, token: str
|
||||
) -> HttpResponse:
|
||||
validate_token(token, PushDeviceToken.GCM)
|
||||
add_push_device_token(user_profile, token, PushDeviceToken.GCM)
|
||||
validate_token(token, PushDeviceToken.FCM)
|
||||
add_push_device_token(user_profile, token, PushDeviceToken.FCM)
|
||||
return json_success(request)
|
||||
|
||||
|
||||
|
@ -84,8 +84,8 @@ def remove_apns_device_token(
|
|||
def remove_android_reg_id(
|
||||
request: HttpRequest, user_profile: UserProfile, *, token: str
|
||||
) -> HttpResponse:
|
||||
validate_token(token, PushDeviceToken.GCM)
|
||||
remove_push_device_token(user_profile, token, PushDeviceToken.GCM)
|
||||
validate_token(token, PushDeviceToken.FCM)
|
||||
remove_push_device_token(user_profile, token, PushDeviceToken.FCM)
|
||||
return json_success(request)
|
||||
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ def validate_uuid(uuid: str) -> None:
|
|||
|
||||
|
||||
def validate_bouncer_token_request(token: str, kind: int) -> None:
|
||||
if kind not in [RemotePushDeviceToken.APNS, RemotePushDeviceToken.GCM]:
|
||||
if kind not in [RemotePushDeviceToken.APNS, RemotePushDeviceToken.FCM]:
|
||||
raise JsonableError(err_("Invalid token type"))
|
||||
validate_token(token, kind)
|
||||
|
||||
|
@ -566,7 +566,7 @@ def remote_server_notify_push(
|
|||
android_devices = list(
|
||||
RemotePushDeviceToken.objects.filter(
|
||||
user_identity.filter_q(),
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
server=server,
|
||||
).order_by("id")
|
||||
)
|
||||
|
@ -734,7 +734,7 @@ def get_deleted_devices(
|
|||
android_devices_we_have = RemotePushDeviceToken.objects.filter(
|
||||
user_identity.filter_q(),
|
||||
token__in=android_devices,
|
||||
kind=RemotePushDeviceToken.GCM,
|
||||
kind=RemotePushDeviceToken.FCM,
|
||||
server=server,
|
||||
).values_list("token", flat=True)
|
||||
apple_devices_we_have = RemotePushDeviceToken.objects.filter(
|
||||
|
|
Loading…
Reference in New Issue