2016-07-25 22:12:12 +02:00
|
|
|
import os
|
2020-06-13 05:24:42 +02:00
|
|
|
from typing import Any, Dict, Sequence
|
2020-05-26 07:16:25 +02:00
|
|
|
from unittest import mock
|
2020-04-04 01:47:18 +02:00
|
|
|
from urllib.parse import urlsplit
|
2016-09-14 07:07:21 +02:00
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
import ujson
|
2019-08-28 06:04:21 +02:00
|
|
|
from django.conf import settings
|
2018-05-11 16:35:03 +02:00
|
|
|
from django.http import HttpResponse
|
2020-07-01 04:19:54 +02:00
|
|
|
from django.test import override_settings
|
2016-09-14 07:07:21 +02:00
|
|
|
|
2020-06-09 12:24:32 +02:00
|
|
|
from corporate.models import Customer
|
2017-11-15 22:58:34 +01:00
|
|
|
from zerver.lib.integrations import INTEGRATIONS
|
2017-03-08 12:32:41 +01:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
2016-09-28 06:06:21 +02:00
|
|
|
from zerver.lib.test_helpers import HostRequestMock
|
2017-03-08 12:43:45 +01:00
|
|
|
from zerver.lib.utils import split_by
|
2018-08-27 12:43:00 +02:00
|
|
|
from zerver.models import Realm, get_realm
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.views.documentation import add_api_uri_context
|
|
|
|
|
2016-07-25 22:12:12 +02:00
|
|
|
|
2017-03-08 12:32:41 +01:00
|
|
|
class DocPageTest(ZulipTestCase):
|
2018-05-11 16:35:03 +02:00
|
|
|
def get_doc(self, url: str, subdomain: str) -> HttpResponse:
|
|
|
|
if url[0:23] == "/integrations/doc-html/":
|
|
|
|
return self.client_get(url, subdomain=subdomain, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
|
|
|
return self.client_get(url, subdomain=subdomain)
|
|
|
|
|
2019-07-21 00:14:48 +02:00
|
|
|
def print_msg_if_error(self, url: str, response: HttpResponse) -> None: # nocoverage
|
|
|
|
if response.status_code == 200:
|
|
|
|
return
|
|
|
|
print("Error processing URL:", url)
|
|
|
|
if response.get('Content-Type') == 'application/json':
|
2018-12-23 01:37:27 +01:00
|
|
|
content = ujson.loads(response.content)
|
|
|
|
print()
|
|
|
|
print("======================================================================")
|
|
|
|
print("ERROR: {}".format(content.get('msg')))
|
|
|
|
print()
|
|
|
|
|
2020-06-13 05:24:42 +02:00
|
|
|
def _test(self, url: str, expected_content: str, extra_strings: Sequence[str]=[],
|
|
|
|
landing_missing_strings: Sequence[str]=[], landing_page: bool=True,
|
2018-05-11 16:35:03 +02:00
|
|
|
doc_html_str: bool=False) -> None:
|
2017-08-25 23:55:33 +02:00
|
|
|
|
2018-05-01 20:59:24 +02:00
|
|
|
# Test the URL on the "zephyr" subdomain
|
2018-05-11 16:35:03 +02:00
|
|
|
result = self.get_doc(url, subdomain="zephyr")
|
2019-07-21 00:14:48 +02:00
|
|
|
self.print_msg_if_error(url, result)
|
2018-12-23 01:37:27 +01:00
|
|
|
|
2017-07-13 01:28:38 +02:00
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn(expected_content, str(result.content))
|
|
|
|
for s in extra_strings:
|
|
|
|
self.assertIn(s, str(result.content))
|
2018-05-11 16:35:03 +02:00
|
|
|
if not doc_html_str:
|
2018-05-01 20:59:24 +02:00
|
|
|
self.assert_in_success_response(['<meta name="robots" content="noindex,nofollow">'], result)
|
2017-03-08 12:32:41 +01:00
|
|
|
|
2017-08-25 23:55:33 +02:00
|
|
|
# Test the URL on the root subdomain
|
2018-05-11 16:35:03 +02:00
|
|
|
result = self.get_doc(url, subdomain="")
|
2019-07-21 00:14:48 +02:00
|
|
|
self.print_msg_if_error(url, result)
|
2018-12-23 01:37:27 +01:00
|
|
|
|
2017-08-25 23:55:33 +02:00
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn(expected_content, str(result.content))
|
2018-05-11 16:35:03 +02:00
|
|
|
if not doc_html_str:
|
2018-05-01 20:59:24 +02:00
|
|
|
self.assert_in_success_response(['<meta name="robots" content="noindex,nofollow">'], result)
|
|
|
|
|
2017-08-25 23:55:33 +02:00
|
|
|
for s in extra_strings:
|
|
|
|
self.assertIn(s, str(result.content))
|
|
|
|
|
|
|
|
if not landing_page:
|
|
|
|
return
|
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
2018-05-04 21:51:05 +02:00
|
|
|
# Test the URL on the root subdomain with the landing page setting
|
2018-05-11 16:35:03 +02:00
|
|
|
result = self.get_doc(url, subdomain="")
|
2019-07-21 00:14:48 +02:00
|
|
|
self.print_msg_if_error(url, result)
|
2018-12-23 01:37:27 +01:00
|
|
|
|
2017-08-25 23:55:33 +02:00
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn(expected_content, str(result.content))
|
|
|
|
for s in extra_strings:
|
|
|
|
self.assertIn(s, str(result.content))
|
2017-11-14 02:01:44 +01:00
|
|
|
for s in landing_missing_strings:
|
|
|
|
self.assertNotIn(s, str(result.content))
|
2018-05-11 16:35:03 +02:00
|
|
|
if not doc_html_str:
|
2018-05-01 20:59:24 +02:00
|
|
|
self.assert_in_success_response(['<meta name="description" content="Zulip combines'], result)
|
2018-05-11 16:35:03 +02:00
|
|
|
self.assert_not_in_success_response(['<meta name="robots" content="noindex,nofollow">'], result)
|
2017-08-25 23:55:33 +02:00
|
|
|
|
2018-05-04 21:51:05 +02:00
|
|
|
# Test the URL on the "zephyr" subdomain with the landing page setting
|
|
|
|
result = self.get_doc(url, subdomain="zephyr")
|
2019-07-21 00:14:48 +02:00
|
|
|
self.print_msg_if_error(url, result)
|
2018-12-23 01:37:27 +01:00
|
|
|
|
2018-05-04 21:51:05 +02:00
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn(expected_content, str(result.content))
|
|
|
|
for s in extra_strings:
|
|
|
|
self.assertIn(s, str(result.content))
|
|
|
|
if not doc_html_str:
|
|
|
|
self.assert_in_success_response(['<meta name="robots" content="noindex,nofollow">'], result)
|
|
|
|
|
2019-05-16 22:38:53 +02:00
|
|
|
def test_api_doc_endpoints(self) -> None:
|
|
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
api_docs_dir = os.path.join(current_dir, '..', '..', 'templates/zerver/api/')
|
|
|
|
files = os.listdir(api_docs_dir)
|
|
|
|
|
|
|
|
def _filter_func(fp: str) -> bool:
|
|
|
|
ignored_files = ['sidebar_index.md', 'index.md', 'missing.md']
|
2019-07-21 00:14:48 +02:00
|
|
|
return fp.endswith('.md') and not fp.startswith(".") and fp not in ignored_files
|
2019-05-16 22:38:53 +02:00
|
|
|
|
|
|
|
files = list(filter(_filter_func, files))
|
|
|
|
|
|
|
|
for f in files:
|
2020-06-09 00:25:09 +02:00
|
|
|
endpoint = f'/api/{os.path.splitext(f)[0]}'
|
2019-05-16 22:38:53 +02:00
|
|
|
self._test(endpoint, '', doc_html_str=True)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_doc_endpoints(self) -> None:
|
2018-04-17 01:10:35 +02:00
|
|
|
self._test('/api/', 'The Zulip API')
|
2018-09-26 06:02:58 +02:00
|
|
|
self._test('/api/api-keys', 'be careful with it')
|
2017-11-11 02:49:43 +01:00
|
|
|
self._test('/api/installation-instructions', 'No download required!')
|
2018-06-18 17:44:48 +02:00
|
|
|
self._test('/api/send-message', 'steal away your hearts')
|
2017-12-30 05:09:16 +01:00
|
|
|
self._test('/api/render-message', '**foo**')
|
2020-06-11 14:44:00 +02:00
|
|
|
self._test('/api/get-streams', 'include_public')
|
2020-05-06 02:26:22 +02:00
|
|
|
self._test('/api/get-stream-id', 'The name of the stream to access.')
|
2020-06-11 14:44:00 +02:00
|
|
|
self._test('/api/get-subscriptions', 'Get all streams that the user is subscribed to.')
|
|
|
|
self._test('/api/get-users', 'client_gravatar')
|
2018-01-03 01:33:30 +01:00
|
|
|
self._test('/api/register-queue', 'apply_markdown')
|
2020-06-11 14:44:00 +02:00
|
|
|
self._test('/api/get-events', 'dont_block')
|
2018-01-04 21:35:32 +01:00
|
|
|
self._test('/api/delete-queue', 'Delete a previously registered queue')
|
2018-01-04 23:49:11 +01:00
|
|
|
self._test('/api/update-message', 'propagate_mode')
|
2020-06-11 14:44:00 +02:00
|
|
|
self._test('/api/get-own-user', 'takes no parameters')
|
|
|
|
self._test('/api/subscribe', 'authorization_errors_fatal')
|
2018-01-08 19:48:53 +01:00
|
|
|
self._test('/api/create-user', 'zuliprc-admin')
|
2020-06-11 14:44:00 +02:00
|
|
|
self._test('/api/unsubscribe', 'not_removed')
|
2017-10-31 20:27:56 +01:00
|
|
|
self._test('/team/', 'industry veterans')
|
2017-10-31 20:08:32 +01:00
|
|
|
self._test('/history/', 'Cambridge, Massachusetts')
|
2017-07-13 01:28:38 +02:00
|
|
|
# Test the i18n version of one of these pages.
|
2017-10-31 20:08:32 +01:00
|
|
|
self._test('/en/history/', 'Cambridge, Massachusetts')
|
2017-07-26 19:08:16 +02:00
|
|
|
self._test('/apps/', 'Apps for every platform.')
|
2017-08-02 09:09:10 +02:00
|
|
|
self._test('/features/', 'Beautiful messaging')
|
2020-03-17 22:41:05 +01:00
|
|
|
self._test('/hello/', 'Chat for distributed teams', landing_missing_strings=["Login"])
|
2018-06-01 05:41:50 +02:00
|
|
|
self._test('/why-zulip/', 'Why Zulip?')
|
2017-07-13 01:28:38 +02:00
|
|
|
self._test('/for/open-source/', 'for open source projects')
|
2020-05-21 02:57:22 +02:00
|
|
|
self._test('/for/research/', 'for researchers')
|
2017-07-30 20:14:59 +02:00
|
|
|
self._test('/for/companies/', 'in a company')
|
2017-08-01 00:19:18 +02:00
|
|
|
self._test('/for/working-groups-and-communities/', 'standards bodies')
|
2018-10-31 02:23:02 +01:00
|
|
|
self._test('/security/', 'TLS encryption')
|
2018-12-15 00:12:09 +01:00
|
|
|
self._test('/atlassian/', 'HipChat')
|
2017-08-25 23:55:33 +02:00
|
|
|
self._test('/devlogin/', 'Normal users', landing_page=False)
|
2017-07-13 01:28:38 +02:00
|
|
|
self._test('/devtools/', 'Useful development URLs')
|
|
|
|
self._test('/errors/404/', 'Page not found')
|
|
|
|
self._test('/errors/5xx/', 'Internal server error')
|
2017-10-25 01:58:05 +02:00
|
|
|
self._test('/emails/', 'manually generate most of the emails by clicking')
|
2017-03-08 12:32:41 +01:00
|
|
|
|
2018-05-11 16:35:03 +02:00
|
|
|
result = self.client_get('/integrations/doc-html/nonexistent_integration', follow=True,
|
|
|
|
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
2017-07-12 02:50:27 +02:00
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
|
2017-07-13 01:28:38 +02:00
|
|
|
result = self.client_get('/new-user/')
|
|
|
|
self.assertEqual(result.status_code, 301)
|
|
|
|
self.assertIn('hello', result['Location'])
|
2017-03-08 12:32:41 +01:00
|
|
|
|
2019-07-11 05:59:52 +02:00
|
|
|
def test_portico_pages_open_graph_metadata(self) -> None:
|
|
|
|
# Why Zulip
|
|
|
|
url = '/why-zulip/'
|
|
|
|
title = '<meta property="og:title" content="Team chat with first-class threading">'
|
|
|
|
description = '<meta property="og:description" content="Most team chats are overwhelming'
|
|
|
|
self._test(url, title, doc_html_str=True)
|
|
|
|
self._test(url, description, doc_html_str=True)
|
|
|
|
|
|
|
|
# Features
|
|
|
|
url = '/features/'
|
|
|
|
title = '<meta property="og:title" content="Zulip Features">'
|
|
|
|
description = '<meta property="og:description" content="First class threading'
|
|
|
|
self._test(url, title, doc_html_str=True)
|
|
|
|
self._test(url, description, doc_html_str=True)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_integration_doc_endpoints(self) -> None:
|
2017-11-11 00:41:55 +01:00
|
|
|
self._test('/integrations/',
|
2018-02-07 22:01:42 +01:00
|
|
|
'native integrations.',
|
2017-11-11 00:41:55 +01:00
|
|
|
extra_strings=[
|
|
|
|
'And hundreds more through',
|
|
|
|
'Hubot',
|
|
|
|
'Zapier',
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
'IFTTT',
|
2018-05-11 16:35:03 +02:00
|
|
|
])
|
2017-11-11 00:41:55 +01:00
|
|
|
|
|
|
|
for integration in INTEGRATIONS.keys():
|
2020-06-09 00:25:09 +02:00
|
|
|
url = f'/integrations/doc-html/{integration}'
|
2018-05-11 16:35:03 +02:00
|
|
|
self._test(url, '', doc_html_str=True)
|
2017-11-11 00:41:55 +01:00
|
|
|
|
2019-06-15 07:19:57 +02:00
|
|
|
def test_integration_pages_open_graph_metadata(self) -> None:
|
|
|
|
url = '/integrations/doc/github'
|
|
|
|
title = '<meta property="og:title" content="Connect GitHub to Zulip">'
|
|
|
|
description = '<meta property="og:description" content="Zulip comes with over'
|
|
|
|
self._test(url, title, doc_html_str=True)
|
|
|
|
self._test(url, description, doc_html_str=True)
|
|
|
|
|
|
|
|
# Test category pages
|
|
|
|
url = '/integrations/communication'
|
|
|
|
title = '<meta property="og:title" content="Connect your Communication tools to Zulip">'
|
|
|
|
description = '<meta property="og:description" content="Zulip comes with over'
|
|
|
|
self._test(url, title, doc_html_str=True)
|
|
|
|
self._test(url, description, doc_html_str=True)
|
2019-07-10 21:30:06 +02:00
|
|
|
|
|
|
|
# Test integrations page
|
|
|
|
url = '/integrations/'
|
|
|
|
title = '<meta property="og:title" content="Connect the tools you use to Zulip">'
|
|
|
|
description = '<meta property="og:description" content="Zulip comes with over'
|
|
|
|
self._test(url, title, doc_html_str=True)
|
|
|
|
self._test(url, description, doc_html_str=True)
|
2019-06-15 07:19:57 +02:00
|
|
|
|
2018-05-11 16:35:03 +02:00
|
|
|
def test_doc_html_str_non_ajax_call(self) -> None:
|
|
|
|
# We don't need to test all the pages for 404
|
|
|
|
for integration in list(INTEGRATIONS.keys())[5]:
|
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
2020-06-09 00:25:09 +02:00
|
|
|
url = f'/en/integrations/doc-html/{integration}'
|
2018-05-11 16:35:03 +02:00
|
|
|
result = self.client_get(url, subdomain="", follow=True)
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
result = self.client_get(url, subdomain="zephyr", follow=True)
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
|
2020-06-09 00:25:09 +02:00
|
|
|
url = f'/en/integrations/doc-html/{integration}'
|
2018-05-11 16:35:03 +02:00
|
|
|
result = self.client_get(url, subdomain="", follow=True)
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
result = self.client_get(url, subdomain="zephyr", follow=True)
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
|
|
|
|
result = self.client_get('/integrations/doc-html/nonexistent_integration', follow=True)
|
|
|
|
self.assertEqual(result.status_code, 404)
|
2018-01-25 23:38:57 +01:00
|
|
|
|
2019-03-12 15:32:33 +01:00
|
|
|
def test_electron_detection(self) -> None:
|
|
|
|
result = self.client_get("/accounts/password/reset/")
|
2020-03-08 21:12:38 +01:00
|
|
|
# TODO: Ideally, this Mozilla would be the specific browser.
|
|
|
|
self.assertTrue('data-platform="Mozilla"' in result.content.decode("utf-8"))
|
2019-03-12 15:32:33 +01:00
|
|
|
|
|
|
|
result = self.client_get("/accounts/password/reset/",
|
|
|
|
HTTP_USER_AGENT="ZulipElectron/1.0.0")
|
|
|
|
self.assertTrue('data-platform="ZulipElectron"' in result.content.decode("utf-8"))
|
|
|
|
|
2018-04-05 21:20:17 +02:00
|
|
|
class HelpTest(ZulipTestCase):
|
2018-09-15 06:17:04 +02:00
|
|
|
def test_help_settings_links(self) -> None:
|
2018-05-14 21:32:44 +02:00
|
|
|
result = self.client_get('/help/change-the-time-format')
|
2018-04-18 04:31:57 +02:00
|
|
|
self.assertEqual(result.status_code, 200)
|
2018-12-06 19:11:02 +01:00
|
|
|
self.assertIn('Go to <a href="/#settings/display-settings">Display settings</a>', str(result.content))
|
|
|
|
# Check that the sidebar was rendered properly.
|
|
|
|
self.assertIn('Getting started with Zulip', str(result.content))
|
2018-04-18 04:31:57 +02:00
|
|
|
|
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
2018-09-15 06:17:04 +02:00
|
|
|
result = self.client_get('/help/change-the-time-format', subdomain="")
|
2018-04-18 04:31:57 +02:00
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn('<strong>Display settings</strong>', str(result.content))
|
2018-09-15 06:17:04 +02:00
|
|
|
self.assertNotIn('/#settings', str(result.content))
|
|
|
|
|
2018-09-16 04:30:18 +02:00
|
|
|
def test_help_relative_links_for_gear(self) -> None:
|
2018-09-15 06:17:04 +02:00
|
|
|
result = self.client_get('/help/analytics')
|
|
|
|
self.assertIn('<a href="/stats">Statistics</a>', str(result.content))
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
|
|
|
result = self.client_get('/help/analytics', subdomain="")
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn('<strong>Statistics</strong>', str(result.content))
|
|
|
|
self.assertNotIn('/stats', str(result.content))
|
2018-04-18 04:31:57 +02:00
|
|
|
|
2018-09-16 04:30:18 +02:00
|
|
|
def test_help_relative_links_for_stream(self) -> None:
|
|
|
|
result = self.client_get('/help/message-a-stream-by-email')
|
|
|
|
self.assertIn('<a href="/#streams/subscribed">Your streams</a>', str(result.content))
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
|
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
|
|
|
result = self.client_get('/help/message-a-stream-by-email', subdomain="")
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assertIn('<strong>Manage streams</strong>', str(result.content))
|
|
|
|
self.assertNotIn('/#streams', str(result.content))
|
|
|
|
|
2020-07-01 04:19:54 +02:00
|
|
|
class IntegrationTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_check_if_every_integration_has_logo_that_exists(self) -> None:
|
2016-07-25 22:12:12 +02:00
|
|
|
for integration in INTEGRATIONS.values():
|
2020-04-04 01:47:18 +02:00
|
|
|
path = urlsplit(integration.logo_url).path
|
|
|
|
self.assertTrue(os.path.isfile(settings.DEPLOY_ROOT + path), integration.name)
|
2016-11-23 18:58:59 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api_url_view_subdomains_base(self) -> None:
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
context: Dict[str, Any] = dict()
|
2017-08-24 05:27:21 +02:00
|
|
|
add_api_uri_context(context, HostRequestMock())
|
2017-10-30 22:04:15 +01:00
|
|
|
self.assertEqual(context["api_url_scheme_relative"], "testserver/api")
|
|
|
|
self.assertEqual(context["api_url"], "http://testserver/api")
|
2017-08-24 05:27:21 +02:00
|
|
|
self.assertTrue(context["html_settings_links"])
|
|
|
|
|
2017-08-25 04:32:16 +02:00
|
|
|
@override_settings(ROOT_DOMAIN_LANDING_PAGE=True)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api_url_view_subdomains_homepage_base(self) -> None:
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
context: Dict[str, Any] = dict()
|
2016-07-19 14:35:08 +02:00
|
|
|
add_api_uri_context(context, HostRequestMock())
|
2017-10-30 22:04:15 +01:00
|
|
|
self.assertEqual(context["api_url_scheme_relative"], "yourZulipDomain.testserver/api")
|
|
|
|
self.assertEqual(context["api_url"], "http://yourZulipDomain.testserver/api")
|
2017-02-28 07:18:45 +01:00
|
|
|
self.assertFalse(context["html_settings_links"])
|
2016-07-19 14:35:08 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_api_url_view_subdomains_full(self) -> None:
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
context: Dict[str, Any] = dict()
|
2016-10-06 01:42:24 +02:00
|
|
|
request = HostRequestMock(host="mysubdomain.testserver")
|
2016-07-19 14:35:08 +02:00
|
|
|
add_api_uri_context(context, request)
|
2017-10-30 22:04:15 +01:00
|
|
|
self.assertEqual(context["api_url_scheme_relative"], "mysubdomain.testserver/api")
|
|
|
|
self.assertEqual(context["api_url"], "http://mysubdomain.testserver/api")
|
2017-02-28 07:18:45 +01:00
|
|
|
self.assertTrue(context["html_settings_links"])
|
|
|
|
|
2018-04-05 20:31:43 +02:00
|
|
|
def test_html_settings_links(self) -> None:
|
python: Convert assignment type annotations to Python 3.6 style.
This commit was split by tabbott; this piece covers the vast majority
of files in Zulip, but excludes scripts/, tools/, and puppet/ to help
ensure we at least show the right error messages for Xenial systems.
We can likely further refine the remaining pieces with some testing.
Generated by com2ann, with whitespace fixes and various manual fixes
for runtime issues:
- invoiced_through: Optional[LicenseLedger] = models.ForeignKey(
+ invoiced_through: Optional["LicenseLedger"] = models.ForeignKey(
-_apns_client: Optional[APNsClient] = None
+_apns_client: Optional["APNsClient"] = None
- notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- signup_notifications_stream: Optional[Stream] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
+ signup_notifications_stream: Optional["Stream"] = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE)
- author: Optional[UserProfile] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
+ author: Optional["UserProfile"] = models.ForeignKey('UserProfile', blank=True, null=True, on_delete=CASCADE)
- bot_owner: Optional[UserProfile] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
+ bot_owner: Optional["UserProfile"] = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
- default_sending_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
- default_events_register_stream: Optional[Stream] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_sending_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
+ default_events_register_stream: Optional["Stream"] = models.ForeignKey('zerver.Stream', null=True, related_name='+', on_delete=CASCADE)
-descriptors_by_handler_id: Dict[int, ClientDescriptor] = {}
+descriptors_by_handler_id: Dict[int, "ClientDescriptor"] = {}
-worker_classes: Dict[str, Type[QueueProcessingWorker]] = {}
-queues: Dict[str, Dict[str, Type[QueueProcessingWorker]]] = {}
+worker_classes: Dict[str, Type["QueueProcessingWorker"]] = {}
+queues: Dict[str, Dict[str, Type["QueueProcessingWorker"]]] = {}
-AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional[LDAPSearch] = None
+AUTH_LDAP_REVERSE_EMAIL_SEARCH: Optional["LDAPSearch"] = None
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-22 01:09:50 +02:00
|
|
|
context: Dict[str, Any] = dict()
|
2018-04-05 20:31:43 +02:00
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
|
|
|
add_api_uri_context(context, HostRequestMock())
|
2017-02-28 07:18:45 +01:00
|
|
|
self.assertEqual(
|
|
|
|
context['settings_html'],
|
|
|
|
'Zulip settings page')
|
|
|
|
self.assertEqual(
|
|
|
|
context['subscriptions_html'],
|
2017-03-09 00:20:22 +01:00
|
|
|
'streams page')
|
2017-02-28 07:18:45 +01:00
|
|
|
|
|
|
|
context = dict()
|
2018-04-05 20:31:43 +02:00
|
|
|
with self.settings(ROOT_DOMAIN_LANDING_PAGE=True):
|
|
|
|
add_api_uri_context(context, HostRequestMock(host="mysubdomain.testserver"))
|
|
|
|
self.assertEqual(
|
|
|
|
context['settings_html'],
|
2018-04-05 23:39:35 +02:00
|
|
|
'<a href="/#settings">Zulip settings page</a>')
|
2018-04-05 20:31:43 +02:00
|
|
|
self.assertEqual(
|
|
|
|
context['subscriptions_html'],
|
2018-04-05 23:39:35 +02:00
|
|
|
'<a target="_blank" href="/#streams">streams page</a>')
|
2018-04-05 20:31:43 +02:00
|
|
|
|
|
|
|
context = dict()
|
|
|
|
add_api_uri_context(context, HostRequestMock())
|
2017-02-28 07:18:45 +01:00
|
|
|
self.assertEqual(
|
|
|
|
context['settings_html'],
|
2018-04-05 23:39:35 +02:00
|
|
|
'<a href="/#settings">Zulip settings page</a>')
|
2017-02-28 07:18:45 +01:00
|
|
|
self.assertEqual(
|
|
|
|
context['subscriptions_html'],
|
2018-04-05 23:39:35 +02:00
|
|
|
'<a target="_blank" href="/#streams">streams page</a>')
|
2017-03-08 12:33:50 +01:00
|
|
|
|
2017-07-27 03:05:45 +02:00
|
|
|
class AboutPageTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_endpoint(self) -> None:
|
2020-04-08 22:08:04 +02:00
|
|
|
with self.settings(CONTRIBUTOR_DATA_FILE_PATH="zerver/tests/fixtures/authors.json"):
|
|
|
|
result = self.client_get('/team/')
|
2017-11-17 19:50:55 +01:00
|
|
|
self.assert_in_success_response(['Our amazing community'], result)
|
2020-04-07 19:27:07 +02:00
|
|
|
self.assert_in_success_response(['2017-11-20'], result)
|
|
|
|
self.assert_in_success_response(['timabbott', 'showell', 'gnprice', 'rishig'], result)
|
|
|
|
|
|
|
|
with mock.patch("zerver.views.portico.open", side_effect=FileNotFoundError) as m:
|
|
|
|
result = self.client_get('/team/')
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
self.assert_in_success_response(['Never ran'], result)
|
|
|
|
m.called_once()
|
|
|
|
|
|
|
|
with self.settings(ZILENCER_ENABLED=False):
|
|
|
|
result = self.client_get('/team/')
|
|
|
|
self.assertEqual(result.status_code, 301)
|
2020-06-08 23:04:39 +02:00
|
|
|
self.assertEqual(result["Location"], "https://zulip.com/team/")
|
2017-03-08 12:43:45 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_split_by(self) -> None:
|
2017-03-08 12:43:45 +01:00
|
|
|
"""Utility function primarily used in authors page"""
|
2017-07-27 03:05:45 +02:00
|
|
|
flat_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
|
|
expected_result = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
|
|
|
self.assertEqual(split_by(flat_list, 3, None), expected_result)
|
2017-08-07 17:38:25 +02:00
|
|
|
|
2020-02-15 19:16:16 +01:00
|
|
|
class SmtpConfigErrorTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_smtp_error(self) -> None:
|
2017-08-17 18:27:36 +02:00
|
|
|
result = self.client_get("/config-error/smtp")
|
|
|
|
self.assertEqual(result.status_code, 200)
|
2017-10-25 01:58:05 +02:00
|
|
|
self.assert_in_success_response(["email configuration"], result)
|
2018-02-21 06:31:53 +01:00
|
|
|
|
2018-08-27 12:43:00 +02:00
|
|
|
class PlansPageTest(ZulipTestCase):
|
|
|
|
def test_plans_auth(self) -> None:
|
2020-07-15 22:18:32 +02:00
|
|
|
root_domain = ""
|
|
|
|
result = self.client_get("/plans/", subdomain=root_domain)
|
2018-08-27 12:43:00 +02:00
|
|
|
self.assert_in_success_response(["Sign up now"], result)
|
2020-07-15 22:18:32 +02:00
|
|
|
|
|
|
|
non_existent_domain = "moo"
|
|
|
|
result = self.client_get("/plans/", subdomain=non_existent_domain)
|
2019-03-12 01:56:52 +01:00
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
self.assert_in_response("does not exist", result)
|
2020-07-15 22:18:32 +02:00
|
|
|
|
2018-08-28 01:32:52 +02:00
|
|
|
realm = get_realm("zulip")
|
2018-10-24 06:09:01 +02:00
|
|
|
realm.plan_type = Realm.STANDARD_FREE
|
2018-08-28 01:32:52 +02:00
|
|
|
realm.save(update_fields=["plan_type"])
|
2018-08-27 12:43:00 +02:00
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
|
|
|
self.assertEqual(result.status_code, 302)
|
2018-12-04 02:12:08 +01:00
|
|
|
self.assertEqual(result["Location"], "/accounts/login/?next=plans")
|
2020-07-15 22:18:32 +02:00
|
|
|
|
|
|
|
guest_user = 'polonius'
|
|
|
|
self.login(guest_user)
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip", follow=True)
|
|
|
|
self.assertEqual(result.status_code, 404)
|
|
|
|
|
|
|
|
organization_member = 'hamlet'
|
|
|
|
self.login(organization_member)
|
2018-08-27 12:43:00 +02:00
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
2018-08-15 18:05:07 +02:00
|
|
|
self.assert_in_success_response(["Current plan"], result)
|
2018-08-27 12:43:00 +02:00
|
|
|
# Test root domain, with login on different domain
|
|
|
|
result = self.client_get("/plans/", subdomain="")
|
|
|
|
# TODO: works in manual testing, but I suspect something is funny in
|
|
|
|
# the test environment
|
|
|
|
# self.assert_in_success_response(["Sign up now"], result)
|
2018-08-15 18:05:07 +02:00
|
|
|
|
|
|
|
def test_CTA_text_by_plan_type(self) -> None:
|
|
|
|
sign_up_now = "Sign up now"
|
2018-10-24 06:09:01 +02:00
|
|
|
buy_standard = "Buy Standard"
|
2018-08-15 18:05:07 +02:00
|
|
|
current_plan = "Current plan"
|
2020-06-09 12:24:32 +02:00
|
|
|
sponsorship_pending = "Sponsorship pending"
|
2018-08-15 18:05:07 +02:00
|
|
|
|
|
|
|
# Root domain
|
|
|
|
result = self.client_get("/plans/", subdomain="")
|
2018-10-24 06:09:01 +02:00
|
|
|
self.assert_in_success_response([sign_up_now, buy_standard], result)
|
2020-06-09 12:24:32 +02:00
|
|
|
self.assert_not_in_success_response([current_plan, sponsorship_pending], result)
|
2018-08-15 18:05:07 +02:00
|
|
|
|
|
|
|
realm = get_realm("zulip")
|
2018-08-28 01:32:52 +02:00
|
|
|
realm.plan_type = Realm.SELF_HOSTED
|
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
|
2019-07-23 02:33:45 +02:00
|
|
|
with self.settings(PRODUCTION=True):
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
|
|
|
self.assertEqual(result.status_code, 302)
|
2020-06-08 23:04:39 +02:00
|
|
|
self.assertEqual(result["Location"], "https://zulip.com/plans")
|
2019-07-23 02:33:45 +02:00
|
|
|
|
2020-03-06 18:40:46 +01:00
|
|
|
self.login('iago')
|
2019-07-23 02:33:45 +02:00
|
|
|
|
|
|
|
# SELF_HOSTED should hide the local plans page, even if logged in
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
|
|
|
self.assertEqual(result.status_code, 302)
|
2020-06-08 23:04:39 +02:00
|
|
|
self.assertEqual(result["Location"], "https://zulip.com/plans")
|
2018-08-28 01:32:52 +02:00
|
|
|
|
2019-07-23 02:33:45 +02:00
|
|
|
# But in the development environment, it renders a page
|
2018-08-28 01:32:52 +02:00
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
2019-07-23 02:33:45 +02:00
|
|
|
self.assert_in_success_response([sign_up_now, buy_standard], result)
|
2020-06-09 12:24:32 +02:00
|
|
|
self.assert_not_in_success_response([current_plan, sponsorship_pending], result)
|
2018-08-15 18:05:07 +02:00
|
|
|
|
|
|
|
realm.plan_type = Realm.LIMITED
|
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
2018-10-24 06:09:01 +02:00
|
|
|
self.assert_in_success_response([current_plan, buy_standard], result)
|
2020-06-09 12:24:32 +02:00
|
|
|
self.assert_not_in_success_response([sign_up_now, sponsorship_pending], result)
|
2018-08-15 18:05:07 +02:00
|
|
|
|
2018-10-24 06:09:01 +02:00
|
|
|
realm.plan_type = Realm.STANDARD_FREE
|
2018-08-15 18:05:07 +02:00
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
|
|
|
self.assert_in_success_response([current_plan], result)
|
2020-06-09 12:24:32 +02:00
|
|
|
self.assert_not_in_success_response([sign_up_now, buy_standard, sponsorship_pending], result)
|
2018-08-15 18:05:07 +02:00
|
|
|
|
2018-10-24 06:09:01 +02:00
|
|
|
realm.plan_type = Realm.STANDARD
|
2018-08-15 18:05:07 +02:00
|
|
|
realm.save(update_fields=["plan_type"])
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
|
|
|
self.assert_in_success_response([current_plan], result)
|
2020-06-09 12:24:32 +02:00
|
|
|
self.assert_not_in_success_response([sign_up_now, buy_standard, sponsorship_pending], result)
|
|
|
|
|
|
|
|
realm.plan_type = Realm.LIMITED
|
|
|
|
realm.save()
|
|
|
|
Customer.objects.create(realm=get_realm("zulip"), stripe_customer_id="cus_id", sponsorship_pending=True)
|
|
|
|
result = self.client_get("/plans/", subdomain="zulip")
|
|
|
|
self.assert_in_success_response([current_plan], result)
|
|
|
|
self.assert_in_success_response([current_plan, sponsorship_pending], result)
|
2018-10-24 06:09:01 +02:00
|
|
|
self.assert_not_in_success_response([sign_up_now, buy_standard], result)
|
2020-01-29 20:41:23 +01:00
|
|
|
|
|
|
|
class AppsPageTest(ZulipTestCase):
|
|
|
|
def test_apps_view(self) -> None:
|
|
|
|
result = self.client_get('/apps')
|
|
|
|
self.assertEqual(result.status_code, 301)
|
|
|
|
self.assertTrue(result['Location'].endswith('/apps/'))
|
|
|
|
|
|
|
|
with self.settings(ZILENCER_ENABLED=False):
|
|
|
|
result = self.client_get('/apps/')
|
|
|
|
self.assertEqual(result.status_code, 301)
|
2020-06-08 23:04:39 +02:00
|
|
|
self.assertTrue(result['Location'] == 'https://zulip.com/apps/')
|
2020-01-29 20:41:23 +01:00
|
|
|
|
|
|
|
with self.settings(ZILENCER_ENABLED=True):
|
|
|
|
result = self.client_get('/apps/')
|
|
|
|
self.assertEqual(result.status_code, 200)
|
|
|
|
html = result.content.decode('utf-8')
|
|
|
|
self.assertIn('Apps for every platform.', html)
|
|
|
|
|
|
|
|
class PrivacyTermsTest(ZulipTestCase):
|
|
|
|
def test_custom_tos_template(self) -> None:
|
|
|
|
response = self.client_get("/terms/")
|
|
|
|
|
2020-04-09 21:51:58 +02:00
|
|
|
self.assert_in_success_response(["Thanks for using our products and services (\"Services\"). ",
|
|
|
|
"By using our Services, you are agreeing to these terms"],
|
2020-01-29 20:41:23 +01:00
|
|
|
response)
|
|
|
|
|
|
|
|
def test_custom_terms_of_service_template(self) -> None:
|
|
|
|
not_configured_message = 'This installation of Zulip does not have a configured ' \
|
|
|
|
'terms of service'
|
|
|
|
with self.settings(TERMS_OF_SERVICE=None):
|
|
|
|
response = self.client_get('/terms/')
|
|
|
|
self.assert_in_success_response([not_configured_message], response)
|
|
|
|
with self.settings(TERMS_OF_SERVICE='zerver/tests/markdown/test_markdown.md'):
|
|
|
|
response = self.client_get('/terms/')
|
|
|
|
self.assert_in_success_response(['This is some <em>bold text</em>.'], response)
|
|
|
|
self.assert_not_in_success_response([not_configured_message], response)
|
|
|
|
|
|
|
|
def test_custom_privacy_policy_template(self) -> None:
|
|
|
|
not_configured_message = 'This installation of Zulip does not have a configured ' \
|
|
|
|
'privacy policy'
|
|
|
|
with self.settings(PRIVACY_POLICY=None):
|
|
|
|
response = self.client_get('/privacy/')
|
|
|
|
self.assert_in_success_response([not_configured_message], response)
|
|
|
|
with self.settings(PRIVACY_POLICY='zerver/tests/markdown/test_markdown.md'):
|
|
|
|
response = self.client_get('/privacy/')
|
|
|
|
self.assert_in_success_response(['This is some <em>bold text</em>.'], response)
|
|
|
|
self.assert_not_in_success_response([not_configured_message], response)
|
|
|
|
|
|
|
|
def test_custom_privacy_policy_template_with_absolute_url(self) -> None:
|
|
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
abs_path = os.path.join(current_dir, '..', '..',
|
|
|
|
'templates/zerver/tests/markdown/test_markdown.md')
|
|
|
|
with self.settings(PRIVACY_POLICY=abs_path):
|
|
|
|
response = self.client_get('/privacy/')
|
|
|
|
self.assert_in_success_response(['This is some <em>bold text</em>.'], response)
|
2020-01-29 00:05:06 +01:00
|
|
|
|
|
|
|
def test_no_nav(self) -> None:
|
|
|
|
# Test that our ?nav=0 feature of /privacy and /terms,
|
|
|
|
# designed to comply with the Apple App Store draconian
|
|
|
|
# policies that ToS/Privacy pages linked from an iOS app have
|
|
|
|
# no links to the rest of the site if there's pricing
|
|
|
|
# information for anything elsewhere on the site.
|
|
|
|
response = self.client_get("/terms/")
|
|
|
|
self.assert_in_success_response(["Plans"], response)
|
|
|
|
|
|
|
|
response = self.client_get("/terms/?nav=no")
|
|
|
|
self.assert_not_in_success_response(["Plans"], response)
|
|
|
|
|
|
|
|
response = self.client_get("/privacy/?nav=no")
|
|
|
|
self.assert_not_in_success_response(["Plans"], response)
|