mirror of https://github.com/zulip/zulip.git
907 lines
33 KiB
Python
907 lines
33 KiB
Python
import os
|
|
|
|
from django.conf import settings
|
|
from django.conf.urls import include
|
|
from django.conf.urls.i18n import i18n_patterns
|
|
from django.contrib.auth.views import (
|
|
LoginView,
|
|
PasswordResetCompleteView,
|
|
PasswordResetConfirmView,
|
|
PasswordResetDoneView,
|
|
)
|
|
from django.urls import path
|
|
from django.utils.module_loading import import_string
|
|
from django.views.generic import RedirectView, TemplateView
|
|
|
|
from zerver.forms import LoggingSetPasswordForm
|
|
from zerver.lib.integrations import WEBHOOK_INTEGRATIONS
|
|
from zerver.lib.rest import rest_path
|
|
from zerver.tornado.views import cleanup_event_queue, get_events, get_events_internal, notify
|
|
from zerver.views.alert_words import add_alert_words, list_alert_words, remove_alert_words
|
|
from zerver.views.archive import archive, get_web_public_topics_backend
|
|
from zerver.views.attachments import list_by_user, remove
|
|
from zerver.views.auth import (
|
|
api_dev_fetch_api_key,
|
|
api_dev_list_users,
|
|
api_fetch_api_key,
|
|
api_fetch_google_client_id,
|
|
api_get_server_settings,
|
|
dev_direct_login,
|
|
json_fetch_api_key,
|
|
log_into_subdomain,
|
|
login_page,
|
|
logout_then_login,
|
|
password_reset,
|
|
remote_user_jwt,
|
|
remote_user_sso,
|
|
saml_sp_metadata,
|
|
show_deactivation_notice,
|
|
start_remote_user_sso,
|
|
start_social_login,
|
|
start_social_signup,
|
|
)
|
|
from zerver.views.camo import handle_camo_url
|
|
from zerver.views.compatibility import check_global_compatibility
|
|
from zerver.views.custom_profile_fields import (
|
|
create_realm_custom_profile_field,
|
|
delete_realm_custom_profile_field,
|
|
list_realm_custom_profile_fields,
|
|
remove_user_custom_profile_data,
|
|
reorder_realm_custom_profile_fields,
|
|
update_realm_custom_profile_field,
|
|
update_user_custom_profile_data,
|
|
)
|
|
from zerver.views.digest import digest_page
|
|
from zerver.views.documentation import IntegrationView, MarkdownDirectoryView, integration_doc
|
|
from zerver.views.drafts import create_drafts, delete_draft, edit_draft, fetch_drafts
|
|
from zerver.views.email_mirror import email_mirror_message
|
|
from zerver.views.events_register import events_register_backend
|
|
from zerver.views.home import accounts_accept_terms, desktop_home, home
|
|
from zerver.views.hotspots import mark_hotspot_as_read
|
|
from zerver.views.invite import (
|
|
generate_multiuse_invite_backend,
|
|
get_user_invites,
|
|
invite_users_backend,
|
|
resend_user_invite_email,
|
|
revoke_multiuse_invite,
|
|
revoke_user_invite,
|
|
)
|
|
from zerver.views.message_edit import (
|
|
delete_message_backend,
|
|
get_message_edit_history,
|
|
json_fetch_raw_message,
|
|
update_message_backend,
|
|
)
|
|
from zerver.views.message_fetch import get_messages_backend, messages_in_narrow_backend
|
|
from zerver.views.message_flags import (
|
|
mark_all_as_read,
|
|
mark_stream_as_read,
|
|
mark_topic_as_read,
|
|
update_message_flags,
|
|
)
|
|
from zerver.views.message_send import render_message_backend, send_message_backend, zcommand_backend
|
|
from zerver.views.muting import update_muted_topic
|
|
from zerver.views.portico import (
|
|
app_download_link_redirect,
|
|
apps_view,
|
|
hello_view,
|
|
landing_view,
|
|
plans_view,
|
|
privacy_view,
|
|
team_view,
|
|
terms_view,
|
|
)
|
|
from zerver.views.presence import (
|
|
get_presence_backend,
|
|
get_statuses_for_realm,
|
|
update_active_status_backend,
|
|
update_user_status_backend,
|
|
)
|
|
from zerver.views.push_notifications import (
|
|
add_android_reg_id,
|
|
add_apns_device_token,
|
|
remove_android_reg_id,
|
|
remove_apns_device_token,
|
|
)
|
|
from zerver.views.reactions import add_reaction, remove_reaction
|
|
from zerver.views.realm import (
|
|
check_subdomain_available,
|
|
deactivate_realm,
|
|
realm_reactivation,
|
|
update_realm,
|
|
)
|
|
from zerver.views.realm_domains import (
|
|
create_realm_domain,
|
|
delete_realm_domain,
|
|
list_realm_domains,
|
|
patch_realm_domain,
|
|
)
|
|
from zerver.views.realm_emoji import delete_emoji, list_emoji, upload_emoji
|
|
from zerver.views.realm_export import delete_realm_export, export_realm, get_realm_exports
|
|
from zerver.views.realm_filters import create_filter, delete_filter, list_filters
|
|
from zerver.views.realm_icon import delete_icon_backend, get_icon_backend, upload_icon
|
|
from zerver.views.realm_logo import delete_logo_backend, get_logo_backend, upload_logo
|
|
from zerver.views.registration import (
|
|
accounts_home,
|
|
accounts_home_from_multiuse_invite,
|
|
accounts_register,
|
|
check_prereg_key_and_redirect,
|
|
create_realm,
|
|
find_account,
|
|
generate_204,
|
|
realm_redirect,
|
|
)
|
|
from zerver.views.report import (
|
|
report_csp_violations,
|
|
report_error,
|
|
report_narrow_times,
|
|
report_send_times,
|
|
report_unnarrow_times,
|
|
)
|
|
from zerver.views.storage import get_storage, remove_storage, update_storage
|
|
from zerver.views.streams import (
|
|
add_default_stream,
|
|
add_subscriptions_backend,
|
|
create_default_stream_group,
|
|
deactivate_stream_backend,
|
|
delete_in_topic,
|
|
get_streams_backend,
|
|
get_subscribers_backend,
|
|
get_topics_backend,
|
|
json_get_stream_id,
|
|
list_subscriptions_backend,
|
|
remove_default_stream,
|
|
remove_default_stream_group,
|
|
remove_subscriptions_backend,
|
|
update_default_stream_group_info,
|
|
update_default_stream_group_streams,
|
|
update_stream_backend,
|
|
update_subscription_properties_backend,
|
|
update_subscriptions_backend,
|
|
update_subscriptions_property,
|
|
)
|
|
from zerver.views.submessage import process_submessage
|
|
from zerver.views.thumbnail import backend_serve_thumbnail
|
|
from zerver.views.tutorial import set_tutorial_status
|
|
from zerver.views.typing import send_notification_backend
|
|
from zerver.views.unsubscribe import email_unsubscribe
|
|
from zerver.views.upload import (
|
|
serve_file_backend,
|
|
serve_file_url_backend,
|
|
serve_local_file_unauthed,
|
|
upload_file_backend,
|
|
)
|
|
from zerver.views.user_groups import (
|
|
add_user_group,
|
|
delete_user_group,
|
|
edit_user_group,
|
|
get_user_group,
|
|
update_user_group_backend,
|
|
)
|
|
from zerver.views.user_settings import (
|
|
change_enter_sends,
|
|
confirm_email_change,
|
|
delete_avatar_backend,
|
|
json_change_notify_settings,
|
|
json_change_settings,
|
|
regenerate_api_key,
|
|
set_avatar_backend,
|
|
update_display_settings_backend,
|
|
)
|
|
from zerver.views.users import (
|
|
add_bot_backend,
|
|
avatar,
|
|
create_user_backend,
|
|
deactivate_bot_backend,
|
|
deactivate_user_backend,
|
|
deactivate_user_own_backend,
|
|
get_bots_backend,
|
|
get_members_backend,
|
|
get_profile_backend,
|
|
get_subscription_backend,
|
|
patch_bot_backend,
|
|
reactivate_user_backend,
|
|
regenerate_bot_api_key,
|
|
update_user_backend,
|
|
)
|
|
from zerver.views.video_calls import (
|
|
complete_zoom_user,
|
|
deauthorize_zoom_user,
|
|
get_bigbluebutton_url,
|
|
join_bigbluebutton,
|
|
make_zoom_video_call,
|
|
register_zoom_user,
|
|
)
|
|
from zerver.views.zephyr import webathena_kerberos_login
|
|
from zproject import dev_urls
|
|
from zproject.legacy_urls import legacy_urls
|
|
|
|
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED:
|
|
from two_factor.gateways.twilio.urls import urlpatterns as tf_twilio_urls
|
|
from two_factor.urls import urlpatterns as tf_urls
|
|
|
|
# NB: There are several other pieces of code which route requests by URL:
|
|
#
|
|
# - legacy_urls.py contains API endpoint written before the redesign
|
|
# and should not be added to.
|
|
#
|
|
# - runtornado.py has its own URL list for Tornado views. See the
|
|
# invocation of web.Application in that file.
|
|
#
|
|
# - The Nginx config knows which URLs to route to Django or Tornado.
|
|
#
|
|
# - Likewise for the local dev server in tools/run-dev.py.
|
|
|
|
# These endpoints constitute the currently designed API (V1), which uses:
|
|
# * REST verbs
|
|
# * Basic auth (username:password is email:apiKey)
|
|
# * Take and return json-formatted data
|
|
#
|
|
# If you're adding a new endpoint to the code that requires authentication,
|
|
# please add it here.
|
|
# See rest_dispatch in zerver.lib.rest for an explanation of auth methods used
|
|
#
|
|
# All of these paths are accessed by either a /json or /api/v1 prefix;
|
|
# e.g. `PATCH /json/realm` or `PATCH /api/v1/realm`.
|
|
v1_api_and_json_patterns = [
|
|
# realm-level calls
|
|
rest_path('realm',
|
|
PATCH=update_realm),
|
|
|
|
# Returns a 204, used by desktop app to verify connectivity status
|
|
path('generate_204', generate_204),
|
|
|
|
path('realm/subdomain/<subdomain>', check_subdomain_available),
|
|
|
|
# realm/domains -> zerver.views.realm_domains
|
|
rest_path('realm/domains',
|
|
GET=list_realm_domains,
|
|
POST=create_realm_domain),
|
|
rest_path('realm/domains/<domain>',
|
|
PATCH=patch_realm_domain,
|
|
DELETE=delete_realm_domain),
|
|
|
|
# realm/emoji -> zerver.views.realm_emoji
|
|
rest_path('realm/emoji',
|
|
GET=list_emoji),
|
|
rest_path('realm/emoji/<emoji_name>',
|
|
POST=upload_emoji,
|
|
DELETE=(delete_emoji, {"intentionally_undocumented"})),
|
|
# this endpoint throws a status code 400 JsonableError when it should be a 404.
|
|
|
|
# realm/icon -> zerver.views.realm_icon
|
|
rest_path('realm/icon',
|
|
POST=upload_icon,
|
|
DELETE=delete_icon_backend,
|
|
GET=get_icon_backend),
|
|
|
|
# realm/logo -> zerver.views.realm_logo
|
|
rest_path('realm/logo',
|
|
POST=upload_logo,
|
|
DELETE=delete_logo_backend,
|
|
GET=get_logo_backend),
|
|
|
|
# realm/filters -> zerver.views.realm_filters
|
|
rest_path('realm/filters',
|
|
GET=list_filters,
|
|
POST=create_filter),
|
|
rest_path('realm/filters/<int:filter_id>',
|
|
DELETE=delete_filter),
|
|
|
|
# realm/profile_fields -> zerver.views.custom_profile_fields
|
|
rest_path('realm/profile_fields',
|
|
GET=list_realm_custom_profile_fields,
|
|
PATCH=reorder_realm_custom_profile_fields,
|
|
POST=create_realm_custom_profile_field),
|
|
rest_path('realm/profile_fields/<int:field_id>',
|
|
PATCH=update_realm_custom_profile_field,
|
|
DELETE=delete_realm_custom_profile_field),
|
|
|
|
# realm/deactivate -> zerver.views.deactivate_realm
|
|
rest_path('realm/deactivate',
|
|
POST=deactivate_realm),
|
|
|
|
# users -> zerver.views.users
|
|
rest_path('users',
|
|
GET=get_members_backend,
|
|
POST=create_user_backend),
|
|
rest_path('users/me',
|
|
GET=get_profile_backend,
|
|
DELETE=deactivate_user_own_backend),
|
|
rest_path('users/<int:user_id>/reactivate',
|
|
POST=reactivate_user_backend),
|
|
rest_path('users/<int:user_id>',
|
|
GET=get_members_backend,
|
|
PATCH=update_user_backend,
|
|
DELETE=deactivate_user_backend),
|
|
rest_path('users/<int:user_id>/subscriptions/<int:stream_id>',
|
|
GET=get_subscription_backend),
|
|
rest_path('bots',
|
|
GET=get_bots_backend,
|
|
POST=add_bot_backend),
|
|
rest_path('bots/<int:bot_id>/api_key/regenerate',
|
|
POST=regenerate_bot_api_key),
|
|
rest_path('bots/<int:bot_id>',
|
|
PATCH=patch_bot_backend,
|
|
DELETE=deactivate_bot_backend),
|
|
|
|
# invites -> zerver.views.invite
|
|
rest_path('invites',
|
|
GET=get_user_invites,
|
|
POST=invite_users_backend),
|
|
rest_path('invites/<int:prereg_id>',
|
|
DELETE=revoke_user_invite),
|
|
rest_path('invites/<int:prereg_id>/resend',
|
|
POST=resend_user_invite_email),
|
|
|
|
# invites/multiuse -> zerver.views.invite
|
|
rest_path('invites/multiuse',
|
|
POST=generate_multiuse_invite_backend),
|
|
# invites/multiuse -> zerver.views.invite
|
|
rest_path('invites/multiuse/<int:invite_id>',
|
|
DELETE=revoke_multiuse_invite),
|
|
|
|
# mark messages as read (in bulk)
|
|
rest_path('mark_all_as_read',
|
|
POST=mark_all_as_read),
|
|
rest_path('mark_stream_as_read',
|
|
POST=mark_stream_as_read),
|
|
rest_path('mark_topic_as_read',
|
|
POST=mark_topic_as_read),
|
|
|
|
rest_path('zcommand',
|
|
POST=zcommand_backend),
|
|
|
|
# Endpoints for syncing drafts.
|
|
rest_path('drafts',
|
|
GET=(fetch_drafts,
|
|
{'intentionally_undocumented'}),
|
|
POST=(create_drafts,
|
|
{'intentionally_undocumented'})),
|
|
rest_path('drafts/<int:draft_id>',
|
|
PATCH=(edit_draft,
|
|
{'intentionally_undocumented'}),
|
|
DELETE=(delete_draft,
|
|
{'intentionally_undocumented'})),
|
|
|
|
# messages -> zerver.views.message*
|
|
# GET returns messages, possibly filtered, POST sends a message
|
|
rest_path('messages',
|
|
GET=(get_messages_backend,
|
|
{'allow_anonymous_user_web'}),
|
|
POST=(send_message_backend,
|
|
{'allow_incoming_webhooks'})),
|
|
rest_path('messages/<int:message_id>',
|
|
GET=json_fetch_raw_message,
|
|
PATCH=update_message_backend,
|
|
DELETE=delete_message_backend),
|
|
rest_path('messages/render',
|
|
POST=render_message_backend),
|
|
rest_path('messages/flags',
|
|
POST=update_message_flags),
|
|
rest_path('messages/<int:message_id>/history',
|
|
GET=get_message_edit_history),
|
|
rest_path('messages/matches_narrow',
|
|
GET=messages_in_narrow_backend),
|
|
|
|
rest_path('users/me/subscriptions/properties',
|
|
POST=update_subscription_properties_backend),
|
|
|
|
rest_path('users/me/subscriptions/<int:stream_id>',
|
|
PATCH=update_subscriptions_property),
|
|
|
|
rest_path('submessage',
|
|
POST=process_submessage),
|
|
|
|
# New endpoint for handling reactions.
|
|
# reactions -> zerver.view.reactions
|
|
# POST adds a reaction to a message
|
|
# DELETE removes a reaction from a message
|
|
rest_path('messages/<int:message_id>/reactions',
|
|
POST=add_reaction,
|
|
DELETE=remove_reaction),
|
|
|
|
# attachments -> zerver.views.attachments
|
|
rest_path('attachments',
|
|
GET=list_by_user),
|
|
rest_path('attachments/<int:attachment_id>',
|
|
DELETE=remove),
|
|
|
|
# typing -> zerver.views.typing
|
|
# POST sends a typing notification event to recipients
|
|
rest_path('typing',
|
|
POST=send_notification_backend),
|
|
|
|
# user_uploads -> zerver.views.upload
|
|
rest_path('user_uploads',
|
|
POST=upload_file_backend),
|
|
rest_path('user_uploads/<realm_id_str>/<path:filename>',
|
|
GET=(serve_file_url_backend,
|
|
{'override_api_url_scheme'})),
|
|
|
|
# bot_storage -> zerver.views.storage
|
|
rest_path('bot_storage',
|
|
PUT=update_storage,
|
|
GET=get_storage,
|
|
DELETE=remove_storage),
|
|
|
|
# Endpoint used by mobile devices to register their push
|
|
# notification credentials
|
|
rest_path('users/me/apns_device_token',
|
|
POST=add_apns_device_token,
|
|
DELETE=remove_apns_device_token),
|
|
rest_path('users/me/android_gcm_reg_id',
|
|
POST=add_android_reg_id,
|
|
DELETE=remove_android_reg_id),
|
|
|
|
# users/*/presnece => zerver.views.presence.
|
|
rest_path('users/me/presence',
|
|
POST=update_active_status_backend),
|
|
# It's important that this sit after users/me/presence so that
|
|
# Django's URL resolution order doesn't break the
|
|
# /users/me/presence endpoint.
|
|
rest_path('users/<email>/presence',
|
|
GET=get_presence_backend),
|
|
rest_path('realm/presence',
|
|
GET=get_statuses_for_realm),
|
|
rest_path('users/me/status',
|
|
POST=update_user_status_backend),
|
|
|
|
# user_groups -> zerver.views.user_groups
|
|
rest_path('user_groups',
|
|
GET=get_user_group),
|
|
rest_path('user_groups/create',
|
|
POST=add_user_group),
|
|
rest_path('user_groups/<int:user_group_id>',
|
|
PATCH=edit_user_group,
|
|
DELETE=delete_user_group),
|
|
rest_path('user_groups/<int:user_group_id>/members',
|
|
POST=update_user_group_backend),
|
|
|
|
# users/me -> zerver.views.user_settings
|
|
rest_path('users/me/api_key/regenerate',
|
|
POST=regenerate_api_key),
|
|
rest_path('users/me/enter-sends',
|
|
POST=(change_enter_sends,
|
|
# This endpoint should be folded into user settings
|
|
{'intentionally_undocumented'})),
|
|
rest_path('users/me/avatar',
|
|
POST=set_avatar_backend,
|
|
DELETE=delete_avatar_backend),
|
|
|
|
# users/me/hotspots -> zerver.views.hotspots
|
|
rest_path('users/me/hotspots',
|
|
POST=(mark_hotspot_as_read,
|
|
# This endpoint is low priority for documentation as
|
|
# it is part of the webapp-specific tutorial.
|
|
{'intentionally_undocumented'})),
|
|
|
|
# users/me/tutorial_status -> zerver.views.tutorial
|
|
rest_path('users/me/tutorial_status',
|
|
POST=(set_tutorial_status,
|
|
# This is a relic of an old Zulip tutorial model and
|
|
# should be deleted.
|
|
{'intentionally_undocumented'})),
|
|
|
|
# settings -> zerver.views.user_settings
|
|
rest_path('settings',
|
|
PATCH=json_change_settings),
|
|
rest_path('settings/display',
|
|
PATCH=update_display_settings_backend),
|
|
rest_path('settings/notifications',
|
|
PATCH=json_change_notify_settings),
|
|
|
|
# users/me/alert_words -> zerver.views.alert_words
|
|
rest_path('users/me/alert_words',
|
|
GET=list_alert_words,
|
|
POST=add_alert_words,
|
|
DELETE=remove_alert_words),
|
|
|
|
# users/me/custom_profile_data -> zerver.views.custom_profile_data
|
|
rest_path('users/me/profile_data',
|
|
PATCH=update_user_custom_profile_data,
|
|
DELETE=remove_user_custom_profile_data),
|
|
|
|
rest_path('users/me/<int:stream_id>/topics',
|
|
GET=(get_topics_backend,
|
|
{'allow_anonymous_user_web'})),
|
|
|
|
|
|
# streams -> zerver.views.streams
|
|
# (this API is only used externally)
|
|
rest_path('streams',
|
|
GET=get_streams_backend),
|
|
|
|
# GET returns `stream_id`, stream name should be encoded in the URL query (in `stream` param)
|
|
rest_path('get_stream_id',
|
|
GET=json_get_stream_id),
|
|
|
|
# GET returns "stream info" (undefined currently?), HEAD returns whether stream exists (200 or 404)
|
|
rest_path('streams/<int:stream_id>/members',
|
|
GET=get_subscribers_backend),
|
|
rest_path('streams/<int:stream_id>',
|
|
PATCH=update_stream_backend,
|
|
DELETE=deactivate_stream_backend),
|
|
|
|
# Delete topic in stream
|
|
rest_path('streams/<int:stream_id>/delete_topic',
|
|
POST=delete_in_topic),
|
|
|
|
rest_path('default_streams',
|
|
POST=add_default_stream,
|
|
DELETE=remove_default_stream),
|
|
rest_path('default_stream_groups/create',
|
|
POST=create_default_stream_group),
|
|
rest_path('default_stream_groups/<int:group_id>',
|
|
PATCH=update_default_stream_group_info,
|
|
DELETE=remove_default_stream_group),
|
|
rest_path('default_stream_groups/<int:group_id>/streams',
|
|
PATCH=update_default_stream_group_streams),
|
|
# GET lists your streams, POST bulk adds, PATCH bulk modifies/removes
|
|
rest_path('users/me/subscriptions',
|
|
GET=list_subscriptions_backend,
|
|
POST=add_subscriptions_backend,
|
|
PATCH=update_subscriptions_backend,
|
|
DELETE=remove_subscriptions_backend),
|
|
# muting -> zerver.views.muting
|
|
rest_path('users/me/subscriptions/muted_topics',
|
|
PATCH=update_muted_topic),
|
|
|
|
# used to register for an event queue in tornado
|
|
rest_path('register',
|
|
POST=events_register_backend),
|
|
|
|
# events -> zerver.tornado.views
|
|
rest_path('events',
|
|
GET=get_events,
|
|
DELETE=cleanup_event_queue),
|
|
|
|
# report -> zerver.views.report
|
|
#
|
|
# These endpoints are for internal error/performance reporting
|
|
# from the browser to the webapp, and we don't expect to ever
|
|
# include in our API documentation.
|
|
rest_path('report/error',
|
|
# Logged-out browsers can hit this endpoint, for portico page JS exceptions.
|
|
POST=(report_error, {'allow_anonymous_user_web',
|
|
'intentionally_undocumented'})),
|
|
rest_path('report/send_times',
|
|
POST=(report_send_times, {'intentionally_undocumented'})),
|
|
rest_path('report/narrow_times',
|
|
POST=(report_narrow_times, {'allow_anonymous_user_web',
|
|
'intentionally_undocumented'})),
|
|
rest_path('report/unnarrow_times',
|
|
POST=(report_unnarrow_times, {'allow_anonymous_user_web',
|
|
'intentionally_undocumented'})),
|
|
|
|
# Used to generate a Zoom video call URL
|
|
rest_path('calls/zoom/create',
|
|
POST=make_zoom_video_call),
|
|
# Used to generate a Big Blue Button video call URL
|
|
rest_path('calls/bigbluebutton/create',
|
|
GET=get_bigbluebutton_url),
|
|
|
|
# export/realm -> zerver.views.realm_export
|
|
rest_path('export/realm',
|
|
POST=export_realm,
|
|
GET=get_realm_exports),
|
|
rest_path('export/realm/<int:export_id>',
|
|
DELETE=delete_realm_export),
|
|
]
|
|
|
|
integrations_view = IntegrationView.as_view()
|
|
|
|
# These views serve pages (HTML). As such, their internationalization
|
|
# must depend on the URL.
|
|
#
|
|
# If you're adding a new page to the website (as opposed to a new
|
|
# endpoint for use by code), you should add it here.
|
|
i18n_urls = [
|
|
path('', home, name='home'),
|
|
# We have a desktop-specific landing page in case we change our /
|
|
# to not log in in the future. We don't want to require a new
|
|
# desktop app build for everyone in that case
|
|
path('desktop_home/', desktop_home),
|
|
|
|
# Backwards-compatibility (legacy) Google auth URL for the mobile
|
|
# apps; see https://github.com/zulip/zulip/issues/13081 for
|
|
# background. We can remove this once older versions of the
|
|
# mobile app are no longer present in the wild.
|
|
path('accounts/login/google/', start_social_login, {"backend": "google"}),
|
|
|
|
path('accounts/login/start/sso/', start_remote_user_sso, name='start-login-sso'),
|
|
path('accounts/login/sso/', remote_user_sso, name='login-sso'),
|
|
path('accounts/login/jwt/', remote_user_jwt),
|
|
path('accounts/login/social/<backend>', start_social_login,
|
|
name='login-social'),
|
|
path('accounts/login/social/<backend>/<extra_arg>', start_social_login,
|
|
name='login-social'),
|
|
path('accounts/register/social/<backend>',
|
|
start_social_signup,
|
|
name='signup-social'),
|
|
path('accounts/register/social/<backend>/<extra_arg>',
|
|
start_social_signup,
|
|
name='signup-social'),
|
|
path('accounts/login/subdomain/<token>', log_into_subdomain),
|
|
path('accounts/login/local/', dev_direct_login, name='login-local'),
|
|
# We have two entries for accounts/login; only the first one is
|
|
# used for URL resolution. The second here is to allow
|
|
# reverse("login") in templates to
|
|
# return `/accounts/login/`.
|
|
path('accounts/login/', login_page,
|
|
{'template_name': 'zerver/login.html'}, name='login_page'),
|
|
path('accounts/login/', LoginView.as_view(template_name='zerver/login.html'),
|
|
name='login'),
|
|
path('accounts/logout/', logout_then_login),
|
|
|
|
path('accounts/webathena_kerberos_login/',
|
|
webathena_kerberos_login),
|
|
|
|
path('accounts/password/reset/', password_reset, name='password_reset'),
|
|
path('accounts/password/reset/done/',
|
|
PasswordResetDoneView.as_view(template_name='zerver/reset_emailed.html')),
|
|
path('accounts/password/reset/<uidb64>/<token>/',
|
|
PasswordResetConfirmView.as_view(success_url='/accounts/password/done/',
|
|
template_name='zerver/reset_confirm.html',
|
|
form_class=LoggingSetPasswordForm),
|
|
name='password_reset_confirm'),
|
|
path('accounts/password/done/',
|
|
PasswordResetCompleteView.as_view(template_name='zerver/reset_done.html')),
|
|
path('accounts/deactivated/',
|
|
show_deactivation_notice),
|
|
|
|
# Displays digest email content in browser.
|
|
path('digest/', digest_page),
|
|
|
|
# Registration views, require a confirmation ID.
|
|
path('accounts/home/', accounts_home),
|
|
path('accounts/send_confirm/<email>',
|
|
TemplateView.as_view(
|
|
template_name='zerver/accounts_send_confirm.html'),
|
|
name='signup_send_confirm'),
|
|
path('accounts/new/send_confirm/<email>',
|
|
TemplateView.as_view(
|
|
template_name='zerver/accounts_send_confirm.html'),
|
|
{'realm_creation': True}, name='new_realm_send_confirm'),
|
|
path('accounts/register/', accounts_register, name='accounts_register'),
|
|
path('accounts/do_confirm/<confirmation_key>',
|
|
check_prereg_key_and_redirect,
|
|
name='check_prereg_key_and_redirect'),
|
|
|
|
path('accounts/confirm_new_email/<confirmation_key>',
|
|
confirm_email_change,
|
|
name='confirm_email_change'),
|
|
|
|
# Email unsubscription endpoint. Allows for unsubscribing from various types of emails,
|
|
# including the welcome emails (day 1 & 2), missed PMs, etc.
|
|
path('accounts/unsubscribe/<email_type>/<confirmation_key>',
|
|
email_unsubscribe, name='unsubscribe'),
|
|
|
|
# Portico-styled page used to provide email confirmation of terms acceptance.
|
|
path('accounts/accept_terms/', accounts_accept_terms, name='accept_terms'),
|
|
|
|
# Find your account
|
|
path('accounts/find/', find_account, name='find_account'),
|
|
|
|
# Go to organization subdomain
|
|
path('accounts/go/', realm_redirect, name='realm_redirect'),
|
|
|
|
# Realm creation
|
|
path('new/', create_realm),
|
|
path('new/<creation_key>',
|
|
create_realm, name='create_realm'),
|
|
|
|
# Realm reactivation
|
|
path('reactivate/<confirmation_key>', realm_reactivation,
|
|
name='realm_reactivation'),
|
|
|
|
# Global public streams (Zulip's way of doing archives)
|
|
path('archive/streams/<int:stream_id>/topics/<topic_name>',
|
|
archive),
|
|
path('archive/streams/<int:stream_id>/topics',
|
|
get_web_public_topics_backend),
|
|
|
|
# Login/registration
|
|
path('register/', accounts_home, name='register'),
|
|
path('login/', login_page, {'template_name': 'zerver/login.html'},
|
|
name='login_page'),
|
|
|
|
path('join/<confirmation_key>/',
|
|
accounts_home_from_multiuse_invite, name='join'),
|
|
|
|
# Used to generate a Zoom video call URL
|
|
path('calls/zoom/register', register_zoom_user),
|
|
path('calls/zoom/complete', complete_zoom_user),
|
|
path('calls/zoom/deauthorize', deauthorize_zoom_user),
|
|
|
|
# Used to join a Big Blue Button video call
|
|
path('calls/bigbluebutton/join', join_bigbluebutton),
|
|
|
|
# API and integrations documentation
|
|
path('integrations/doc-html/<integration_name>',
|
|
integration_doc),
|
|
path('integrations/', integrations_view),
|
|
path('integrations/<path:path>', integrations_view),
|
|
|
|
# Landing page, features pages, signup form, etc.
|
|
path('hello/', hello_view),
|
|
path('new-user/', RedirectView.as_view(url='/hello', permanent=True)),
|
|
path('features/', landing_view, {'template_name': 'zerver/features.html'}),
|
|
path('plans/', plans_view, name='plans'),
|
|
path('apps/', apps_view),
|
|
path('apps/download/<platform>', app_download_link_redirect),
|
|
path('apps/<platform>', apps_view),
|
|
path('team/', team_view),
|
|
path('history/', landing_view, {'template_name': 'zerver/history.html'}),
|
|
path('why-zulip/', landing_view, {'template_name': 'zerver/why-zulip.html'}),
|
|
path('for/open-source/', landing_view,
|
|
{'template_name': 'zerver/for-open-source.html'}),
|
|
path('for/research/', landing_view,
|
|
{'template_name': 'zerver/for-research.html'}),
|
|
path('for/companies/', landing_view,
|
|
{'template_name': 'zerver/for-companies.html'}),
|
|
path('for/working-groups-and-communities/', landing_view,
|
|
{'template_name': 'zerver/for-working-groups-and-communities.html'}),
|
|
path('security/', landing_view, {'template_name': 'zerver/security.html'}),
|
|
|
|
# Terms of Service and privacy pages.
|
|
path('terms/', terms_view),
|
|
path('privacy/', privacy_view),
|
|
]
|
|
|
|
# Make a copy of i18n_urls so that they appear without prefix for english
|
|
urls = list(i18n_urls)
|
|
|
|
# Include the dual-use patterns twice
|
|
urls += [
|
|
path('api/v1/', include(v1_api_and_json_patterns)),
|
|
path('json/', include(v1_api_and_json_patterns)),
|
|
]
|
|
|
|
# user_uploads -> zerver.views.upload.serve_file_backend
|
|
#
|
|
# This URL is an exception to the URL naming schemes for endpoints. It
|
|
# supports both API and session cookie authentication, using a single
|
|
# URL for both (not 'api/v1/' or 'json/' prefix). This is required to
|
|
# easily support the mobile apps fetching uploaded files without
|
|
# having to rewrite URLs, and is implemented using the
|
|
# 'override_api_url_scheme' flag passed to rest_dispatch
|
|
urls += [
|
|
path('user_uploads/temporary/<token>/<filename>',
|
|
serve_local_file_unauthed,
|
|
name='local_file_unauthed'),
|
|
rest_path('user_uploads/<realm_id_str>/<path:filename>',
|
|
GET=(serve_file_backend,
|
|
{'override_api_url_scheme'})),
|
|
# This endpoint serves thumbnailed versions of images using thumbor;
|
|
# it requires an exception for the same reason.
|
|
rest_path('thumbnail',
|
|
GET=(backend_serve_thumbnail,
|
|
{'override_api_url_scheme'})),
|
|
# Avatars have the same constraint because their URLs are included
|
|
# in API data structures used by both the mobile and web clients.
|
|
rest_path('avatar/<email_or_id>',
|
|
GET=(avatar,
|
|
{'override_api_url_scheme'})),
|
|
rest_path('avatar/<email_or_id>/medium',
|
|
{'medium': True},
|
|
GET=(avatar,
|
|
{'override_api_url_scheme'})),
|
|
]
|
|
|
|
# This URL serves as a way to receive CSP violation reports from the users.
|
|
# We use this endpoint to just log these reports.
|
|
urls += [
|
|
path('report/csp_violations', report_csp_violations),
|
|
]
|
|
|
|
# This URL serves as a way to provide backward compatibility to messages
|
|
# rendered at the time Zulip used camo for doing http -> https conversion for
|
|
# such links with images previews. Now thumbor can be used for serving such
|
|
# images.
|
|
urls += [
|
|
path('external_content/<digest>/<received_url>',
|
|
handle_camo_url),
|
|
]
|
|
|
|
# Incoming webhook URLs
|
|
# We don't create URLs for particular Git integrations here
|
|
# because of generic one below
|
|
for incoming_webhook in WEBHOOK_INTEGRATIONS:
|
|
if incoming_webhook.url_object:
|
|
urls.append(incoming_webhook.url_object)
|
|
|
|
# Desktop-specific authentication URLs
|
|
urls += [
|
|
rest_path('json/fetch_api_key',
|
|
POST=json_fetch_api_key),
|
|
]
|
|
|
|
# Mobile-specific authentication URLs
|
|
urls += [
|
|
# Used as a global check by all mobile clients, which currently send
|
|
# requests to https://zulip.com/compatibility almost immediately after
|
|
# starting up.
|
|
path('compatibility', check_global_compatibility),
|
|
]
|
|
|
|
v1_api_mobile_patterns = [
|
|
# This json format view used by the mobile apps lists which
|
|
# authentication backends the server allows as well as details
|
|
# like the requested subdomains'd realm icon (if known) and
|
|
# server-specific compatibility.
|
|
path('server_settings', api_get_server_settings),
|
|
|
|
# This json format view used by the mobile apps accepts a username
|
|
# password/pair and returns an API key.
|
|
path('fetch_api_key', api_fetch_api_key),
|
|
|
|
# This is for the signing in through the devAuthBackEnd on mobile apps.
|
|
path('dev_fetch_api_key', api_dev_fetch_api_key),
|
|
# This is for fetching the emails of the admins and the users.
|
|
path('dev_list_users', api_dev_list_users),
|
|
|
|
# Used to present the GOOGLE_CLIENT_ID to mobile apps
|
|
path('fetch_google_client_id',
|
|
api_fetch_google_client_id),
|
|
]
|
|
urls += [
|
|
path('api/v1/', include(v1_api_mobile_patterns)),
|
|
]
|
|
|
|
# View for uploading messages from email mirror
|
|
urls += [
|
|
path('email_mirror_message', email_mirror_message),
|
|
]
|
|
|
|
# Include URL configuration files for site-specified extra installed
|
|
# Django apps
|
|
for app_name in settings.EXTRA_INSTALLED_APPS:
|
|
app_dir = os.path.join(settings.DEPLOY_ROOT, app_name)
|
|
if os.path.exists(os.path.join(app_dir, 'urls.py')):
|
|
urls += [path('', include(f'{app_name}.urls'))]
|
|
i18n_urls += import_string(f"{app_name}.urls.i18n_urlpatterns")
|
|
|
|
# Tornado views
|
|
urls += [
|
|
# Used internally for communication between Django and Tornado processes
|
|
#
|
|
# Since these views don't use rest_dispatch, they cannot have
|
|
# asynchronous Tornado behavior.
|
|
path('notify_tornado', notify),
|
|
path('api/v1/events/internal', get_events_internal),
|
|
]
|
|
|
|
# Python Social Auth
|
|
|
|
urls += [path('', include('social_django.urls', namespace='social'))]
|
|
urls += [path('saml/metadata.xml', saml_sp_metadata)]
|
|
|
|
# User documentation site
|
|
help_documentation_view = MarkdownDirectoryView.as_view(
|
|
template_name='zerver/documentation_main.html', path_template='/zerver/help/%s.md'
|
|
)
|
|
api_documentation_view = MarkdownDirectoryView.as_view(
|
|
template_name='zerver/documentation_main.html', path_template='/zerver/api/%s.md'
|
|
)
|
|
urls += [
|
|
path('help/', help_documentation_view),
|
|
path('help/<path:article>', help_documentation_view),
|
|
path('api/', api_documentation_view),
|
|
path('api/<slug:article>', api_documentation_view),
|
|
]
|
|
|
|
# Two-factor URLs
|
|
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED:
|
|
urls += [path('', include(tf_urls)),
|
|
path('', include(tf_twilio_urls))]
|
|
|
|
if settings.DEVELOPMENT:
|
|
urls += dev_urls.urls
|
|
i18n_urls += dev_urls.i18n_urls
|
|
|
|
# The sequence is important; if i18n URLs don't come first then
|
|
# reverse URL mapping points to i18n URLs which causes the frontend
|
|
# tests to fail
|
|
urlpatterns = i18n_patterns(*i18n_urls) + urls + legacy_urls
|