Procházet zdrojové kódy

Merge branch 'develop' into doc_conficts_ux

version-14
Suraj Shetty před 3 roky
committed by GitHub
rodič
revize
94f61fc3ba
V databázi nebyl nalezen žádný známý klíč pro tento podpis ID GPG klíče: 4AEE18F83AFDEB23
22 změnil soubory, kde provedl 197 přidání a 86 odebrání
  1. +22
    -0
      .github/workflows/deps-checker.yml
  2. +2
    -2
      frappe/__init__.py
  3. +9
    -9
      frappe/database/postgres/database.py
  4. +17
    -2
      frappe/model/base_document.py
  5. +1
    -4
      frappe/oauth.py
  6. +0
    -1
      frappe/public/js/desk.bundle.js
  7. +8
    -5
      frappe/public/js/frappe/utils/help.js
  8. +4
    -0
      frappe/public/js/frappe/utils/utils.js
  9. +1
    -1
      frappe/public/js/frappe/widgets/onboarding_widget.js
  10. +1
    -1
      frappe/public/js/video_player.bundle.js
  11. +4
    -2
      frappe/templates/includes/navbar/navbar_items.html
  12. +3
    -1
      frappe/templates/includes/web_block.html
  13. +1
    -1
      frappe/tests/test_commands.py
  14. +31
    -26
      frappe/tests/test_db.py
  15. +18
    -7
      frappe/tests/test_oauth20.py
  16. +1
    -1
      frappe/twofactor.py
  17. +21
    -2
      frappe/utils/jinja_globals.py
  18. +16
    -7
      frappe/website/doctype/web_page/templates/web_page.html
  19. +23
    -11
      frappe/website/doctype/web_page/web_page.py
  20. +8
    -1
      frappe/website/doctype/web_page_block/web_page_block.json
  21. +5
    -1
      frappe/www/contact.html
  22. +1
    -1
      pyproject.toml

+ 22
- 0
.github/workflows/deps-checker.yml Zobrazit soubor

@@ -0,0 +1,22 @@
name: 'Python Dependency Check'
on:
pull_request:
workflow_dispatch:
push:
branches: [ develop ]

permissions:
contents: read

jobs:
deps-vulnerable-check:
name: 'Vulnerable Dependency'
runs-on: ubuntu-latest

steps:
- uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: actions/checkout@v3
- run: pip install pip-audit
- run: pip-audit ${GITHUB_WORKSPACE}

+ 2
- 2
frappe/__init__.py Zobrazit soubor

@@ -2231,14 +2231,14 @@ def get_website_settings(key):
if not hasattr(local, "website_settings"):
local.website_settings = db.get_singles_dict("Website Settings", cast=True)

return local.website_settings[key]
return local.website_settings.get(key)


def get_system_settings(key):
if not hasattr(local, "system_settings"):
local.system_settings = db.get_singles_dict("System Settings", cast=True)

return local.system_settings[key]
return local.system_settings.get(key)


def get_active_domains():


+ 9
- 9
frappe/database/postgres/database.py Zobrazit soubor

@@ -403,13 +403,12 @@ def modify_query(query):


def modify_values(values):
def stringify_value(value):
if isinstance(value, int):
def modify_value(value):
if isinstance(value, (list, tuple)):
value = tuple(modify_values(value))

elif isinstance(value, int):
value = str(value)
elif isinstance(value, float):
truncated_float = int(value)
if value == truncated_float:
value = str(truncated_float)

return value

@@ -418,14 +417,15 @@ def modify_values(values):

if isinstance(values, dict):
for k, v in values.items():
values[k] = stringify_value(v)
values[k] = modify_value(v)
elif isinstance(values, (tuple, list)):
new_values = []
for val in values:
new_values.append(stringify_value(val))
new_values.append(modify_value(val))

values = new_values
else:
values = stringify_value(values)
values = modify_value(values)

return values



+ 17
- 2
frappe/model/base_document.py Zobrazit soubor

@@ -123,8 +123,23 @@ class BaseDocument(object):
return meta

def __getstate__(self):
self._meta = None
return self.__dict__
"""
Called when pickling.
Returns a copy of `__dict__` excluding unpicklable values like `_meta`.

More info: https://docs.python.org/3/library/pickle.html#handling-stateful-objects
"""

