Remove all references to django (#2358)

* Remove all references to django

Replace any functionality with flask

* more cleanup

* fix template test after removing empty comment

* remove unused test_app
This commit is contained in:
James C Scott III 2022-10-19 13:51:39 -04:00 коммит произвёл GitHub
Родитель 385d62374b
Коммит ad9ee9ae31
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
39 изменённых файлов: 95 добавлений и 139 удалений

Просмотреть файл

@ -41,8 +41,6 @@ app_engine_apis: true
env_variables:
GAE_USE_SOCKETS_HTTPLIB : ''
DJANGO_SETTINGS_MODULE: 'settings'
DJANGO_SECRET: 'this-is-a-secret'
# Redis envs
REDISHOST: '10.231.56.251'
REDISPORT: '6379'

Просмотреть файл

@ -41,8 +41,6 @@ app_engine_apis: true
env_variables:
GAE_USE_SOCKETS_HTTPLIB : ''
DJANGO_SETTINGS_MODULE: 'settings'
DJANGO_SECRET: 'this-is-a-secret'
# Redis envs
REDISHOST: '10.250.3.187'
REDISPORT: '6379'

Просмотреть файл

@ -1,8 +1,6 @@
import os
import sys
import importlib
# name of the django settings module
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
# Add libraries to pkg_resources working set to find the distribution.
import pkg_resources

Просмотреть файл

@ -6,7 +6,7 @@ class ChromedashLegend extends LitElement {
static get properties() {
return {
opened: {type: Boolean, reflect: true},
views: {attribute: false}, // Assigned in features-page.js, value from Django
views: {attribute: false}, // Assigned in features-page.js, value from Flask
};
}

Просмотреть файл

@ -2,7 +2,7 @@
This doc covers some basic overview of the codebase to help developers navigate.
In summary, this web app is using a combination of Django & Flask as the backend and uses Lit webcomponents in the front end.
In summary, this web app is using Flask as the backend and uses Lit webcomponents in the front end.
It uses [Sign in with Google](https://developers.google.com/identity/gsi/web) for authentication.
**Google Cloud Datastore** is used as database.
@ -10,12 +10,13 @@ It uses [Sign in with Google](https://developers.google.com/identity/gsi/web) fo
In the Backend,
- **Django** is used just for HTML templates (see `FlaskHandler.render()` in `Framework/basehandlers.py`).
- **Flask** is being used for all the request handlers (see `basehandlers.py` and all the code under `api/` and `pages/`).
- **Flask** is being used for:
- All the request handlers (see `basehandlers.py` and all the code under `api/` and `pages/`).
- HTML templates (see `FlaskHandler.render()` in `framework/basehandlers.py`).
HISTORY:-
- The app used to use a combination of Django plus Webapp2. However, now it uses Django plus Flask as mentioned above.
- The app used to use a combination of Django plus Webapp2. However, now it uses Flask as mentioned above.
- The app used to use _DB Client Library_ for interacting with Google Cloud DataStore. It was later replaced by _NDB Client Library_. Now, it uses the _Cloud NDB Library_
## Front end
@ -24,10 +25,10 @@ Front end codes exist in two parts: main site (including admin) and http2push.
### Main site page renderring
All the pages are rendered in a combination of Django template (`/templates`) and front-end components (`/client-src/elements`).
All the pages are rendered in a combination of Jinja2 template (`/templates`) and front-end components (`/client-src/elements`).
1. `/templates/base.html` and `/templates/base_embed.html` are the html skeleton.
1. Templates in `/templates` (extend the `_base.html` or `_embed_base.html`) are the Django templates for each page.
1. Templates in `/templates` (extend the `_base.html` or `_embed_base.html`) are the Jinja2 templates for each page.
- The folder organization and template file names matches the router. (See `template_path=os.path.join(path + '.html')` in `server.py`)
- lit-element components, css, js files are all imported/included in those templates.
- We pass backend variables to js like this: `const variableInJs = {{variable_in_template|safe}}`.

Просмотреть файл

@ -37,19 +37,12 @@ from internals import approval_defs
from internals import core_models
from internals import user_models
from django.template.loader import render_to_string
import django
from google.auth.transport import requests
from flask import session
from flask import render_template
from flask_cors import CORS
import sys
# Initialize django so that it'll function when run as a standalone script.
# https://django.readthedocs.io/en/latest/releases/1.7.html#standalone-scripts
django.setup()
# Our API responses are prefixed with this ro prevent attacks that
# exploit <script src="...">. See go/xssi.
XSSI_PREFIX = ')]}\'\n';
@ -361,7 +354,7 @@ class FlaskHandler(BaseHandler):
return common_data
def render(self, template_data, template_path):
return render_to_string(template_path, template_data)
return render_template(template_path, **template_data)
def get(self, *args, **kwargs):
"""GET handlers can render templates, return JSON, or do redirects."""
@ -568,7 +561,7 @@ def FlaskApplication(import_name, routes, post_routes, pattern_base='', debug=Fa
"""Make a Flask app and add routes and handlers that work like webapp2."""
app = flask.Flask(import_name,
template_folder=settings.flask_compat_get_template_path())
template_folder=settings.get_flask_template_path())
app.original_wsgi_app = app.wsgi_app # Only for unit tests.
app.wsgi_app = ndb_wsgi_middleware(app.wsgi_app) # For Cloud NDB Context
# For GAE legacy libraries
@ -604,7 +597,7 @@ def FlaskApplication(import_name, routes, post_routes, pattern_base='', debug=Fa
# In production, it will return a status 400.
app.config["TRAP_BAD_REQUEST_ERRORS"] = settings.DEV_MODE
# Flask apps also have a debug setting that can be used to auto-reload
# template source code, but we use django for that.
# template source code. TODO: investigate using the setting.
# Set the CORS HEADERS.
CORS(app, resources={r'/data/*': {'origins': '*'}})

Просмотреть файл

@ -577,7 +577,8 @@ class FlaskHandlerTests(testing_config.CustomTestCase):
def test_render(self):
"""We can render a simple template to a string."""
actual = self.handler.render({'name': 'literal'}, 'test_template.html')
with test_app.app_context():
actual = self.handler.render({'name': 'literal'}, 'test_template.html')
self.assertIn('Hi literal', actual)
def test_get__remove_www(self):

Просмотреть файл

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en" xmlns="http://www.w3.org/2005/Atom"><title>Local testing - test feed</title><link href="https://host/samples" rel="alternate"></link><id>https://host/samples</id><updated>2017-10-07T00:00:00Z</updated></feed>
<feed xml:lang="en" xmlns="http://www.w3.org/2005/Atom"><title>Local testing - test feed</title><link href="https://host/samples" rel="alternate"></link><id>https://host/samples</id><updated>2017-10-07T00:00:00Z</updated><subtitle>New features exposed to web developers</subtitle></feed>

Просмотреть файл

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en" xmlns="http://www.w3.org/2005/Atom"><title>Local testing - test feed</title><link href="https://host/samples" rel="alternate"></link><id>https://host/samples</id><updated>2021-07-27T12:25:00Z</updated><entry><title>feature one</title><link href="https://host/feature/12345678" rel="alternate"></link><published>2021-07-27T12:25:00Z</published><author><name>Local testing</name></author><id>tag:host,2021-07-27:/feature/12345678/</id><summary type="html">one for testing</summary><category term="CSS"></category></entry><entry><title>feature two</title><link href="https://host/feature/23456789" rel="alternate"></link><published>2021-06-03T11:22:00Z</published><author><name>Local testing</name></author><id>tag:host,2021-06-03:/feature/23456789/</id><summary type="html">two for testing</summary><category term="Device"></category></entry></feed>
<feed xml:lang="en" xmlns="http://www.w3.org/2005/Atom"><title>Local testing - test feed</title><link href="https://host/samples" rel="alternate"></link><id>https://host/samples</id><updated>2021-07-27T12:25:00Z</updated><subtitle>New features exposed to web developers</subtitle><entry><title>feature one</title><link href="https://host/feature/12345678" rel="alternate"></link><published>2021-07-27T12:25:00Z</published><updated>2021-07-27T12:25:00Z</updated><author><name>Local testing</name></author><id>tag:host,2021-07-27:/feature/12345678</id><summary type="html">one for testing</summary><category term="CSS"></category></entry><entry><title>feature two</title><link href="https://host/feature/23456789" rel="alternate"></link><published>2021-06-03T11:22:00Z</published><updated>2021-06-03T11:22:00Z</updated><author><name>Local testing</name></author><id>tag:host,2021-06-03:/feature/23456789</id><summary type="html">two for testing</summary><category term="Device"></category></entry></feed>

Просмотреть файл

@ -23,7 +23,7 @@ import traceback
from framework import users
import settings
from django.utils import feedgenerator
from feedgenerator.django.utils import feedgenerator
def normalized_name(val):

Просмотреть файл

@ -109,7 +109,7 @@ class UtilsFunctionTests(unittest.TestCase):
self.assertEqual('/request/path', handlerInstance.redirected_to)
# For empty feeds, django sets the updated date to utcnow().
@mock.patch('django.utils.feedgenerator.SyndicationFeed.latest_post_date')
@mock.patch('feedgenerator.django.utils.feedgenerator.SyndicationFeed.latest_post_date')
def test_render_atom_feed__empty(self, mock_latest_post_date):
"""It can render a feed with zero items."""
mock_latest_post_date.return_value = datetime.datetime(2017, 10, 7)

Просмотреть файл

@ -24,8 +24,7 @@ import urllib
from framework import permissions
from google.cloud import ndb
from django.utils.html import conditional_escape as escape
from flask import escape
from flask import render_template
from framework import basehandlers
@ -75,7 +74,6 @@ def format_email_body(is_update, feature, changes):
}
template_path = ('update-feature-email.html' if is_update
else 'new-feature-email.html')
# final_full_path = os.path.join(settings.TEMPLATES[0]['DIRS'][0], template_path)
body = render_template(template_path, **body_data)
return body

Просмотреть файл

@ -32,7 +32,7 @@ from internals import user_models
import settings
test_app = flask.Flask(__name__,
template_folder=settings.flask_compat_get_template_path())
template_folder=settings.get_flask_template_path())
# Load testdata to be used across all of the CustomTestCases
TESTDATA = testing_config.Testdata(__file__)

Просмотреть файл

@ -17,7 +17,7 @@ import json
import logging
import requests
from django.template.loader import render_to_string
from flask import render_template
from framework import basehandlers
from internals import core_models
@ -53,7 +53,7 @@ def build_email_tasks(
'milestone': mstone,
'beta_date_str': beta_date_str,
}
html = render_to_string(body_template_path, body_data)
html = render_template(body_template_path, **body_data)
subject = subject_format % feature.name
for owner in feature.owner:
email_tasks.append({

Просмотреть файл

@ -13,6 +13,8 @@
# limitations under the License.
import testing_config # Must be imported before the module under test.
import flask
import settings
from datetime import datetime
from unittest import mock
@ -21,6 +23,8 @@ from internals import reminders
from google.cloud import ndb
test_app = flask.Flask(__name__,
template_folder=settings.get_flask_template_path())
# Load testdata to be used across all of the CustomTestCases
TESTDATA = testing_config.Testdata(__file__)
@ -63,10 +67,11 @@ class FunctionTest(testing_config.CustomTestCase):
self.maxDiff = None
def test_build_email_tasks_feature_accuracy(self):
actual = reminders.build_email_tasks(
[(self.feature_template, 100)], '[Action requested] Update %s',
reminders.FeatureAccuracyHandler.EMAIL_TEMPLATE_PATH,
self.current_milestone_info)
with test_app.app_context():
actual = reminders.build_email_tasks(
[(self.feature_template, 100)], '[Action requested] Update %s',
reminders.FeatureAccuracyHandler.EMAIL_TEMPLATE_PATH,
self.current_milestone_info)
self.assertEqual(1, len(actual))
task = actual[0]
self.assertEqual('feature_owner@example.com', task['to'])
@ -77,10 +82,11 @@ class FunctionTest(testing_config.CustomTestCase):
TESTDATA['test_build_email_tasks_feature_accuracy.html'], task['html'])
def test_build_email_tasks_prepublication(self):
actual = reminders.build_email_tasks(
[(self.feature_template, 100)], '[Action requested] Update %s',
reminders.PrepublicationHandler.EMAIL_TEMPLATE_PATH,
self.current_milestone_info)
with test_app.app_context():
actual = reminders.build_email_tasks(
[(self.feature_template, 100)], '[Action requested] Update %s',
reminders.PrepublicationHandler.EMAIL_TEMPLATE_PATH,
self.current_milestone_info)
self.assertEqual(1, len(actual))
task = actual[0]
self.assertEqual('feature_owner@example.com', task['to'])
@ -117,7 +123,8 @@ class FeatureAccuracyHandlerTest(testing_config.CustomTestCase):
text=('{"mstones":[{"mstone": "100", '
'"earliest_beta": "2022-08-01T01:23:45"}]}'))
mock_get.return_value = mock_return
result = self.handler.get_template_data()
with test_app.app_context():
result = self.handler.get_template_data()
expected = {'message': '1 email(s) sent or logged.'}
self.assertEqual(result, expected)
@ -127,7 +134,8 @@ class FeatureAccuracyHandlerTest(testing_config.CustomTestCase):
text=('{"mstones":[{"mstone": "148", '
'"earliest_beta": "2024-02-03T01:23:45"}]}'))
mock_get.return_value = mock_return
result = self.handler.get_template_data()
with test_app.app_context():
result = self.handler.get_template_data()
expected = {'message': '2 email(s) sent or logged.'}
self.assertEqual(result, expected)

Просмотреть файл

@ -61,7 +61,6 @@
</table>
</p>
</br>
<p>
@ -78,4 +77,4 @@
</br>
<b><a href="http://127.0.0.1:8888/guide/verify_accuracy/123">
http://127.0.0.1:8888/guide/verify_accuracy/123
</a></b>
</a></b>

Просмотреть файл

@ -59,4 +59,4 @@ publication.</p>
the cache on top frame origins helps the browser deflect
side-channel attacks where one site can detect resources in another
site's cache.
</p>
</p>

Просмотреть файл

@ -17,8 +17,6 @@ vpc_access_connector:
name: projects/cr-status-staging/locations/us-central1/connectors/redis-connector
env_variables:
DJANGO_SETTINGS_MODULE: 'settings'
DJANGO_SECRET: 'this-is-a-secret'
# Redis envs
REDISHOST: '10.231.56.251'
REDISPORT: '6379'

Просмотреть файл

@ -17,8 +17,6 @@ vpc_access_connector:
name: projects/cr-status/locations/us-central1/connectors/redis-connector
env_variables:
DJANGO_SETTINGS_MODULE: 'settings'
DJANGO_SECRET: 'this-is-a-secret'
# Redis envs for prod
REDISHOST: '10.250.3.187'
REDISPORT: '6379'

Просмотреть файл

@ -61,7 +61,7 @@ class BlinkHandler(basehandlers.FlaskHandler):
possible_subscribers = user_models.FeatureOwner.query().order(
user_models.FeatureOwner.name).fetch(None)
# Format for django template
# Format for template
possible_subscriber_dicts = [
{'id': fo.key.integer_id(), 'email': fo.email}
for fo in possible_subscribers]

Просмотреть файл

@ -19,12 +19,14 @@ from unittest import mock
import flask
import werkzeug
import html5lib
import settings
from google.cloud import ndb
from pages import blink_handler
from internals import user_models
test_app = flask.Flask(__name__)
test_app = flask.Flask(__name__,
template_folder=settings.get_flask_template_path())
# Load testdata to be used across all of the CustomTestCases
TESTDATA = testing_config.Testdata(__file__)
@ -78,8 +80,9 @@ class BlinkTemplateTest(testing_config.CustomTestCase):
def test_html_rendering(self):
"""We can render the template with valid html."""
template_text = self.handler.render(
self.template_data, self.full_template_path)
with test_app.app_context():
template_text = self.handler.render(
self.template_data, self.full_template_path)
parser = html5lib.HTMLParser(strict=True)
document = parser.parse(template_text)
# TESTDATA.make_golden(template_text, 'BlinkTemplateTest_test_html_rendering.html')
@ -149,8 +152,9 @@ class SubscribersTemplateTest(testing_config.CustomTestCase):
def test_html_rendering(self):
"""We can render the template with valid html."""
template_text = self.handler.render(
self.template_data, self.full_template_path)
with test_app.app_context():
template_text = self.handler.render(
self.template_data, self.full_template_path)
parser = html5lib.HTMLParser(strict=True)
document = parser.parse(template_text)
# TESTDATA.make_golden(template_text, 'SubscribersTemplateTest_test_html_rendering.html')

Просмотреть файл

@ -18,6 +18,7 @@ import os
import flask
import werkzeug
import html5lib
import settings
from internals import core_enums
from internals import core_models
@ -25,7 +26,8 @@ from internals import user_models
from pages import featurelist
from framework import rediscache
test_app = flask.Flask(__name__)
test_app = flask.Flask(__name__,
template_folder=settings.get_flask_template_path())
# Load testdata to be used across all of the CustomTestCases
TESTDATA = testing_config.Testdata(__file__)
@ -140,8 +142,9 @@ class FeatureListTemplateTest(TestWithFeature):
def test_html_rendering(self):
"""We can render the template with valid html."""
template_text = self.handler.render(
self.template_data, self.full_template_path)
with test_app.app_context():
template_text = self.handler.render(
self.template_data, self.full_template_path)
parser = html5lib.HTMLParser(strict=True)
document = parser.parse(template_text)
# TESTDATA.make_golden(template_text, 'test_html_rendering.html')

Просмотреть файл

@ -20,13 +20,15 @@ import os
import flask
import werkzeug
import html5lib
import settings
from google.cloud import ndb
from pages import intentpreview
from internals import core_enums
from internals import core_models
test_app = flask.Flask(__name__)
test_app = flask.Flask(__name__,
template_folder=settings.get_flask_template_path())
# Load testdata to be used across all of the CustomTestCases
TESTDATA = testing_config.Testdata(__file__)
@ -228,9 +230,9 @@ class IntentEmailPreviewTemplateTest(testing_config.CustomTestCase):
actual_data['xsrf_token'] = ''
actual_data['xsrf_token_expires'] = 0
template_text = self.handler.render(
actual_data, self.full_template_path)
testing_config.sign_out()
template_text = self.handler.render(
actual_data, self.full_template_path)
testing_config.sign_out()
parser = html5lib.HTMLParser(strict=True)
document = parser.parse(template_text)
# TESTDATA.make_golden(template_text, 'test_html_rendering.html')

Просмотреть файл

@ -76,7 +76,6 @@ limitations under the License.
</head>
<body class="loading" data-path="/admin/blink.html?">
<div id="app-content-container">
<div>
@ -281,4 +280,4 @@ document.body.classList.remove('loading');
<script type="module" nonce="fake nonce" src="/static/js/shared.min.js?v=Undeployed"></script>
</body>
</html>
</html>

Просмотреть файл

@ -76,7 +76,6 @@ limitations under the License.
</head>
<body class="loading" data-path="/admin/subscribers.html?">
<div id="app-content-container">
<div>
@ -220,4 +219,4 @@ document.body.classList.remove('loading');
<script type="module" nonce="fake nonce" src="/static/js/shared.min.js?v=Undeployed"></script>
</body>
</html>
</html>

Просмотреть файл

@ -78,7 +78,6 @@ limitations under the License.
</head>
<body class="loading" data-path="/subclasses fill this in?">
<div id="app-content-container">
<div>
@ -107,10 +106,8 @@ limitations under the License.
<div id="column-container">
<div id="drawer-column">
<h3>Filter By</h3>
<!-- Use single quote here. The value is a json string with double quote. -->
<chromedash-metadata implstatuses='[{"key": 1, "val": "No active development"}, {"key": 2, "val": "Proposed"}, {"key": 3, "val": "In development"}, {"key": 4, "val": "In developer trial (Behind a flag)"}, {"key": 5, "val": "Enabled by default"}, {"key": 6, "val": "Deprecated"}, {"key": 7, "val": "Removed"}, {"key": 8, "val": "Origin trial"}, {"key": 9, "val": "Browser Intervention"}, {"key": 10, "val": "On hold"}, {"key": 1000, "val": "No longer pursuing"}]'></chromedash-metadata>
</div>
<div id="content-column">
<div id="subheader">
@ -125,7 +122,7 @@ limitations under the License.
</div>
</div>
<chromedash-featurelist
user="{&quot;can_create_feature&quot;: true, &quot;can_approve&quot;: true, &quot;can_edit_all&quot;: true, &quot;is_admin&quot;: true, &quot;editable_features&quot;: [], &quot;email&quot;: &quot;admin@example.com&quot;, &quot;dismissed_cues&quot;: &quot;[]&quot;}"
user="{&#34;can_create_feature&#34;: true, &#34;can_approve&#34;: true, &#34;can_edit_all&#34;: true, &#34;is_admin&#34;: true, &#34;editable_features&#34;: [], &#34;email&#34;: &#34;admin@example.com&#34;, &#34;dismissed_cues&#34;: &#34;[]&#34;}"
signedInUser="admin@example.com"
isSiteEditor
editableFeatures="[]"
@ -170,4 +167,4 @@ limitations under the License.
<script type="module" nonce="fake nonce" src="/static/js/shared.min.js?v=Undeployed"></script>
</body>
</html>
</html>

Просмотреть файл

@ -77,7 +77,6 @@ limitations under the License.
</head>
<body class="loading" data-path="/admin/features/launch/5/234?intent">
<div id="app-content-container">
<div>
@ -273,7 +272,6 @@ False
<br><br><h4>Link to entry on the Local testing</h4>
<a href="http://localhost/feature/234">http://localhost/feature/234</a>
@ -288,7 +286,6 @@ False
</small></div>
</div> <!-- end email body div -->
</section>
@ -334,4 +331,4 @@ False
<script type="module" nonce="fake nonce" src="/static/js/shared.min.js?v=Undeployed"></script>
</body>
</html>
</html>

Просмотреть файл

@ -76,7 +76,6 @@ limitations under the License.
</head>
<body class="loading" data-path="/request_path?">
<div id="app-content-container">
<div>
@ -139,4 +138,4 @@ limitations under the License.
<script type="module" nonce="fake nonce" src="/static/js/shared.min.js?v=Undeployed"></script>
</body>
</html>
</html>

Просмотреть файл

@ -16,6 +16,7 @@ import testing_config # Must be imported first
import flask
import html5lib
import settings
from google.cloud import ndb
from unittest import mock
@ -23,7 +24,8 @@ from unittest import mock
from internals import user_models
from pages import users
test_app = flask.Flask(__name__)
test_app = flask.Flask(__name__,
template_folder=settings.get_flask_template_path())
# Load testdata to be used across all of the CustomTestCases
@ -55,8 +57,9 @@ class UsersListTemplateTest(testing_config.CustomTestCase):
def test_html_rendering(self):
"""We can render the template with valid html."""
template_text = self.handler.render(
self.template_data, self.full_template_path)
with test_app.app_context():
template_text = self.handler.render(
self.template_data, self.full_template_path)
parser = html5lib.HTMLParser(strict=True)
document = parser.parse(template_text)
# TESTDATA.make_golden(template_text, 'test_html_rendering.html')

Просмотреть файл

@ -4,7 +4,6 @@
# Py3 Libraries
appengine-python-standard>=1.0.0
html5lib==1.1
Django==3.2.15
funcsigs==1.0.2
google-api-python-client==2.47.0
google-python-cloud-debugger==2.18
@ -15,7 +14,7 @@ google-auth==1.31.0
requests==2.27.1
redis==4.3.4
fakeredis==1.9.0
feedgenerator==2.0.0
Flask==2.1.2
flask-cors==3.0.10
funcsigs==1.0.2

Просмотреть файл

@ -8,8 +8,6 @@ export PYTHONPATH=cs-env/lib/python3.9/site-packages:$PYTHONPATH
export GOOGLE_CLOUD_PROJECT='cr-status-staging'
export SERVER_SOFTWARE='gunicorn'
export GAE_ENV='localdev'
export DJANGO_SETTINGS_MODULE='settings'
export DJANGO_SECRET='this-is-a-secret'
export DATASTORE_EMULATOR_HOST='localhost:15606'

Просмотреть файл

@ -2,37 +2,12 @@ import logging
import os
#Hack to get custom tags working django 1.3 + python27.
INSTALLED_APPS = [
#'nothing',
'django.forms'
]
ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(ROOT_DIR, 'templates')],
'APP_DIRS': True,
},
]
def flask_compat_get_template_path() -> str:
def get_flask_template_path() -> str:
"""Returns a path to the templates.
Leverages the existing TEMPLATES variable used for Django templates and
returns a path usable by Flask/Jinja2.
This is useful because by default flask.render_template will look for a
template folder relative to the module.
Once all Django templates are completely converted to Jinja2, a simpler
variable TEMPLATES could be used to hold information about the templates.
"""
return TEMPLATES[0]['DIRS'][0]
# This is necessary to override django templates.
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
return os.path.join(ROOT_DIR, 'templates')
# By default, send all email to an archive for debugging.
# For the live cr-status server, this setting is None.
@ -123,8 +98,6 @@ elif APP_ID == 'cr-status-staging':
else:
logging.error('Unexpected app ID %r, please configure settings.py.', APP_ID)
SECRET_KEY = os.environ['DJANGO_SECRET']
RSS_FEED_LIMIT = 15
DEFAULT_CACHE_TIME = 3600 # seconds

