Merge branch 'develop' into disable_change_log

This commit is contained in:
Himanshu 2022-05-09 16:44:30 +01:00 committed by GitHub
commit d7b42e34fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 738 additions and 681 deletions

View file

@ -59,7 +59,7 @@ context('Data Control', () => {
//Checking for the error message
cy.get('.modal-title').should('have.text', 'Message');
cy.get('.msgprint').should('have.text', '@@### is not a valid Name');
cy.get('.modal').type('{esc}');
cy.hide_dialog();
cy.get_field('name1', 'Data').clear({force: true});
cy.fill_field('name1', 'Komal{}/!', 'Data');
@ -67,10 +67,10 @@ context('Data Control', () => {
cy.findByRole('button', {name: 'Save'}).click();
cy.get('.modal-title').should('have.text', 'Message');
cy.get('.msgprint').should('have.text', 'Komal{}/! is not a valid Name');
cy.hide_dialog();
});
it('Verifying data control by inputting different patterns for "Email" field', () => {
cy.get('.modal-actions > .btn-modal-close').trigger("click");
cy.get_field('name1', 'Data').clear({force: true});
cy.fill_field('name1', 'Komal', 'Data');
cy.get_field('email', 'Data').clear({force: true});
@ -79,17 +79,17 @@ context('Data Control', () => {
cy.findByRole('button', {name: 'Save'}).click();
cy.get('.modal-title').should('have.text', 'Message');
cy.get('.msgprint').should('have.text', 'komal is not a valid Email Address');
cy.get('.modal-actions > .btn-modal-close').trigger("click");
cy.hide_dialog();
cy.get_field('email', 'Data').clear({force: true});
cy.fill_field('email', 'komal@test', 'Data');
cy.get('.frappe-control[data-fieldname="email"]').should('have.class', 'has-error');
cy.findByRole('button', {name: 'Save'}).click();
cy.get('.modal-title').should('have.text', 'Message');
cy.get('.msgprint').should('have.text', 'komal@test is not a valid Email Address');
cy.hide_dialog();
});
it('Verifying data control by inputting different patterns for "Phone" field', () => {
cy.get('.modal-actions > .btn-modal-close').trigger("click");
cy.get_field('email', 'Data').clear({force: true});
cy.fill_field('email', 'komal@test.com', 'Data');
cy.get_field('phone', 'Data').clear({force: true});
@ -98,7 +98,7 @@ context('Data Control', () => {
cy.findByRole('button', {name: 'Save'}).click({force: true});
cy.get('.modal-title').should('have.text', 'Message');
cy.get('.msgprint').should('have.text', 'komal is not a valid Phone Number');
cy.get('.modal-actions > .btn-modal-close').trigger("click");
cy.hide_dialog();
});
it('Inputting correct data and saving the doc', () => {
@ -124,6 +124,6 @@ context('Data Control', () => {
cy.get('.actions-btn-group > .btn').contains('Actions').click();
cy.get('.actions-btn-group > .dropdown-menu [data-label="Delete"]').click();
cy.click_modal_primary_button('Yes');
cy.get('.btn-modal-close').click();
cy.hide_dialog();
});
});

View file

@ -1,7 +1,7 @@
context('Form Tour', () => {
context.skip('Form Tour', () => {
before(() => {
cy.login();
cy.visit('/app/form-tour');
cy.visit('/app');
return cy.window().its('frappe').then(frappe => {
return frappe.call("frappe.tests.ui_test_helpers.create_form_tour");
});

View file

@ -435,7 +435,7 @@ def msgprint(
if as_table and type(msg) in (list, tuple):
out.as_table = 1
if as_list and type(msg) in (list, tuple) and len(msg) > 1:
if as_list and type(msg) in (list, tuple):
out.as_list = 1
if flags.print_messages and out.message:

View file

@ -11,7 +11,6 @@
"language",
"column_break_3",
"time_zone",
"is_first_startup",
"enable_onboarding",
"setup_complete",
"date_and_number_format",
@ -104,14 +103,6 @@
"read_only": 1,
"reqd": 1
},
{
"default": "0",
"fieldname": "is_first_startup",
"fieldtype": "Check",
"hidden": 1,
"label": "Is First Startup",
"read_only": 1
},
{
"default": "0",
"fieldname": "setup_complete",
@ -509,7 +500,7 @@
"icon": "fa fa-cog",
"issingle": 1,
"links": [],
"modified": "2022-04-28 14:31:50.330954",
"modified": "2022-05-09 18:53:35.218721",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",

View file

@ -1019,21 +1019,17 @@ class Database(object):
return self.get_value(dt, dn, ignore=True, cache=cache)
def count(self, dt, filters=None, debug=False, cache=False):
def count(self, dt, filters=None, debug=False, cache=False, distinct: bool = True):
"""Returns `COUNT(*)` for given DocType and filters."""
if cache and not filters:
cache_count = frappe.cache().get_value("doctype:count:{}".format(dt))
if cache_count is not None:
return cache_count
query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"))
if filters:
count = self.sql(query, debug=debug)[0][0]
return count
else:
count = self.sql(query, debug=debug)[0][0]
if cache:
frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400)
return count
query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"), distinct=distinct)
count = query.run(debug=debug)[0][0]
if not filters and cache:
frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400)
return count
@staticmethod
def format_date(date):

View file

@ -4,10 +4,10 @@ from typing import Any, Dict, List, Tuple, Union
import frappe
from frappe import _
from frappe.query_builder import Criterion, Field, Order
from frappe.query_builder import Criterion, Field, Order, Table
def like(key: str, value: str) -> frappe.qb:
def like(key: Field, value: str) -> frappe.qb:
"""Wrapper method for `LIKE`
Args:
@ -17,10 +17,10 @@ def like(key: str, value: str) -> frappe.qb:
Returns:
frappe.qb: `frappe.qb object with `LIKE`
"""
return Field(key).like(value)
return key.like(value)
def func_in(key: str, value: Union[List, Tuple]) -> frappe.qb:
def func_in(key: Field, value: Union[List, Tuple]) -> frappe.qb:
"""Wrapper method for `IN`
Args:
@ -30,10 +30,10 @@ def func_in(key: str, value: Union[List, Tuple]) -> frappe.qb:
Returns:
frappe.qb: `frappe.qb object with `IN`
"""
return Field(key).isin(value)
return key.isin(value)
def not_like(key: str, value: str) -> frappe.qb:
def not_like(key: Field, value: str) -> frappe.qb:
"""Wrapper method for `NOT LIKE`
Args:
@ -43,10 +43,10 @@ def not_like(key: str, value: str) -> frappe.qb:
Returns:
frappe.qb: `frappe.qb object with `NOT LIKE`
"""
return Field(key).not_like(value)
return key.not_like(value)
def func_not_in(key: str, value: Union[List, Tuple]):
def func_not_in(key: Field, value: Union[List, Tuple]):
"""Wrapper method for `NOT IN`
Args:
@ -56,10 +56,10 @@ def func_not_in(key: str, value: Union[List, Tuple]):
Returns:
frappe.qb: `frappe.qb object with `NOT IN`
"""
return Field(key).notin(value)
return key.notin(value)
def func_regex(key: str, value: str) -> frappe.qb:
def func_regex(key: Field, value: str) -> frappe.qb:
"""Wrapper method for `REGEX`
Args:
@ -69,10 +69,10 @@ def func_regex(key: str, value: str) -> frappe.qb:
Returns:
frappe.qb: `frappe.qb object with `REGEX`
"""
return Field(key).regex(value)
return key.regex(value)
def func_between(key: str, value: Union[List, Tuple]) -> frappe.qb:
def func_between(key: Field, value: Union[List, Tuple]) -> frappe.qb:
"""Wrapper method for `BETWEEN`
Args:
@ -82,7 +82,7 @@ def func_between(key: str, value: Union[List, Tuple]) -> frappe.qb:
Returns:
frappe.qb: `frappe.qb object with `BETWEEN`
"""
return Field(key)[slice(*value)]
return key[slice(*value)]
def make_function(key: Any, value: Union[int, str]):
@ -139,7 +139,9 @@ OPERATOR_MAP = {
class Query:
def get_condition(self, table: str, **kwargs) -> frappe.qb:
tables: dict = {}
def get_condition(self, table: Union[str, Table], **kwargs) -> frappe.qb:
"""Get initial table object
Args:
@ -148,11 +150,20 @@ class Query:
Returns:
frappe.qb: DocType with initial condition
"""
table_object = self.get_table(table)
if kwargs.get("update"):
return frappe.qb.update(table)
return frappe.qb.update(table_object)
if kwargs.get("into"):
return frappe.qb.into(table)
return frappe.qb.from_(table)
return frappe.qb.into(table_object)
return frappe.qb.from_(table_object)
def get_table(self, table_name: Union[str, Table]) -> Table:
if isinstance(table_name, Table):
return table_name
table_name = table_name.strip('"').strip("'")
if table_name not in self.tables:
self.tables[table_name] = frappe.qb.DocType(table_name)
return self.tables[table_name]
def criterion_query(self, table: str, criterion: Criterion, **kwargs) -> frappe.qb:
"""Generate filters from Criterion objects
@ -217,8 +228,13 @@ class Query:
conditions = conditions.where(_operator(Field(filters[0]), filters[2]))
break
else:
_operator = OPERATOR_MAP[f[1]]
conditions = conditions.where(_operator(Field(f[0]), f[2]))
_operator = OPERATOR_MAP[f[-2]]
if len(f) == 4:
table_object = self.get_table(f[0])
_field = table_object[f[1]]
else:
_field = Field(f[0])
conditions = conditions.where(_operator(_field, f[-1]))
return self.add_conditions(conditions, **kwargs)
@ -249,7 +265,7 @@ class Query:
if isinstance(value, (list, tuple)):
if isinstance(value[1], (list, tuple)) or value[0] in list(OPERATOR_MAP.keys())[-4:]:
_operator = OPERATOR_MAP[value[0]]
conditions = conditions.where(_operator(key, value[1]))
conditions = conditions.where(_operator(Field(key), value[1]))
else:
_operator = OPERATOR_MAP[value[0]]
conditions = conditions.where(_operator(Field(key), value[1]))
@ -293,10 +309,19 @@ class Query:
self,
table: str,
fields: Union[List, Tuple],
filters: Union[Dict[str, Union[str, int]], str, int] = None,
filters: Union[Dict[str, Union[str, int]], str, int, List[Union[List, str, int]]] = None,
**kwargs,
):
# Clean up state before each query
self.tables = {}
criterion = self.build_conditions(table, filters, **kwargs)
if len(self.tables) > 1:
primary_table = self.tables[table]
del self.tables[table]
for table_object in self.tables.values():
criterion = criterion.left_join(table_object).on(table_object.parent == primary_table.name)
if isinstance(fields, (list, tuple)):
query = criterion.select(*kwargs.get("field_objects", fields))

View file

@ -269,7 +269,6 @@ def add_all_roles_to(name):
def disable_future_access():
frappe.db.set_default("desktop:home_page", "workspace")
frappe.db.set_value("System Settings", "System Settings", "setup_complete", 1)
frappe.db.set_value("System Settings", "System Settings", "is_first_startup", 1)
# Enable onboarding after install
frappe.db.set_value("System Settings", "System Settings", "enable_onboarding", 1)
@ -334,11 +333,6 @@ def load_user_details():
}
@frappe.whitelist()
def reset_is_first_startup():
frappe.db.set_value("System Settings", "System Settings", "is_first_startup", 0)
def prettify_args(args):
# remove attachments
for key, val in args.items():

View file

@ -48,15 +48,12 @@ def get_list():
@frappe.read_only()
def get_count():
args = get_form_params()
if is_virtual_doctype(args.doctype):
controller = get_controller(args.doctype)
data = controller(args.doctype).get_count(args)
else:
distinct = "distinct " if args.distinct == "true" else ""
args.fields = [f"count({distinct}`tab{args.doctype}`.name) as total_count"]
data = execute(**args)[0].get("total_count")
distinct = args["distinct"] == "true"
data = frappe.db.count(args["doctype"], args["filters"], distinct=distinct)
return data

View file

@ -189,6 +189,7 @@ frappe.patches.v14_0.save_ratings_in_fraction #23-12-2021
frappe.patches.v14_0.transform_todo_schema
frappe.patches.v14_0.remove_post_and_post_comment
frappe.patches.v14_0.reset_creation_datetime
frappe.patches.v14_0.remove_is_first_startup
[post_model_sync]
frappe.patches.v14_0.drop_data_import_legacy

View file

@ -0,0 +1,8 @@
import frappe
def execute():
singles = frappe.qb.Table("tabSingles")
frappe.qb.from_(singles).delete().where(
(singles.doctype == "System Settings") & (singles.field == "is_first_startup")
).run()

View file

@ -137,13 +137,13 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat
});
}
parse(value) {
if(value) {
return frappe.datetime.user_to_str(value);
if (value) {
return frappe.datetime.user_to_str(value, false, true);
}
}
format_for_input(value) {
if(value) {
return frappe.datetime.str_to_user(value);
if (value) {
return frappe.datetime.str_to_user(value, false, true);
}
return "";
}

View file

@ -45,8 +45,6 @@ frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.Co
}
format_for_input(value) {
if (!value) return "";
return frappe.datetime.str_to_user(value, false);
}
set_description() {

View file

@ -78,7 +78,7 @@ export default class ListSettings {
if (field_count < 4) {
field_count = 4;
} else if (field_count > 10) {
field_count = 4;
field_count = 10;
}
me.dialog.set_value("total_fields", field_count);

View file

@ -133,7 +133,7 @@ $.extend(frappe.datetime, {
return frappe.sys_defaults && frappe.sys_defaults.date_format || "yyyy-mm-dd";
},
str_to_user: function(val, only_time = false) {
str_to_user: function(val, only_time=false, only_date=false) {
if (!val) return "";
const user_date_fmt = frappe.datetime.get_user_date_fmt().toUpperCase();
const user_time_fmt = frappe.datetime.get_user_time_fmt();
@ -142,6 +142,9 @@ $.extend(frappe.datetime, {
if (only_time) {
let date_obj = moment(val, frappe.defaultTimeFormat);
return date_obj.format(user_format);
} else if (only_date) {
let date_obj = moment(val, frappe.defaultDateFormat);
return date_obj.format(user_date_fmt);
} else {
let date_obj = moment.tz(val, frappe.boot.time_zone.system);
if (typeof val !== "string" || val.indexOf(" ") === -1) {

View file

@ -26,8 +26,8 @@ frappe.ready(function() {
window.location.replace('/login?redirect-to=' + window.location.pathname);
}
});
login_required.set_message(__("You are not permitted to access this page."));
login_required.show();
login_required.set_message(__("You are not permitted to access this page without login."));
}
function show_grid() {

View file

@ -1,16 +0,0 @@
/*! Clusterize.js - v0.17.6 - 2017-03-05
* http://NeXTs.github.com/Clusterize.js/
* Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
;(function(q,n){"undefined"!=typeof module?module.exports=n():"function"==typeof define&&"object"==typeof define.amd?define(n):this[q]=n()})("Clusterize",function(){function q(b,a,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)}function n(b,a,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)}function r(b){return"[object Array]"===Object.prototype.toString.call(b)}function m(b,a){return window.getComputedStyle?window.getComputedStyle(a)[b]:
a.currentStyle[b]}var l=function(){for(var b=3,a=document.createElement("b"),c=a.all||[];a.innerHTML="\x3c!--[if gt IE "+ ++b+"]><i><![endif]--\x3e",c[0];);return 4<b?b:document.documentMode}(),x=navigator.platform.toLowerCase().indexOf("mac")+1,p=function(b){if(!(this instanceof p))return new p(b);var a=this,c={rows_in_block:50,blocks_in_cluster:4,tag:null,show_no_data_row:!0,no_data_class:"clusterize-no-data",no_data_text:"No data",keep_parity:!0,callbacks:{}};a.options={};for(var d="rows_in_block blocks_in_cluster show_no_data_row no_data_class no_data_text keep_parity tag callbacks".split(" "),
f=0,h;h=d[f];f++)a.options[h]="undefined"!=typeof b[h]&&null!=b[h]?b[h]:c[h];c=["scroll","content"];for(f=0;d=c[f];f++)if(a[d+"_elem"]=b[d+"Id"]?document.getElementById(b[d+"Id"]):b[d+"Elem"],!a[d+"_elem"])throw Error("Error! Could not find "+d+" element");a.content_elem.hasAttribute("tabindex")||a.content_elem.setAttribute("tabindex",0);var e=r(b.rows)?b.rows:a.fetchMarkup(),g={};b=a.scroll_elem.scrollTop;a.insertToDOM(e,g);a.scroll_elem.scrollTop=b;var k=!1,m=0,l=!1,t=function(){x&&(l||(a.content_elem.style.pointerEvents=
"none"),l=!0,clearTimeout(m),m=setTimeout(function(){a.content_elem.style.pointerEvents="auto";l=!1},50));k!=(k=a.getClusterNum())&&a.insertToDOM(e,g);a.options.callbacks.scrollingProgress&&a.options.callbacks.scrollingProgress(a.getScrollProgress())},u=0,v=function(){clearTimeout(u);u=setTimeout(a.refresh,100)};q("scroll",a.scroll_elem,t);q("resize",window,v);a.destroy=function(b){n("scroll",a.scroll_elem,t);n("resize",window,v);a.html((b?a.generateEmptyRow():e).join(""))};a.refresh=function(b){(a.getRowsHeight(e)||
b)&&a.update(e)};a.update=function(b){e=r(b)?b:[];b=a.scroll_elem.scrollTop;e.length*a.options.item_height<b&&(k=a.scroll_elem.scrollTop=0);a.insertToDOM(e,g);a.scroll_elem.scrollTop=b};a.clear=function(){a.update([])};a.getRowsAmount=function(){return e.length};a.getScrollProgress=function(){return this.options.scroll_top/(e.length*this.options.item_height)*100||0};var w=function(b,c){var d=r(c)?c:[];d.length&&(e="append"==b?e.concat(d):d.concat(e),a.insertToDOM(e,g))};a.append=function(a){w("append",
a)};a.prepend=function(a){w("prepend",a)}};p.prototype={constructor:p,fetchMarkup:function(){for(var b=[],a=this.getChildNodes(this.content_elem);a.length;)b.push(a.shift().outerHTML);return b},exploreEnvironment:function(b,a){var c=this.options;c.content_tag=this.content_elem.tagName.toLowerCase();b.length&&(l&&9>=l&&!c.tag&&(c.tag=b[0].match(/<([^>\s/]*)/)[1].toLowerCase()),1>=this.content_elem.children.length&&(a.data=this.html(b[0]+b[0]+b[0])),c.tag||(c.tag=this.content_elem.children[0].tagName.toLowerCase()),
this.getRowsHeight(b))},getRowsHeight:function(b){var a=this.options,c=a.item_height;a.cluster_height=0;if(b.length){b=this.content_elem.children;var d=b[Math.floor(b.length/2)];a.item_height=d.offsetHeight;"tr"==a.tag&&"collapse"!=m("borderCollapse",this.content_elem)&&(a.item_height+=parseInt(m("borderSpacing",this.content_elem),10)||0);"tr"!=a.tag&&(b=parseInt(m("marginTop",d),10)||0,d=parseInt(m("marginBottom",d),10)||0,a.item_height+=Math.max(b,d));a.block_height=a.item_height*a.rows_in_block;
a.rows_in_cluster=a.blocks_in_cluster*a.rows_in_block;a.cluster_height=a.blocks_in_cluster*a.block_height;return c!=a.item_height}},getClusterNum:function(){this.options.scroll_top=this.scroll_elem.scrollTop;return Math.floor(this.options.scroll_top/(this.options.cluster_height-this.options.block_height))||0},generateEmptyRow:function(){var b=this.options;if(!b.tag||!b.show_no_data_row)return[];var a=document.createElement(b.tag),c=document.createTextNode(b.no_data_text),d;a.className=b.no_data_class;
"tr"==b.tag&&(d=document.createElement("td"),d.colSpan=100,d.appendChild(c));a.appendChild(d||c);return[a.outerHTML]},generate:function(b,a){var c=this.options,d=b.length;if(d<c.rows_in_block)return{top_offset:0,bottom_offset:0,rows_above:0,rows:d?b:this.generateEmptyRow()};var f=Math.max((c.rows_in_cluster-c.rows_in_block)*a,0),h=f+c.rows_in_cluster,e=Math.max(f*c.item_height,0),c=Math.max((d-h)*c.item_height,0),d=[],g=f;for(1>e&&g++;f<h;f++)b[f]&&d.push(b[f]);return{top_offset:e,bottom_offset:c,
rows_above:g,rows:d}},renderExtraTag:function(b,a){var c=document.createElement(this.options.tag);c.className=["clusterize-extra-row","clusterize-"+b].join(" ");a&&(c.style.height=a+"px");return c.outerHTML},insertToDOM:function(b,a){this.options.cluster_height||this.exploreEnvironment(b,a);var c=this.generate(b,this.getClusterNum()),d=c.rows.join(""),f=this.checkChanges("data",d,a),h=this.checkChanges("top",c.top_offset,a),e=this.checkChanges("bottom",c.bottom_offset,a),g=this.options.callbacks,
k=[];f||h?(c.top_offset&&(this.options.keep_parity&&k.push(this.renderExtraTag("keep-parity")),k.push(this.renderExtraTag("top-space",c.top_offset))),k.push(d),c.bottom_offset&&k.push(this.renderExtraTag("bottom-space",c.bottom_offset)),g.clusterWillChange&&g.clusterWillChange(),this.html(k.join("")),"ol"==this.options.content_tag&&this.content_elem.setAttribute("start",c.rows_above),g.clusterChanged&&g.clusterChanged()):e&&(this.content_elem.lastChild.style.height=c.bottom_offset+"px")},html:function(b){var a=
this.content_elem;if(l&&9>=l&&"tr"==this.options.tag){var c=document.createElement("div");for(c.innerHTML="<table><tbody>"+b+"</tbody></table>";b=a.lastChild;)a.removeChild(b);for(c=this.getChildNodes(c.firstChild.firstChild);c.length;)a.appendChild(c.shift())}else a.innerHTML=b},getChildNodes:function(b){b=b.children;for(var a=[],c=0,d=b.length;c<d;c++)a.push(b[c]);return a},checkChanges:function(b,a,c){var d=a!=c[b];c[b]=a;return d}};return p});

View file

@ -1,4 +1,3 @@
import "./lib/clusterize.min.js";
import "./frappe/views/reports/report_factory.js";
import "./frappe/views/reports/report_view.js";
import "./frappe/views/reports/query_report.js";

View file

@ -187,9 +187,6 @@ def get():
bootinfo["disable_async"] = frappe.conf.disable_async
bootinfo["setup_complete"] = cint(frappe.db.get_single_value("System Settings", "setup_complete"))
bootinfo["is_first_startup"] = cint(
frappe.db.get_single_value("System Settings", "is_first_startup")
)
bootinfo["desk_theme"] = frappe.db.get_value("User", frappe.session.user, "desk_theme") or "Light"

View file

@ -3,12 +3,12 @@
<div class="form-group">
<label class="form-label sr-only" for="signup_fullname">{{ _("Full Name") }}</label>
<input type="text" id="signup_fullname" class="form-control" placeholder="{{ _('Jane Doe') }}"
required autofocus>
required autofocus autocomplete="name">
</div>
<div class="form-group">
<label class="form-label sr-only" for="signup_email">{{ _("Email") }}</label>
<input type="email" id="signup_email" class="form-control"
placeholder="{{ _('jane@example.com') }}" required>
placeholder="{{ _('jane@example.com') }}" required autocomplete="username">
</div>
</div>
<div class="page-card-actions">

View file

@ -482,6 +482,33 @@ class TestDB(unittest.TestCase):
frappe.db.delete("ToDo", {"description": test_body})
def test_count(self):
frappe.db.delete("Note")
frappe.get_doc(doctype="Note", title="note1", content="something").insert()
frappe.get_doc(doctype="Note", title="note2", content="someting else").insert()
# Count with no filtes
self.assertEquals((frappe.db.count("Note")), 2)
# simple filters
self.assertEquals((frappe.db.count("Note", ["title", "=", "note1"])), 1)
frappe.get_doc(doctype="Note", title="note3", content="something other").insert()
# List of list filters with tables
self.assertEquals(
(
frappe.db.count(
"Note",
[["Note", "title", "like", "note%"], ["Note", "content", "like", "some%"]],
)
),
3,
)
frappe.db.rollback()
@run_only_if(db_type_is.MARIADB)
class TestDDLCommandsMaria(unittest.TestCase):

View file

@ -0,0 +1,20 @@
import unittest
import frappe
from frappe.tests.test_query_builder import db_type_is, run_only_if
@run_only_if(db_type_is.MARIADB)
class TestQuery(unittest.TestCase):
def test_multiple_tables_in_filters(self):
self.assertEqual(
frappe.db.query.get_sql(
"DocType",
["*"],
[
["BOM Update Log", "name", "like", "f%"],
["DocType", "parent", "=", "something"],
],
).get_sql(),
"SELECT * FROM `tabDocType` LEFT JOIN `tabBOM Update Log` ON `tabBOM Update Log`.`parent`=`tabDocType`.`name` WHERE `tabBOM Update Log`.`name` LIKE 'f%' AND `tabDocType`.`parent`='something'",
)

View file

@ -1,10 +1,27 @@
import unittest
import frappe
from frappe.utils import set_request
from frappe.website.serve import get_response
from frappe.www.list import get_list_context
class TestWebsite(unittest.TestCase):
class TestWebform(unittest.TestCase):
def test_webform_publish_functionality(self):
edit_profile = frappe.get_doc("Web Form", "edit-profile")
# publish webform
edit_profile.published = True
edit_profile.save()
set_request(method="GET", path="update-profile")
response = get_response()
self.assertEqual(response.status_code, 200)
# un-publish webform
edit_profile.published = False
edit_profile.save()
response = get_response()
self.assertEqual(response.status_code, 404)
def test_get_context_hook_of_webform(self):
create_custom_doctype()
create_webform()

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ from frappe.website.page_renderers.document_page import DocumentPage
class WebFormPage(DocumentPage):
def can_render(self):
webform_name = frappe.db.exists("Web Form", {"route": self.path}, cache=True)
webform_name = frappe.db.exists("Web Form", {"route": self.path, "published": 1}, cache=True)
if webform_name:
self.doctype = "Web Form"
self.docname = webform_name

View file

@ -7,7 +7,7 @@
<div class="email-field">
<input type="text" id="login_email" class="form-control"
placeholder="{% if login_name_placeholder %}{{ login_name_placeholder }}{% else %}{{ _('jane@example.com') }}{% endif %}"
required autofocus>
required autofocus autocomplete="username">
<svg class="field-icon email-icon" width="20" height="20" viewBox="0 0 20 20" fill="none"
xmlns="http://www.w3.org/2000/svg">
@ -152,7 +152,7 @@
<div class="page-card-body">
<div class="email-field">
<input type="email" id="forgot_email" class="form-control"
placeholder="{{ _('Email Address') }}" required autofocus>
placeholder="{{ _('Email Address') }}" required autofocus autocomplete="username">
<svg class="field-icon email-icon" width="20" height="20" viewBox="0 0 20 20" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path

View file

@ -12,16 +12,16 @@
<form id="reset-password">
<div class="form-group">
<input id="old_password" type="password"
class="form-control mb-4" placeholder="{{ _('Old Password') }}">
class="form-control mb-4" placeholder="{{ _('Old Password') }}" autocomplete="current-password">
</div>
<div class="form-group">
<input id="new_password" type="password"
class="form-control mb-4" placeholder="{{ _('New Password') }}">
class="form-control mb-4" placeholder="{{ _('New Password') }}" autocomplete="new-password">
<span class="password-strength-indicator indicator"></span>
</div>
<div class="form-group">
<input id="confirm_password" type="password"
class="form-control" placeholder="{{ _('Confirm Password') }}">
class="form-control" placeholder="{{ _('Confirm Password') }}" autocomplete="new-password">
<p class="password-mismatch-message text-muted small hidden mt-2"></p>
</div>