# Always use the dict.copy() method to avoid modifying the original state
state = self.__dict__.copy()
self.remove_unpicklable_values(state)

return state

def remove_unpicklable_values(self, state):
"""Remove unpicklable values before pickling"""

state.pop("_meta", None)

def update(self, d):
"""Update multiple fields of a doctype using a dictionary of key-value pairs.


+ 1
- 4
frappe/oauth.py Zobrazit soubor

@@ -323,10 +323,7 @@ class OAuthWebRequestValidator(RequestValidator):
# Check whether frappe server URL is set
id_token_header = {"typ": "jwt", "alg": "HS256"}

user = frappe.get_doc(
"User",
frappe.session.user,
)
user = frappe.get_doc("User", request.user)

if request.nonce:
id_token["nonce"] = request.nonce


+ 0
- 1
frappe/public/js/desk.bundle.js Zobrazit soubor

@@ -107,5 +107,4 @@ import "./frappe/utils/dashboard_utils.js";
import "./frappe/ui/chart.js";
import "./frappe/ui/datatable.js";
import "./frappe/ui/driver.js";
import "./frappe/ui/plyr.js";
import "./frappe/scanner";

+ 8
- 5
frappe/public/js/frappe/utils/help.js Zobrazit soubor

@@ -33,13 +33,16 @@ frappe.help.show_video = function (youtube_id, title) {
dialog.show();
dialog.$wrapper.addClass("video-modal");

let plyr = new frappe.Plyr(video[0], {
hideControls: true,
resetOnEnd: true,
});
let plyr;
frappe.utils.load_video_player().then(() => {
plyr = new frappe.Plyr(video[0], {
hideControls: true,
resetOnEnd: true,
});
})

dialog.onhide = () => {
plyr.destroy();
plyr?.destroy();
};
}



+ 4
- 0
frappe/public/js/frappe/utils/utils.js Zobrazit soubor

@@ -1528,5 +1528,9 @@ Object.assign(frappe.utils, {
return [doctype, filter, val[0], val[1], false];
});
}
},

load_video_player() {
return frappe.require("video_player.bundle.js");
}
});

+ 1
- 1
frappe/public/js/frappe/widgets/onboarding_widget.js Zobrazit soubor

@@ -5,6 +5,7 @@ frappe.provide("frappe.utils");
export default class OnboardingWidget extends Widget {

async refresh() {
frappe.utils.load_video_player();
this.new && await this.get_onboarding_data();
this.set_title();
this.set_actions();
@@ -156,7 +157,6 @@ export default class OnboardingWidget extends Widget {
};

toggle_content();
// toggle_video();
}

go_to_page(step) {


frappe/public/js/frappe/ui/plyr.js → frappe/public/js/video_player.bundle.js Zobrazit soubor

@@ -1,3 +1,3 @@
import Plyr from "plyr/dist/plyr.polyfilled";

frappe.Plyr = Plyr;
frappe.Plyr = Plyr;

+ 4
- 2
frappe/templates/includes/navbar/navbar_items.html Zobrazit soubor

@@ -33,14 +33,16 @@
{% else %}

{% if parent %}
{% set url = item.url or '' %}
{% set url = url if url.startswith('#') else url | abs_url %}
<li class="nav-item">
<a class="nav-link" href="{{ (item.url or '')|abs_url }}"
<a class="nav-link" href="{{ url }}"
{% if item.open_in_new_tab %} target="_blank" {% endif %}>
{{ _(item.label) }}
</a>
</li>
{% else %}
<a class="dropdown-item" href="{{ (item.url or '') | abs_url }}"
<a class="dropdown-item" href="{{ url }}"
{% if item.open_in_new_tab %} target="_blank" {% endif %}>
{{ _(item.label) }}
</a>


+ 3
- 1
frappe/templates/includes/web_block.html Zobrazit soubor

@@ -11,7 +11,9 @@

{%- if web_template_type == 'Section' -%}
{%- if not web_block.hide_block -%}
<section class="section {{ classes }}" data-section-idx="{{ web_block.idx | e }}"
<section class="section {{ classes }}"
{% if web_block.section_id %} id="{{ web_block.section_id }}" {% endif %}
data-section-idx="{{ web_block.idx | e }}"
data-section-template="{{ web_block.web_template | e }}"
{% if web_block.add_background_image -%}
style="background: url({{ web_block.background_image}}) no-repeat center center; background-size: cover;"


+ 1
- 1
frappe/tests/test_commands.py Zobrazit soubor

@@ -699,7 +699,7 @@ class TestBenchBuild(BaseTestCommands):
self.assertEqual(result.exit_code, 0)
self.assertEqual(result.exception, None)

CURRENT_SIZE = 3.7 # MB
CURRENT_SIZE = 3.5 # MB
JS_ASSET_THRESHOLD = 0.1

hooks = frappe.get_hooks()


+ 31
- 26
frappe/tests/test_db.py Zobrazit soubor

@@ -511,6 +511,37 @@ class TestDB(unittest.TestCase):

frappe.db.rollback()

@run_only_if(db_type_is.POSTGRES)
def test_modify_query(self):
from frappe.database.postgres.database import modify_query

query = "select * from `tabtree b` where lft > 13 and rgt <= 16 and name =1.0 and parent = 4134qrsdc and isgroup = 1.00045"
self.assertEqual(
"select * from \"tabtree b\" where lft > '13' and rgt <= '16' and name = '1' and parent = 4134qrsdc and isgroup = 1.00045",
modify_query(query),
)

query = (
'select locate(".io", "frappe.io"), locate("3", cast(3 as varchar)), locate("3", 3::varchar)'
)
self.assertEqual(
'select strpos( "frappe.io", ".io"), strpos( cast(3 as varchar), "3"), strpos( 3::varchar, "3")',
modify_query(query),
)

@run_only_if(db_type_is.POSTGRES)
def test_modify_values(self):
from frappe.database.postgres.database import modify_values

self.assertEqual(
{"a": "23", "b": 23.0, "c": 23.0345, "d": "wow", "e": ("1", "2", "3", "abc")},
modify_values({"a": 23, "b": 23.0, "c": 23.0345, "d": "wow", "e": [1, 2, 3, "abc"]}),
)
self.assertEqual(
["23", 23.0, 23.00004345, "wow", ("1", "2", "3", "abc")],
modify_values((23, 23.0, 23.00004345, "wow", [1, 2, 3, "abc"])),
)


@run_only_if(db_type_is.MARIADB)
class TestDDLCommandsMaria(unittest.TestCase):
@@ -813,32 +844,6 @@ class TestDDLCommandsPost(unittest.TestCase):
)
self.assertEqual(len(indexs_in_table), 1)

def test_modify_query(self):
from frappe.database.postgres.database import modify_query

query = "select * from `tabtree b` where lft > 13 and rgt <= 16 and name =1.0 and parent = 4134qrsdc and isgroup = 1.00045"
self.assertEqual(
"select * from \"tabtree b\" where lft > '13' and rgt <= '16' and name = '1' and parent = 4134qrsdc and isgroup = 1.00045",
modify_query(query),
)

query = (
'select locate(".io", "frappe.io"), locate("3", cast(3 as varchar)), locate("3", 3::varchar)'
)
self.assertEqual(
'select strpos( "frappe.io", ".io"), strpos( cast(3 as varchar), "3"), strpos( 3::varchar, "3")',
modify_query(query),
)

def test_modify_values(self):
from frappe.database.postgres.database import modify_values

self.assertEqual(
{"abcd": "23", "efgh": "23", "ijkl": 23.0345, "mnop": "wow"},
modify_values({"abcd": 23, "efgh": 23.0, "ijkl": 23.0345, "mnop": "wow"}),
)
self.assertEqual(["23", "23", 23.00004345, "wow"], modify_values((23, 23.0, 23.00004345, "wow")))

def test_sequence_table_creation(self):
from frappe.core.doctype.doctype.test_doctype import new_doctype



+ 18
- 7
frappe/tests/test_oauth20.py Zobrazit soubor

@@ -16,7 +16,9 @@ class TestOAuth20(unittest.TestCase):
def setUp(self):
make_test_records("OAuth Client")
make_test_records("User")
self.client_id = frappe.get_all("OAuth Client", fields=["*"])[0].get("client_id")
client = frappe.get_all("OAuth Client", fields=["*"])[0]
self.client_id = client.get("client_id")
self.client_secret = client.get("client_secret")
self.form_header = {"content-type": "application/x-www-form-urlencoded"}
self.scope = "all openid"
self.redirect_uri = "http://localhost"
@@ -90,6 +92,9 @@ class TestOAuth20(unittest.TestCase):
self.assertTrue(bearer_token.get("token_type") == "Bearer")
self.assertTrue(check_valid_openid_response(bearer_token.get("access_token")))

decoded_token = self.decode_id_token(bearer_token.get("id_token"))
self.assertEqual(decoded_token["email"], "test@example.com")

def test_login_using_authorization_code_with_pkce(self):
update_client_for_auth_code_grant(self.client_id)

@@ -142,6 +147,9 @@ class TestOAuth20(unittest.TestCase):
self.assertTrue(bearer_token.get("access_token"))
self.assertTrue(bearer_token.get("id_token"))

decoded_token = self.decode_id_token(bearer_token.get("id_token"))
self.assertEqual(decoded_token["email"], "test@example.com")

def test_revoke_token(self):
client = frappe.get_doc("OAuth Client", self.client_id)
client.grant_type = "Authorization Code"
@@ -316,16 +324,19 @@ class TestOAuth20(unittest.TestCase):
# Parse bearer token json
bearer_token = token_response.json()

id_token = bearer_token.get("id_token")
payload = jwt.decode(
payload = self.decode_id_token(bearer_token.get("id_token"))
self.assertEqual(payload["email"], "test@example.com")

self.assertTrue(payload.get("nonce") == nonce)

def decode_id_token(self, id_token):
return jwt.decode(
id_token,
audience=client.client_id,
key=client.client_secret,
audience=self.client_id,
key=self.client_secret,
algorithms=["HS256"],
)

self.assertTrue(payload.get("nonce") == nonce)


def check_valid_openid_response(access_token=None):
"""Return True for valid response."""


+ 1
- 1
frappe/twofactor.py Zobrazit soubor

@@ -279,7 +279,7 @@ def get_email_body_for_qr_code(kwargs_dict):
"""Get QRCode email body."""
body_template = _(
"Please click on the following link and follow the instructions on the page. {0}"
).format("<br><br> {{qrcode_link}}")
).format("<br><br> <a href='{{qrcode_link}}'>{{qrcode_link}}</a>")
body = frappe.render_template(body_template, kwargs_dict)
return body



+ 21
- 2
frappe/utils/jinja_globals.py Zobrazit soubor

@@ -36,6 +36,7 @@ def web_block(template, values=None, **kwargs):


def web_blocks(blocks):
import frappe
from frappe import _, _dict, throw
from frappe.website.doctype.web_page.web_page import get_web_blocks_html

@@ -62,8 +63,26 @@ def web_blocks(blocks):
out = get_web_blocks_html(web_blocks)

html = out.html
for script in out.scripts:
html += "<script>{}</script>".format(script)

if not frappe.flags.web_block_scripts:
frappe.flags.web_block_scripts = {}
frappe.flags.web_block_styles = {}

for template, scripts in out.scripts.items():
# deduplication of scripts when web_blocks methods are used in web pages
# see render_dynamic method web_page.py
if template not in frappe.flags.web_block_scripts:
for script in scripts:
html += f"<script data-web-template='{template}'>{script}</script>"
frappe.flags.web_block_scripts[template] = True

for template, styles in out.styles.items():
# deduplication of styles when web_blocks methods are used in web pages
# see render_dynamic method web_page.py
if template not in frappe.flags.web_block_styles:
for style in styles:
html += f"<style data-web-template='{template}'>{style}</style>"
frappe.flags.web_block_styles[template] = True

return html



+ 16
- 7
frappe/website/doctype/web_page/templates/web_page.html Zobrazit soubor

@@ -33,13 +33,18 @@
{% endblock %}

{% block style %}
<style>
{{ style or "" }}
</style>

{%- for style in page_builder_styles -%}
{%- if style -%}
<style>{{ style }}</style>
{%- endif -%}

{%- for web_template, styles in (page_builder_styles or {}).items() -%}
{%- if styles -%}
{%- for style in styles -%}
<style data-web-template="{{ web_template }}">{{ style }}</style>
{%- endfor -%}
{%- endif -%}
{%- endfor -%}

{% endblock %}

{% block script %}
@@ -47,7 +52,11 @@
<script>{{ script }}</script>
{%- endif -%}

{%- for script in page_builder_scripts -%}
<script>{{ script }}</script>
{%- for web_template, scripts in (page_builder_scripts or {}).items() -%}
{%- if scripts -%}
{%- for script in scripts -%}
<script data-web-template="{{ web_template }}">{{ script }}</script>
{%- endfor -%}
{%- endif -%}
{%- endfor -%}
{% endblock %}

+ 23
- 11
frappe/website/doctype/web_page/web_page.py Zobrazit soubor

@@ -79,15 +79,23 @@ class WebPage(WebsiteGenerator):

def render_dynamic(self, context):
# dynamic
is_jinja = context.dynamic_template or "<!-- jinja -->" in context.main_section
if is_jinja or ("{{" in context.main_section):
is_jinja = (
context.dynamic_template
or "<!-- jinja -->" in context.main_section
or ("{{" in context.main_section)
)
if is_jinja:
frappe.flags.web_block_scripts = {}
frappe.flags.web_block_styles = {}
try:
context["main_section"] = render_template(context.main_section, context)
if not "<!-- static -->" in context.main_section:
context["no_cache"] = 1
except TemplateSyntaxError:
if is_jinja:
raise
raise
finally:
frappe.flags.web_block_scripts = {}
frappe.flags.web_block_styles = {}

def set_breadcrumbs(self, context):
"""Build breadcrumbs template"""
@@ -193,9 +201,9 @@ def check_publish_status():
def get_web_blocks_html(blocks):
"""Converts a list of blocks into Raw HTML and extracts out their scripts for deduplication"""

out = frappe._dict(html="", scripts=[], styles=[])
extracted_scripts = []
extracted_styles = []
out = frappe._dict(html="", scripts={}, styles={})
extracted_scripts = {}
extracted_styles = {}
for block in blocks:
web_template = frappe.get_cached_doc("Web Template", block.web_template)
rendered_html = frappe.render_template(
@@ -209,11 +217,15 @@ def get_web_blocks_html(blocks):
html, scripts, styles = extract_script_and_style_tags(rendered_html)
out.html += html
if block.web_template not in extracted_scripts:
out.scripts += scripts
extracted_scripts.append(block.web_template)
extracted_scripts.setdefault(block.web_template, [])
extracted_scripts[block.web_template] += scripts

if block.web_template not in extracted_styles:
out.styles += styles
extracted_styles.append(block.web_template)
extracted_styles.setdefault(block.web_template, [])
extracted_styles[block.web_template] += styles

out.scripts = extracted_scripts
out.styles = extracted_styles

return out



+ 8
- 1
frappe/website/doctype/web_page_block/web_page_block.json Zobrazit soubor

@@ -9,6 +9,7 @@
"edit_values",
"web_template_values",
"css_class",
"section_id",
"column_break_5",
"add_container",
"add_top_padding",
@@ -103,11 +104,17 @@
"fieldname": "background_image",
"fieldtype": "Attach Image",
"label": "Background Image"
},
{
"description": "IDs must contain only alphanumeric characters, not contain spaces, and should be unique.",
"fieldname": "section_id",
"fieldtype": "Data",
"label": "Section ID"
}
],
"istable": 1,
"links": [],
"modified": "2022-03-21 14:23:32.665108",
"modified": "2022-06-21 20:00:17.025272",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Page Block",


+ 5
- 1
frappe/www/contact.html Zobrazit soubor

@@ -67,7 +67,11 @@
<i class='fa fa-phone'></i> <span itemprop="telephone">{{ phone }}</span><br>
{% endif %}
{% if email_id %}
<i class='fa fa-envelope'></i> <span itemprop="email">{{ email_id }}</span><br>
<i class='fa fa-envelope'></i>
<span itemprop="email">
<a href="mailto:{{ email_id }}">{{ email_id }}</a>
</span>
<br>
{% endif %}
{% if skype %}
<i class='fa fa-skype'></i> <span itemprop="email">{{ skype }}</span><br>


+ 1
- 1
pyproject.toml Zobrazit soubor

@@ -14,7 +14,7 @@ dependencies = [
"GitPython~=3.1.14",
"Jinja2~=3.1.2",
"Pillow~=9.1.1",
"PyJWT~=2.0.1",
"PyJWT~=2.4.0",
"PyMySQL~=1.0.2",
"PyPDF2~=2.1.0",
"PyPika~=0.48.9",


Načítá se…
Zrušit
Uložit