2021-09-23 23:01:43 +03:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2021 Google Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
from dataclasses import dataclass, field
|
|
|
|
from typing import Any, Type
|
|
|
|
|
2023-03-28 04:21:46 +03:00
|
|
|
from api import accounts_api
|
2022-08-31 20:42:50 +03:00
|
|
|
from api import blink_components_api
|
2023-03-25 01:25:18 +03:00
|
|
|
from api import component_users
|
|
|
|
from api import components_users
|
2021-09-23 23:01:43 +03:00
|
|
|
from api import channels_api
|
|
|
|
from api import comments_api
|
|
|
|
from api import cues_api
|
|
|
|
from api import features_api
|
2023-06-16 18:07:48 +03:00
|
|
|
from api import feature_links_api
|
2021-09-23 23:01:43 +03:00
|
|
|
from api import login_api
|
|
|
|
from api import logout_api
|
|
|
|
from api import metricsdata
|
2022-06-25 17:54:02 +03:00
|
|
|
from api import permissions_api
|
2022-06-25 02:34:24 +03:00
|
|
|
from api import processes_api
|
2022-12-16 04:47:21 +03:00
|
|
|
from api import reviews_api
|
2022-07-06 00:38:02 +03:00
|
|
|
from api import settings_api
|
2022-12-06 00:10:14 +03:00
|
|
|
from api import stages_api
|
2021-09-23 23:01:43 +03:00
|
|
|
from api import stars_api
|
|
|
|
from api import token_refresh_api
|
|
|
|
from framework import basehandlers
|
|
|
|
from framework import csp
|
2022-06-11 00:56:40 +03:00
|
|
|
from framework import sendemail
|
2021-09-29 00:57:37 +03:00
|
|
|
from internals import detect_intent
|
2021-09-23 23:01:43 +03:00
|
|
|
from internals import fetchmetrics
|
2023-04-13 08:46:41 +03:00
|
|
|
from internals import maintenance_scripts
|
2021-09-25 01:19:17 +03:00
|
|
|
from internals import notifier
|
2022-07-15 03:04:45 +03:00
|
|
|
from internals import data_backup
|
2022-09-15 23:43:22 +03:00
|
|
|
from internals import inactive_users
|
2022-10-26 22:09:01 +03:00
|
|
|
from internals import search_fulltext
|
2022-09-23 20:23:55 +03:00
|
|
|
from internals import reminders
|
2021-09-23 23:01:43 +03:00
|
|
|
from pages import featurelist
|
|
|
|
from pages import guide
|
|
|
|
from pages import intentpreview
|
|
|
|
from pages import metrics
|
|
|
|
from pages import users
|
|
|
|
import settings
|
|
|
|
|
2021-10-06 01:15:47 +03:00
|
|
|
# Sets up Cloud Logging client library.
|
|
|
|
if not settings.UNIT_TEST_MODE and not settings.DEV_MODE:
|
|
|
|
import google.cloud.logging
|
|
|
|
client = google.cloud.logging.Client()
|
|
|
|
client.get_default_handler()
|
|
|
|
client.setup_logging()
|
2021-08-18 01:35:08 +03:00
|
|
|
|
2021-10-07 22:48:30 +03:00
|
|
|
# Sets up Cloud Debugger client library.
|
|
|
|
if not settings.UNIT_TEST_MODE and not settings.DEV_MODE:
|
|
|
|
try:
|
|
|
|
import googleclouddebugger
|
|
|
|
googleclouddebugger.enable(breakpoint_enable_canary=False)
|
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2021-10-20 02:56:37 +03:00
|
|
|
# Note: In the URLs below, parameters like <int:feature_id> are
|
|
|
|
# required for the URL to match the route, but we still accecpt
|
|
|
|
# those parameters as keywords in those handlers where the same
|
|
|
|
# handler might be used for multiple routes that have the field
|
|
|
|
# or not.
|
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
@dataclass
|
|
|
|
class Route:
|
|
|
|
path: str
|
|
|
|
handler_class: Type[basehandlers.BaseHandler] = basehandlers.SPAHandler
|
|
|
|
defaults: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
|
|
|
|
|
|
metrics_chart_routes: list[Route] = [
|
|
|
|
Route('/data/timeline/cssanimated', metricsdata.AnimatedTimelineHandler),
|
|
|
|
Route('/data/timeline/csspopularity', metricsdata.PopularityTimelineHandler),
|
|
|
|
Route('/data/timeline/featurepopularity',
|
|
|
|
metricsdata.FeatureObserverTimelineHandler),
|
|
|
|
Route('/data/csspopularity', metricsdata.CSSPopularityHandler),
|
|
|
|
Route('/data/cssanimated', metricsdata.CSSAnimatedHandler),
|
|
|
|
Route('/data/featurepopularity',
|
|
|
|
metricsdata.FeatureObserverPopularityHandler),
|
|
|
|
Route('/data/blink/<string:prop_type>', metricsdata.FeatureBucketsHandler),
|
2021-09-23 23:01:43 +03:00
|
|
|
]
|
|
|
|
|
|
|
|
# TODO(jrobbins): Advance this to v1 once we have it fleshed out
|
|
|
|
API_BASE = '/api/v0'
|
2022-11-09 21:06:59 +03:00
|
|
|
api_routes: list[Route] = [
|
|
|
|
Route(f'{API_BASE}/features', features_api.FeaturesAPI),
|
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>', features_api.FeaturesAPI),
|
2023-05-04 23:15:02 +03:00
|
|
|
Route(f'{API_BASE}/features/create', features_api.FeaturesAPI),
|
2023-06-16 18:07:48 +03:00
|
|
|
Route(f'{API_BASE}/feature_links', feature_links_api.FeatureLinksAPI),
|
2023-01-24 23:39:50 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/votes',
|
|
|
|
reviews_api.VotesAPI),
|
2022-12-16 04:47:21 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/votes/<int:gate_id>',
|
|
|
|
reviews_api.VotesAPI),
|
2022-11-19 04:19:11 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/gates',
|
2022-12-16 04:47:21 +03:00
|
|
|
reviews_api.GatesAPI),
|
2022-11-09 21:06:59 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/approvals/comments',
|
|
|
|
comments_api.CommentsAPI),
|
2023-01-11 04:11:49 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/approvals/<int:gate_id>/comments',
|
2022-11-09 21:06:59 +03:00
|
|
|
comments_api.CommentsAPI),
|
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/process',
|
|
|
|
processes_api.ProcessesAPI),
|
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/progress',
|
|
|
|
processes_api.ProgressAPI),
|
2023-01-03 21:42:23 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/stages',
|
|
|
|
stages_api.StagesAPI),
|
2022-12-06 00:10:14 +03:00
|
|
|
Route(f'{API_BASE}/features/<int:feature_id>/stages/<int:stage_id>',
|
|
|
|
stages_api.StagesAPI),
|
2022-11-09 21:06:59 +03:00
|
|
|
|
|
|
|
Route(f'{API_BASE}/blinkcomponents',
|
|
|
|
blink_components_api.BlinkComponentsAPI),
|
2023-03-25 01:25:18 +03:00
|
|
|
Route(f'{API_BASE}/componentsusers',
|
|
|
|
components_users.ComponentsUsersAPI),
|
|
|
|
Route(f'{API_BASE}/components/<int:component_id>/users/<int:user_id>',
|
|
|
|
component_users.ComponentUsersAPI),
|
2022-11-09 21:06:59 +03:00
|
|
|
|
|
|
|
Route(f'{API_BASE}/login', login_api.LoginAPI),
|
|
|
|
Route(f'{API_BASE}/logout', logout_api.LogoutAPI),
|
|
|
|
Route(f'{API_BASE}/currentuser/permissions', permissions_api.PermissionsAPI),
|
|
|
|
Route(f'{API_BASE}/currentuser/settings', settings_api.SettingsAPI),
|
|
|
|
Route(f'{API_BASE}/currentuser/stars', stars_api.StarsAPI),
|
|
|
|
Route(f'{API_BASE}/currentuser/cues', cues_api.CuesAPI),
|
|
|
|
Route(f'{API_BASE}/currentuser/token', token_refresh_api.TokenRefreshAPI),
|
|
|
|
# (f'{API_BASE}/currentuser/autosaves', TODO),
|
2021-09-23 23:01:43 +03:00
|
|
|
|
|
|
|
# Admin operations for user accounts
|
2022-11-09 21:06:59 +03:00
|
|
|
Route(f'{API_BASE}/accounts', accounts_api.AccountsAPI),
|
|
|
|
Route(f'{API_BASE}/accounts/<int:account_id>', accounts_api.AccountsAPI),
|
2021-09-23 23:01:43 +03:00
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
Route(f'{API_BASE}/channels', channels_api.ChannelsAPI), # omaha data
|
|
|
|
# (f'{API_BASE}/schedule', TODO), # chromiumdash data
|
|
|
|
# (f'{API_BASE}/metrics/<str:kind>', TODO), # uma-export data
|
|
|
|
# (f'{API_BASE}/metrics/<str:kind>/<int:bucket_id>', TODO),
|
2021-09-23 23:01:43 +03:00
|
|
|
]
|
|
|
|
|
2023-03-27 23:54:05 +03:00
|
|
|
# The Routes below that have no handler specified use SPAHandler.
|
|
|
|
# The guide.* handlers each call get_spa_template_data().
|
2022-11-09 21:06:59 +03:00
|
|
|
spa_page_routes = [
|
|
|
|
Route('/'),
|
|
|
|
Route('/roadmap'),
|
|
|
|
Route('/myfeatures', defaults={'require_signin': True}),
|
|
|
|
Route('/newfeatures'),
|
|
|
|
Route('/feature/<int:feature_id>'),
|
2023-04-21 23:08:15 +03:00
|
|
|
Route('/feature/<int:feature_id>/activity'),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/new', guide.FeatureCreateHandler,
|
2022-11-09 21:06:59 +03:00
|
|
|
defaults={'require_create_feature': True}),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/enterprise/new', guide.EnterpriseFeatureCreateHandler,
|
2023-06-09 20:38:57 +03:00
|
|
|
defaults={'require_signin': True, 'require_create_feature': True, 'is_enterprise_page': True}),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/edit/<int:feature_id>', guide.FeatureEditHandler,
|
2022-11-09 21:06:59 +03:00
|
|
|
defaults={'require_edit_feature': True}),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/stage/<int:feature_id>/<int:intent_stage>/<int:stage_id>',
|
|
|
|
guide.FeatureEditHandler,
|
2022-12-08 01:14:00 +03:00
|
|
|
defaults={'require_edit_feature': True}),
|
2022-11-09 21:06:59 +03:00
|
|
|
Route('/guide/stage/<int:feature_id>/<int:stage_id>',
|
2023-03-27 23:54:05 +03:00
|
|
|
guide.FeatureEditHandler,
|
2022-11-09 21:06:59 +03:00
|
|
|
defaults={'require_edit_feature': True}),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/edit/<int:feature_id>/<int:stage_id>', guide.FeatureEditHandler,
|
2022-12-08 01:14:00 +03:00
|
|
|
defaults={'require_edit_feature': True}),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/editall/<int:feature_id>', guide.FeatureEditHandler,
|
2022-11-09 21:06:59 +03:00
|
|
|
defaults={'require_edit_feature': True}),
|
2023-03-27 23:54:05 +03:00
|
|
|
Route('/guide/verify_accuracy/<int:feature_id>', guide.FeatureEditHandler,
|
2022-11-09 21:06:59 +03:00
|
|
|
defaults={'require_edit_feature': True}),
|
2023-01-04 03:00:01 +03:00
|
|
|
Route('/guide/stage/<int:feature_id>/metadata',
|
|
|
|
defaults={'require_edit_feature': True}),
|
2022-11-09 21:06:59 +03:00
|
|
|
Route('/metrics'),
|
|
|
|
Route('/metrics/css'),
|
|
|
|
Route('/metrics/css/popularity'),
|
|
|
|
Route('/metrics/css/animated'),
|
|
|
|
Route('/metrics/css/timeline/popularity'),
|
|
|
|
Route('/metrics/css/timeline/popularity/<int:bucket_id>'),
|
|
|
|
Route('/metrics/css/timeline/animated'),
|
|
|
|
Route('/metrics/css/timeline/animated/<int:bucket_id>'),
|
|
|
|
Route('/metrics/feature/popularity'),
|
|
|
|
Route('/metrics/feature/timeline/popularity'),
|
|
|
|
Route('/metrics/feature/timeline/popularity/<int:bucket_id>'),
|
|
|
|
Route('/settings', defaults={'require_signin': True}),
|
2022-12-01 22:41:08 +03:00
|
|
|
Route('/enterprise'),
|
2023-05-12 00:08:03 +03:00
|
|
|
Route(
|
|
|
|
'/enterprise/releasenotes',
|
2023-06-09 20:38:57 +03:00
|
|
|
defaults={'require_signin': True, 'is_enterprise_page': True}),
|
2023-03-25 01:25:18 +03:00
|
|
|
# Admin pages
|
|
|
|
Route('/admin/blink', defaults={'require_admin_site': True, 'require_signin': True}),
|
2023-06-16 03:12:28 +03:00
|
|
|
Route('/admin/slo_report', reminders.SLOReportHandler),
|
2022-09-13 21:54:32 +03:00
|
|
|
]
|
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
mpa_page_routes: list[Route] = [
|
|
|
|
Route('/admin/users/new', users.UserListHandler),
|
2021-09-23 23:01:43 +03:00
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
Route('/admin/features/launch/<int:feature_id>',
|
|
|
|
intentpreview.IntentEmailPreviewHandler),
|
|
|
|
Route('/admin/features/launch/<int:feature_id>/<int:stage_id>',
|
|
|
|
intentpreview.IntentEmailPreviewHandler),
|
2021-09-23 23:01:43 +03:00
|
|
|
|
|
|
|
# Note: The only requests being made now hit /features.json and
|
|
|
|
# /features_v2.json, but both of those cause version == 2.
|
|
|
|
# There was logic to accept another version value, but it it was not used.
|
2022-11-09 21:06:59 +03:00
|
|
|
Route(r'/features.json', featurelist.FeaturesJsonHandler),
|
|
|
|
Route(r'/features_v2.json', featurelist.FeaturesJsonHandler),
|
2021-09-23 23:01:43 +03:00
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
Route('/features', featurelist.FeatureListHandler),
|
|
|
|
Route('/features/<int:feature_id>', featurelist.FeatureListHandler),
|
|
|
|
Route('/features.xml', basehandlers.ConstHandler,
|
|
|
|
defaults={'template_path': 'farewell-rss.xml'}),
|
|
|
|
Route('/samples', basehandlers.ConstHandler,
|
|
|
|
defaults={'template_path': 'farewell-samples.html'}),
|
2021-09-23 23:01:43 +03:00
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
Route('/omaha_data', metrics.OmahaDataHandler),
|
2021-09-23 23:01:43 +03:00
|
|
|
]
|
|
|
|
|
2022-11-09 21:06:59 +03:00
|
|
|
internals_routes: list[Route] = [
|
|
|
|
Route('/cron/metrics', fetchmetrics.YesterdayHandler),
|
|
|
|
Route('/cron/histograms', fetchmetrics.HistogramsHandler),
|
|
|
|
Route('/cron/update_blink_components', fetchmetrics.BlinkComponentHandler),
|
|
|
|
Route('/cron/export_backup', data_backup.BackupExportHandler),
|
|
|
|
Route('/cron/send_accuracy_notifications', reminders.FeatureAccuracyHandler),
|
|
|
|
Route('/cron/send_prepublication', reminders.PrepublicationHandler),
|
|
|
|
Route('/cron/warn_inactive_users', notifier.NotifyInactiveUsersHandler),
|
|
|
|
Route('/cron/remove_inactive_users',
|
|
|
|
inactive_users.RemoveInactiveUsersHandler),
|
|
|
|
Route('/cron/reindex_all', search_fulltext.ReindexAllFeatures),
|
|
|
|
|
|
|
|
Route('/admin/find_stop_words', search_fulltext.FindStopWords),
|
|
|
|
|
|
|
|
Route('/tasks/email-subscribers', notifier.FeatureChangeHandler),
|
|
|
|
Route('/tasks/detect-intent', detect_intent.IntentEmailHandler),
|
2023-02-14 08:51:52 +03:00
|
|
|
Route('/tasks/email-reviewers', notifier.FeatureReviewHandler),
|
2023-03-20 20:08:24 +03:00
|
|
|
Route('/tasks/email-comments', notifier.FeatureCommentHandler),
|
2022-11-09 21:06:59 +03:00
|
|
|
|
2023-04-13 08:46:41 +03:00
|
|
|
# Maintenance scripts.
|
|
|
|
Route('/scripts/evaluate_gate_status',
|
2023-06-15 03:24:43 +03:00
|
|
|
maintenance_scripts.EvaluateGateStatus),
|
2023-04-13 08:46:41 +03:00
|
|
|
Route('/scripts/write_missing_gates',
|
2023-06-15 03:24:43 +03:00
|
|
|
maintenance_scripts.WriteMissingGates),
|
2023-05-20 03:34:42 +03:00
|
|
|
Route('/scripts/migrate_gecko_views',
|
2023-06-15 03:24:43 +03:00
|
|
|
maintenance_scripts.MigrateGeckoViews),
|
|
|
|
Route('/scripts/backfill_responded_on',
|
|
|
|
maintenance_scripts.BackfillRespondedOn),
|
2023-06-22 16:33:11 +03:00
|
|
|
Route('/scripts/backfill_stage_created',
|
|
|
|
maintenance_scripts.BackfillStageCreated),
|
2021-09-23 23:01:43 +03:00
|
|
|
]
|
|
|
|
|
2022-11-17 09:48:38 +03:00
|
|
|
dev_routes: list[Route] = []
|
|
|
|
if settings.DEV_MODE:
|
|
|
|
dev_routes = [
|
2021-09-23 23:01:43 +03:00
|
|
|
|
2022-11-17 09:48:38 +03:00
|
|
|
## These routes can be uncommented for local environment use. ##
|
|
|
|
|
|
|
|
# Route('/dev/clear_entities', dev_api.ClearEntities),
|
2023-06-28 05:21:37 +03:00
|
|
|
# Route('/dev/write_dev_data', dev_api.WriteDevData),
|
|
|
|
Route('/dev/mock_login', login_api.MockLogin),
|
2022-11-17 09:48:38 +03:00
|
|
|
]
|
2021-09-23 23:01:43 +03:00
|
|
|
# All requests to the app-py3 GAE service are handled by this Flask app.
|
|
|
|
app = basehandlers.FlaskApplication(
|
2022-02-16 00:31:27 +03:00
|
|
|
__name__,
|
2022-09-13 21:54:32 +03:00
|
|
|
(metrics_chart_routes + api_routes + mpa_page_routes + spa_page_routes +
|
2023-03-27 23:54:05 +03:00
|
|
|
internals_routes + dev_routes))
|
2021-09-23 23:01:43 +03:00
|
|
|
|
|
|
|
# TODO(jrobbins): Make the CSP handler be a class like our others.
|
|
|
|
app.add_url_rule(
|
|
|
|
'/csp', view_func=csp.report_handler,
|
|
|
|
methods=['POST'])
|
2021-08-18 01:35:08 +03:00
|
|
|
|
2022-06-11 00:56:40 +03:00
|
|
|
sendemail.add_routes(app)
|
2021-08-18 01:35:08 +03:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
# This is used when running locally only. When deploying to Google App
|
|
|
|
# Engine, a webserver process such as Gunicorn will serve the app. This
|
|
|
|
# can be configured by adding an `entrypoint` to app.yaml.
|
2022-01-25 22:11:39 +03:00
|
|
|
app.run(host='127.0.0.1', port=8080)
|