Просмотреть файл

@ -74,8 +74,6 @@ limitations under the License.
</head>
<body class="loading" data-path="{{current_path}}">
{% comment %}
{% endcomment %}
<div id="app-content-container">
<div>
@ -118,11 +116,11 @@ limitations under the License.
<script src="https://www.googletagmanager.com/gtag/js?id=UA-179341418-1"
async nonce="{{nonce}}"></script>
{% comment %}
{#
Note that the following script tag must include type="module" so that the form field event listeners
attached by shared.min.js will not be attached until after Shoelace event listeners are attached.
See https://github.com/GoogleChrome/chromium-dashboard/issues/2014
{% endcomment %}
#}
<script type="module" nonce="{{nonce}}" src="/static/js/shared.min.js?v={{app_version}}"></script>
</body>
</html>

Просмотреть файл

@ -28,7 +28,7 @@
<section>
{% comment %}
{#
<!--<p>Start typing a component name:</p>
<input list="components" name="components" placeholder="{{components.0}}>Animation"></label>
<datalist id="components">
@ -44,7 +44,7 @@
{% endfor %}
</select>
</template>-->
{% endcomment %}
#}
<ul id="components_list">
{% for c in components %}
@ -59,7 +59,7 @@
<div class="owners_list layout horizontal center">
<div>
<div class="column_header">Receives email updates:</div>
<select multiple disabled id="owner_list_{{forloop.counter}}" size="{{c.computed_subscribers|length}}">
<select multiple disabled id="owner_list_{{loop.index}}" size="{{c.computed_subscribers|length}}">
{% for s in c.computed_subscribers %}
<option class="owner_name {% if s.name in c.computed_owners %}component_owner{% endif %}"
value="{{s.id}}">{{s.name}}: {{s.email}}</option>
@ -76,9 +76,9 @@
</select><br>
<label title="Toggles the user as an owner. If you click 'Remove' ans this is not checked, the user is removed from the component.">Owner? <input type="checkbox" class="is_primary_checkbox"></label>
</div>
<button class="add_owner_button" data-index="{{forloop.counter}}"
<button class="add_owner_button" data-index="{{loop.index}}"
data-component-name="{{c.name}}">Add</button>
<button class="remove_owner_button" data-index="{{forloop.counter}}"
<button class="remove_owner_button" data-index="{{loop.index}}"
data-component-name="{{c.name}}">Remove</button>
</div>
</div>

Просмотреть файл

@ -24,7 +24,7 @@
<h3 class="channels-title" title="Select a version to only show features for that milestone">Show features in:</h3>
<!-- <a href="?showFeatures">show all</a> | <a href="/admin/subscribers">hide all</a> -->
</div>
{% for key,channel in channels.items %}
{% for key,channel in channels.items() %}
<div class="chrome_version layout horizontal center chrome_version--{{key}} {% if selected_milestone == channel.mstone %}highlight{% endif %}" title="Show only features for the current {{key}}">
<a href="?showFeatures&amp;milestone={{channel.mstone}}" class="layout horizontal center">
<div class="chrome-logo"></div>

Просмотреть файл

@ -9,10 +9,10 @@
{{feature.name}}
</div>
{% comment %}
{#
Insted of vertical margins, <br> elements are used to create line breaks
that can be copied and pasted into a text editor.
{% endcomment %}
#}
<p>Body
<span class="tooltip copy-text" style="float:right"
@ -29,14 +29,14 @@
<h4>Contact emails</h4>
{% if not feature.browsers.chrome.owners %}None{% endif %}
{% for owner in feature.browsers.chrome.owners %}
<a href="mailto:{{owner}}">{% if forloop.last %}{{owner}}</a>{% else %}{{owner}}</a>,{% endif %}
<a href="mailto:{{owner}}">{% if loop.last %}{{owner}}</a>{% else %}{{owner}}</a>,{% endif %}
{% endfor %}
{% if feature.explainer_links or feature.feature_type_int != 2 %}
<br><br><h4>Explainer</h4>
{% if not feature.explainer_links %}None{% endif %}
{% for link in feature.explainer_links %}
{% if forloop.counter0 %}<br>{% endif %}<a href="{{link}}">{{link}}</a>
{% if loop.index0 %}<br>{% endif %}<a href="{{link}}">{{link}}</a>
{% endfor %}
{% endif %}
@ -69,7 +69,7 @@
{% if feature.tags %}
<br><br><h4>Search tags</h4>
{% for tag in feature.tags %}
<a href="/features#tags:{{tag}}">{{tag}}</a>{% if not forloop.last %}, {% endif %}
<a href="/features#tags:{{tag}}">{{tag}}</a>{% if not loop.last %}, {% endif %}
{% endfor %}
{% endif %}
@ -232,7 +232,7 @@
<br><br><h4>Estimated milestones</h4>
{% include "../estimated-milestones-table.html" %}
{% include "estimated-milestones-table.html" %}
{% if 'anticipated_spec_changes' in sections_to_show or feature.anticipated_spec_changes %}

Просмотреть файл

@ -1,6 +1,5 @@
{% extends "_base.html" %}
{% load cache %}
{% block rss %}
<link rel="alternate" type="application/rss+xml" href="/features.xml" title="All features" />
@ -14,10 +13,8 @@
<div id="column-container">
<div id="drawer-column">
<h3>Filter By</h3>
{% cache TEMPLATE_CACHE_TIME chromedashmetadata %}
<!-- Use single quote here. The value is a json string with double quote. -->
<chromedash-metadata implstatuses='{{IMPLEMENTATION_STATUSES|safe}}'></chromedash-metadata>
{% endcache %}
</div>
<div id="content-column">
<div id="subheader">

Просмотреть файл

@ -80,11 +80,11 @@ limitations under the License.
<script src="https://www.googletagmanager.com/gtag/js?id=UA-179341418-1" async nonce="{{nonce}}"></script>
{% comment %}
{#
Note that the following script tag must include type="module" so that the form field event listeners
attached by shared.min.js will not be attached until after Shoelace event listeners are attached.
See https://github.com/GoogleChrome/chromium-dashboard/issues/2014
{% endcomment %}
#}
<script type="module" nonce="{{nonce}}" src="/static/js/shared.min.js?v={{app_version}}"></script>
</body>

Просмотреть файл

@ -19,10 +19,8 @@ import unittest
from google.cloud import ndb
from pathlib import Path
os.environ['DJANGO_SECRET'] = 'test secret'
os.environ['SERVER_SOFTWARE'] = 'test ' + os.environ.get('SERVER_SOFTWARE', '')
os.environ['CURRENT_VERSION_ID'] = 'test.123'
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
os.environ['APPLICATION_ID'] = 'testing'
# Envs for datastore-emulator, same as running `gcloud beta emulators datastore env-init`.
os.environ['DATASTORE_DATASET'] = 'cr-status-staging'