Merge pull request #19375 from barredterra/fix-note-2

This commit is contained in:
Suraj Shetty 2023-05-17 13:14:55 +05:30 committed by GitHub
commit 774aeb430a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 327 additions and 252 deletions

View file

@ -215,14 +215,13 @@ context("View", () => {
});
it("Route to Form", () => {
cy.call("frappe.tests.ui_test_helpers.create_note").then(() => {
cy.visit("/app/note/Routing Test");
cy.window()
.its("cur_frm")
.then((frm) => {
expect(frm.doc.title).to.equal("Routing Test");
});
});
const test_user = cy.config("testUser");
cy.visit(`/app/user/${test_user}`);
cy.window()
.its("cur_frm")
.then((frm) => {
expect(frm.doc.name).to.equal(test_user);
});
});
it("Route to Settings Workspace", () => {

View file

@ -6,7 +6,7 @@ context("Web Form", () => {
.window()
.its("frappe")
.then((frappe) => {
return frappe.xcall("frappe.tests.ui_test_helpers.clear_notes");
return frappe.xcall("frappe.tests.ui_test_helpers.prepare_webform_test");
});
});
@ -99,7 +99,7 @@ context("Web Form", () => {
cy.visit("/note");
cy.url().should("include", "/note/list");
cy.get(".web-list-table thead th").contains("Name");
cy.get(".web-list-table thead th").contains("Sr.");
cy.get(".web-list-table thead th").contains("Title");
cy.visit("/app/web-form/note");
@ -133,13 +133,17 @@ context("Web Form", () => {
cy.visit("/note");
cy.url().should("include", "/note/list");
cy.get(".web-list-table thead th").contains("Sr.");
cy.get(".web-list-table thead th").contains("Title");
cy.get(".web-list-table thead th").contains("Public");
cy.get(".web-list-table thead th").contains("Content");
});
it("Breadcrumbs", () => {
cy.visit("/note/Note 1");
cy.visit("/note");
cy.url().should("include", "/note/list");
cy.get(".web-list-table tbody tr:last").click();
cy.get(".breadcrumb-container .breadcrumb .breadcrumb-item:first a")
.should("contain.text", "Note")
.click();
@ -154,7 +158,9 @@ context("Web Form", () => {
cy.get(".form-tabs .nav-item .nav-link").contains("Customization").click();
cy.save();
cy.visit("/note/Note 1");
cy.visit("/note");
cy.url().should("include", "/note/list");
cy.get(".web-list-table tbody tr:last").click();
cy.get(".breadcrumb-container .breadcrumb .breadcrumb-item:first a").should(
"contain.text",
"Notes"
@ -167,7 +173,7 @@ context("Web Form", () => {
cy.url().should("include", "/note/list");
// Read Only Field
cy.get('.web-list-table tbody tr[id="Note 1"]').click();
cy.get(".web-list-table tbody tr:last").click();
cy.get('.frappe-control[data-fieldname="title"] .control-input').should(
"have.css",
"display",
@ -183,11 +189,12 @@ context("Web Form", () => {
cy.save();
cy.visit("/note/Note 1");
cy.url().should("include", "/note/Note%201");
cy.visit("/note");
cy.url().should("include", "/note/list");
cy.get(".web-list-table tbody tr:last").click();
cy.get(".web-form-actions a").contains("Edit Response").click();
cy.url().should("include", "/note/Note%201/edit");
cy.url().should("include", "/edit");
// Editable Field
cy.get_field("title").should("have.value", "Note 1");
@ -227,16 +234,14 @@ context("Web Form", () => {
cy.visit("/note");
cy.url().should("include", "/note/list");
cy.get('.web-list-table tbody tr[id="Note 1"] .list-col-checkbox input').click();
cy.get('.web-list-table tbody tr[id="Note 2"] .list-col-checkbox input').click();
cy.get(".web-list-table tbody tr:nth-child(1) .list-col-checkbox input").click();
cy.get(".web-list-table tbody tr:nth-child(2) .list-col-checkbox input").click();
cy.get(".web-list-actions button:visible").contains("Delete").click({ force: true });
cy.get(".web-list-actions button").contains("Delete").should("not.be.visible");
cy.visit("/note");
cy.get('.web-list-table tbody tr[id="Note 1"]').should("not.exist");
cy.get('.web-list-table tbody tr[id="Note 2"]').should("not.exist");
cy.get('.web-list-table tbody tr[id="Guest Note 1"]').should("exist");
cy.get(".web-list-table tbody tr:nth-child(1)").should("not.exist");
});
it("Navigate and Submit a WebForm", () => {

View file

@ -4,7 +4,8 @@
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from frappe.utils import random_string
TEST_DOCTYPE = "Assignment Test"
class TestAutoAssign(FrappeTestCase):
@ -12,12 +13,14 @@ class TestAutoAssign(FrappeTestCase):
def setUpClass(cls):
super().setUpClass()
frappe.db.delete("Assignment Rule")
create_test_doctype(TEST_DOCTYPE)
@classmethod
def tearDownClass(cls):
frappe.db.rollback()
def setUp(self):
frappe.set_user("Administrator")
make_test_records("User")
days = [
dict(day="Sunday"),
@ -33,45 +36,49 @@ class TestAutoAssign(FrappeTestCase):
clear_assignments()
def test_round_robin(self):
note = make_note(dict(public=1))
# check if auto assigned to first user
record = _make_test_record(public=1)
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=record.name, status="Open"),
"allocated_to",
),
"test@example.com",
)
note = make_note(dict(public=1))
# check if auto assigned to second user
record = _make_test_record(public=1)
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=record.name, status="Open"),
"allocated_to",
),
"test1@example.com",
)
clear_assignments()
note = make_note(dict(public=1))
# check if auto assigned to third user, even if
# previous assignments where closed
record = _make_test_record(public=1)
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=record.name, status="Open"),
"allocated_to",
),
"test2@example.com",
)
# check loop back to first user
note = make_note(dict(public=1))
record = _make_test_record(public=1)
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=record.name, status="Open"),
"allocated_to",
),
"test@example.com",
)
@ -81,29 +88,29 @@ class TestAutoAssign(FrappeTestCase):
self.assignment_rule.save()
for _ in range(30):
note = make_note(dict(public=1))
_make_test_record(public=1)
# check if each user has 10 assignments (?)
for user in ("test@example.com", "test1@example.com", "test2@example.com"):
self.assertEqual(
len(frappe.get_all("ToDo", dict(allocated_to=user, reference_type="Note"))), 10
len(frappe.get_all("ToDo", dict(allocated_to=user, reference_type=TEST_DOCTYPE))), 10
)
# clear 5 assignments for first user
# can't do a limit in "delete" since postgres does not support it
for d in frappe.get_all(
"ToDo", dict(reference_type="Note", allocated_to="test@example.com"), limit=5
"ToDo", dict(reference_type=TEST_DOCTYPE, allocated_to="test@example.com"), limit=5
):
frappe.db.delete("ToDo", {"name": d.name})
# add 5 more assignments
for i in range(5):
make_note(dict(public=1))
_make_test_record(public=1)
# check if each user still has 10 assignments
for user in ("test@example.com", "test1@example.com", "test2@example.com"):
self.assertEqual(
len(frappe.get_all("ToDo", dict(allocated_to=user, reference_type="Note"))), 10
len(frappe.get_all("ToDo", dict(allocated_to=user, reference_type=TEST_DOCTYPE))), 10
)
def test_based_on_field(self):
@ -111,45 +118,36 @@ class TestAutoAssign(FrappeTestCase):
self.assignment_rule.field = "owner"
self.assignment_rule.save()
frappe.set_user("test1@example.com")
note = make_note(dict(public=1))
# check if auto assigned to doc owner, test1@example.com
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "owner"
),
"test1@example.com",
)
frappe.set_user("test2@example.com")
note = make_note(dict(public=1))
# check if auto assigned to doc owner, test2@example.com
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "owner"
),
"test2@example.com",
)
frappe.set_user("Administrator")
for test_user in ("test1@example.com", "test2@example.com"):
frappe.set_user(test_user)
note = _make_test_record(public=1)
# check if auto assigned to doc owner, test1@example.com
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"), "owner"
),
test_user,
)
def test_assign_condition(self):
# check condition
note = make_note(dict(public=0))
note = _make_test_record(public=0)
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"),
"allocated_to",
),
None,
)
def test_clear_assignment(self):
note = make_note(dict(public=1))
note = _make_test_record(public=1)
# check if auto assigned to first user
todo = frappe.get_list(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), limit=1
"ToDo", dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"), limit=1
)[0]
todo = frappe.get_doc("ToDo", todo["name"])
@ -165,11 +163,11 @@ class TestAutoAssign(FrappeTestCase):
self.assertEqual(todo.status, "Cancelled")
def test_close_assignment(self):
note = make_note(dict(public=1, content="valid"))
note = _make_test_record(public=1, content="valid")
# check if auto assigned
todo = frappe.get_list(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), limit=1
"ToDo", dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"), limit=1
)[0]
todo = frappe.get_doc("ToDo", todo["name"])
@ -186,12 +184,14 @@ class TestAutoAssign(FrappeTestCase):
self.assertEqual(todo.allocated_to, "test@example.com")
def check_multiple_rules(self):
note = make_note(dict(public=1, notify_on_login=1))
note = _make_test_record(public=1, notify_on_login=1)
# check if auto assigned to test3 (2nd rule is applied, as it has higher priority)
self.assertEqual(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"),
"allocated_to",
),
"test@example.com",
)
@ -206,21 +206,25 @@ class TestAutoAssign(FrappeTestCase):
get_assignment_rule([days_1, days_2], ["public == 1", "public == 1"])
frappe.flags.assignment_day = "Monday"
note = make_note(dict(public=1))
note = _make_test_record(public=1)
self.assertIn(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"),
"allocated_to",
),
["test@example.com", "test1@example.com", "test2@example.com"],
)
frappe.flags.assignment_day = "Friday"
note = make_note(dict(public=1))
note = _make_test_record(public=1)
self.assertIn(
frappe.db.get_value(
"ToDo", dict(reference_type="Note", reference_name=note.name, status="Open"), "allocated_to"
"ToDo",
dict(reference_type=TEST_DOCTYPE, reference_name=note.name, status="Open"),
"allocated_to",
),
["test3@example.com"],
)
@ -228,17 +232,11 @@ class TestAutoAssign(FrappeTestCase):
def test_assignment_rule_condition(self):
frappe.db.delete("Assignment Rule")
# Add expiry_date custom field
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
df = dict(fieldname="expiry_date", label="Expiry Date", fieldtype="Date")
create_custom_field("Note", df)
assignment_rule = frappe.get_doc(
dict(
name="Assignment with Due Date",
doctype="Assignment Rule",
document_type="Note",
document_type=TEST_DOCTYPE,
assign_condition="public == 0",
due_date_based_on="expiry_date",
assignment_days=self.days,
@ -249,11 +247,11 @@ class TestAutoAssign(FrappeTestCase):
).insert()
expiry_date = frappe.utils.add_days(frappe.utils.nowdate(), 2)
note1 = make_note({"expiry_date": expiry_date})
note2 = make_note({"expiry_date": expiry_date})
note1 = _make_test_record(expiry_date=expiry_date)
note2 = _make_test_record(expiry_date=expiry_date)
note1_todo = frappe.get_all(
"ToDo", filters=dict(reference_type="Note", reference_name=note1.name, status="Open")
"ToDo", filters=dict(reference_type=TEST_DOCTYPE, reference_name=note1.name, status="Open")
)[0]
note1_todo_doc = frappe.get_doc("ToDo", note1_todo.name)
@ -268,7 +266,7 @@ class TestAutoAssign(FrappeTestCase):
# saving one note's expiry should not update other note todo's due date
note2_todo = frappe.get_all(
"ToDo",
filters=dict(reference_type="Note", reference_name=note2.name, status="Open"),
filters=dict(reference_type=TEST_DOCTYPE, reference_name=note2.name, status="Open"),
fields=["name", "date"],
)[0]
self.assertNotEqual(frappe.utils.get_date_str(note2_todo.date), note1.expiry_date)
@ -278,21 +276,21 @@ class TestAutoAssign(FrappeTestCase):
def clear_assignments():
frappe.db.delete("ToDo", {"reference_type": "Note"})
frappe.db.delete("ToDo", {"reference_type": TEST_DOCTYPE})
def get_assignment_rule(days, assign=None):
frappe.delete_doc_if_exists("Assignment Rule", "For Note 1")
frappe.delete_doc_if_exists("Assignment Rule", f"For {TEST_DOCTYPE} 1")
if not assign:
assign = ["public == 1", "notify_on_login == 1"]
assignment_rule = frappe.get_doc(
dict(
name="For Note 1",
name=f"For {TEST_DOCTYPE} 1",
doctype="Assignment Rule",
priority=0,
document_type="Note",
document_type=TEST_DOCTYPE,
assign_condition=assign[0],
unassign_condition="public == 0 or notify_on_login == 1",
close_condition='"Closed" in content',
@ -306,15 +304,15 @@ def get_assignment_rule(days, assign=None):
)
).insert()
frappe.delete_doc_if_exists("Assignment Rule", "For Note 2")
frappe.delete_doc_if_exists("Assignment Rule", f"For {TEST_DOCTYPE} 2")
# 2nd rule
frappe.get_doc(
dict(
name="For Note 2",
name=f"For {TEST_DOCTYPE} 2",
doctype="Assignment Rule",
priority=1,
document_type="Note",
document_type=TEST_DOCTYPE,
assign_condition=assign[1],
unassign_condition="notify_on_login == 0",
rule="Round Robin",
@ -326,12 +324,60 @@ def get_assignment_rule(days, assign=None):
return assignment_rule
def make_note(values=None):
note = frappe.get_doc(dict(doctype="Note", title=random_string(10), content=random_string(20)))
def _make_test_record(**kwargs):
doc = frappe.new_doc(TEST_DOCTYPE)
if values:
note.update(values)
if kwargs:
doc.update(kwargs)
note.insert()
return doc.insert()
return note
def create_test_doctype(doctype: str):
"""Create custom doctype."""
frappe.db.delete("DocType", doctype)
frappe.get_doc(
{
"doctype": "DocType",
"name": doctype,
"module": "Custom",
"custom": 1,
"fields": [
{
"fieldname": "expiry_date",
"label": "Expiry Date",
"fieldtype": "Date",
},
{
"fieldname": "notify_on_login",
"label": "Notify on Login",
"fieldtype": "Check",
},
{
"fieldname": "public",
"label": "Public",
"fieldtype": "Check",
},
{
"fieldname": "content",
"label": "Content",
"fieldtype": "Text",
},
],
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"share": 1,
"write": 1,
},
],
}
).insert()

View file

@ -1,41 +1,41 @@
frappe.ui.form.on("Note", {
refresh: function (frm) {
if (frm.doc.__islocal) {
frm.events.set_editable(frm, true);
} else {
if (!frm.doc.content) {
frm.doc.content = "<span></span>";
}
// toggle edit
frm.add_custom_button("Edit", function () {
frm.events.set_editable(frm, !frm.is_note_editable);
});
frm.events.set_editable(frm, false);
if (!frm.is_new()) {
frm.is_note_editable = false;
frm.events.set_editable(frm);
}
},
set_editable: function (frm, editable) {
// hide all fields other than content
// no permission
if (editable && !frm.perm[0].write) return;
set_editable: function (frm) {
if (frm.has_perm("write")) {
const read_label = __("Read mode");
const edit_label = __("Edit mode");
frm.remove_custom_button(frm.is_note_editable ? edit_label : read_label);
frm.add_custom_button(frm.is_note_editable ? read_label : edit_label, function () {
frm.is_note_editable = !frm.is_note_editable;
frm.events.set_editable(frm);
});
}
// toggle "read_only" for content and "hidden" of all other fields
// content read_only
frm.set_df_property("content", "read_only", editable ? 0 : 1);
frm.set_df_property("content", "read_only", frm.is_note_editable ? 0 : 1);
// hide all other fields
$.each(frm.fields_dict, function (fieldname) {
if (fieldname !== "content") {
frm.set_df_property(fieldname, "hidden", editable ? 0 : 1);
for (const field of frm.meta.fields) {
if (field.fieldname !== "content") {
frm.set_df_property(
field.fieldname,
"hidden",
frm.is_note_editable && !field.hidden && frm.get_perm(field.permlevel, "write")
? 0
: 1
);
}
});
}
// no label, description for content either
frm.get_field("content").toggle_label(editable);
frm.get_field("content").toggle_description(editable);
// set flag for toggle
frm.is_note_editable = editable;
frm.get_field("content").toggle_label(frm.is_note_editable);
frm.get_field("content").toggle_description(frm.is_note_editable);
},
});

View file

@ -1,6 +1,6 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "hash",
"creation": "2013-05-24 13:41:00",
"doctype": "DocType",
"document_type": "Document",
@ -19,11 +19,8 @@
{
"fieldname": "title",
"fieldtype": "Data",
"in_global_search": 1,
"in_list_view": 1,
"label": "Title",
"no_copy": 1,
"print_hide": 1,
"reqd": 1
},
{
@ -32,6 +29,7 @@
"fieldname": "public",
"fieldtype": "Check",
"label": "Public",
"permlevel": 1,
"print_hide": 1
},
{
@ -40,7 +38,8 @@
"depends_on": "public",
"fieldname": "notify_on_login",
"fieldtype": "Check",
"label": "Notify users with a popup when they log in"
"label": "Notify users with a popup when they log in",
"permlevel": 1
},
{
"bold": 1,
@ -49,13 +48,15 @@
"description": "If enabled, users will be notified every time they login. If not enabled, users will only be notified once.",
"fieldname": "notify_on_every_login",
"fieldtype": "Check",
"label": "Notify Users On Every Login"
"label": "Notify Users On Every Login",
"permlevel": 1
},
{
"depends_on": "eval:doc.notify_on_login && doc.public",
"fieldname": "expire_notification_on",
"fieldtype": "Date",
"label": "Expire Notification On",
"permlevel": 1,
"search_index": 1
},
{
@ -68,39 +69,80 @@
},
{
"collapsible": 1,
"depends_on": "notify_on_login",
"fieldname": "seen_by_section",
"fieldtype": "Section Break",
"label": "Seen By"
"label": "Seen By",
"permlevel": 1
},
{
"fieldname": "seen_by",
"fieldtype": "Table",
"label": "Seen By Table",
"options": "Note Seen By"
"options": "Note Seen By",
"permlevel": 1
}
],
"icon": "fa fa-file-text",
"idx": 1,
"links": [],
"modified": "2021-09-18 10:57:51.352643",
"modified": "2023-04-24 16:07:03.281184",
"modified_by": "Administrator",
"module": "Desk",
"name": "Note",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"permlevel": 1,
"read": 1,
"role": "System Manager",
"write": 1
},
{
"permlevel": 2,
"read": 1,
"role": "System Manager",
"write": 1
},
{
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All"
},
{
"create": 1,
"delete": 1,
"email": 1,
"if_owner": 1,
"role": "All",
"share": 1,
"write": 1
},
{
"permlevel": 1,
"read": 1,
"role": "All"
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "ASC",
"states": [],
"title_field": "title",
"track_changes": 1
}

View file

@ -1,53 +1,39 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
import re
import frappe
from frappe.model.document import Document
NAME_PATTERN = re.compile("[%'\"#*?`]")
class Note(Document):
def autoname(self):
# replace forbidden characters
self.name = NAME_PATTERN.sub("", self.title.strip())
def validate(self):
if self.notify_on_login and not self.expire_notification_on:
# expire this notification in a week (default)
self.expire_notification_on = frappe.utils.add_days(self.creation, 7)
if not self.content:
self.content = "<span></span>"
def before_print(self, settings=None):
self.print_heading = self.name
self.sub_heading = ""
def mark_seen_by(self, user: str) -> None:
if user in [d.user for d in self.seen_by]:
return
self.append("seen_by", {"user": user})
@frappe.whitelist()
def mark_as_seen(note):
note = frappe.get_doc("Note", note)
if frappe.session.user not in [d.user for d in note.seen_by]:
note.append("seen_by", {"user": frappe.session.user})
note.save(ignore_version=True, ignore_permissions=True)
def mark_as_seen(note: str):
note: Note = frappe.get_doc("Note", note)
note.mark_seen_by(frappe.session.user)
note.save(ignore_permissions=True, ignore_version=True)
def get_permission_query_conditions(user):
if not user:
user = frappe.session.user
if user == "Administrator":
return ""
return f"""(`tabNote`.public=1 or `tabNote`.owner={frappe.db.escape(user)})"""
def has_permission(doc, ptype, user):
if doc.public == 1 or user == "Administrator":
return True
if user == doc.owner:
return True
return False
return f"(`tabNote`.owner = {frappe.db.escape(user)} or `tabNote`.public = 1)"

View file

@ -1,8 +1,6 @@
frappe.listview_settings["Note"] = {
onload: function (me) {
me.page.set_title(__("Notes"));
},
add_fields: ["title", "public"],
hide_name_column: true,
add_fields: ["public"],
get_indicator: function (doc) {
if (doc.public) {
return [__("Public"), "green", "public,=,Yes"];

View file

@ -13,12 +13,13 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "User",
"options": "User"
"options": "User",
"permlevel": 2
}
],
"istable": 1,
"links": [],
"modified": "2022-08-03 12:20:51.030908",
"modified": "2023-04-24 16:14:53.684098",
"modified_by": "Administrator",
"module": "Desk",
"name": "Note Seen By",

View file

@ -114,7 +114,6 @@ has_permission = {
"Event": "frappe.desk.doctype.event.event.has_permission",
"ToDo": "frappe.desk.doctype.todo.todo.has_permission",
"User": "frappe.core.doctype.user.user.has_permission",
"Note": "frappe.desk.doctype.note.note.has_permission",
"Dashboard Chart": "frappe.desk.doctype.dashboard_chart.dashboard_chart.has_permission",
"Number Card": "frappe.desk.doctype.number_card.number_card.has_permission",
"Kanban Board": "frappe.desk.doctype.kanban_board.kanban_board.has_permission",

View file

@ -2,13 +2,22 @@
# License: MIT. See LICENSE
import frappe
import frappe.desk.form.assign_to
from frappe.automation.doctype.assignment_rule.test_assignment_rule import make_note
from frappe.automation.doctype.assignment_rule.test_assignment_rule import (
TEST_DOCTYPE,
_make_test_record,
create_test_doctype,
)
from frappe.desk.form.load import get_assignments
from frappe.desk.listview import get_group_by_count
from frappe.tests.utils import FrappeTestCase
class TestAssign(FrappeTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
create_test_doctype(TEST_DOCTYPE)
def test_assign(self):
todo = frappe.get_doc({"doctype": "ToDo", "description": "test"}).insert()
if not frappe.db.exists("User", "test@example.com"):
@ -18,7 +27,7 @@ class TestAssign(FrappeTestCase):
self.assertTrue("test@example.com" in [d.owner for d in added])
removed = frappe.desk.form.assign_to.remove(todo.doctype, todo.name, "test@example.com")
frappe.desk.form.assign_to.remove(todo.doctype, todo.name, "test@example.com")
# assignment is cleared
assignments = frappe.desk.form.assign_to.get(dict(doctype=todo.doctype, name=todo.name))
@ -47,25 +56,27 @@ class TestAssign(FrappeTestCase):
}
).insert()
note = make_note()
note = _make_test_record()
assign(note, "test_assign1@example.com")
note = make_note(dict(public=1))
note = _make_test_record(public=1)
assign(note, "test_assign2@example.com")
note = make_note(dict(public=1))
note = _make_test_record(public=1)
assign(note, "test_assign2@example.com")
note = make_note()
note = _make_test_record()
assign(note, "test_assign2@example.com")
data = {d.name: d.count for d in get_group_by_count("Note", "[]", "assigned_to")}
data = {d.name: d.count for d in get_group_by_count(TEST_DOCTYPE, "[]", "assigned_to")}
self.assertTrue("test_assign1@example.com" in data)
self.assertEqual(data["test_assign1@example.com"], 1)
self.assertEqual(data["test_assign2@example.com"], 3)
data = {d.name: d.count for d in get_group_by_count("Note", '[{"public": 1}]', "assigned_to")}
data = {
d.name: d.count for d in get_group_by_count(TEST_DOCTYPE, '[{"public": 1}]', "assigned_to")
}
self.assertFalse("test_assign1@example.com" in data)
self.assertEqual(data["test_assign2@example.com"], 2)

View file

@ -237,8 +237,8 @@ class TestClient(FrappeTestCase):
docs = insert_many(doc_list)
self.assertEqual(len(docs), 7)
self.assertEqual(docs[3], "not-a-random-title")
self.assertEqual(docs[6], "another-note-title")
self.assertEqual(frappe.db.get_value("Note", docs[3], "title"), "not-a-random-title")
self.assertEqual(frappe.db.get_value("Note", docs[6], "title"), "another-note-title")
self.assertIn(note1.name, docs)
# cleanup

View file

@ -8,6 +8,7 @@ import requests
import frappe
from frappe.core.doctype.user.user import generate_keys
from frappe.frappeclient import FrappeClient, FrappeException
from frappe.model import default_fields
from frappe.tests.utils import FrappeTestCase
from frappe.utils.data import get_url
@ -17,33 +18,33 @@ class TestFrappeClient(FrappeTestCase):
def test_insert_many(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
frappe.db.delete("Note", {"title": ("in", ("Sing", "a", "song", "of", "sixpence"))})
frappe.db.commit()
server.insert_many(
[
{"doctype": "Note", "public": True, "title": "Sing"},
{"doctype": "Note", "public": True, "title": "a"},
{"doctype": "Note", "public": True, "title": "song"},
{"doctype": "Note", "public": True, "title": "of"},
{"doctype": "Note", "public": True, "title": "sixpence"},
{"doctype": "Note", "title": "Sing"},
{"doctype": "Note", "title": "a"},
{"doctype": "Note", "title": "song"},
{"doctype": "Note", "title": "of"},
{"doctype": "Note", "title": "sixpence"},
]
)
records = server.get_list("Note", fields=["title"])
records = [r.get("title") for r in records]
self.assertTrue(frappe.db.get_value("Note", {"title": "Sing"}))
self.assertTrue(frappe.db.get_value("Note", {"title": "a"}))
self.assertTrue(frappe.db.get_value("Note", {"title": "song"}))
self.assertTrue(frappe.db.get_value("Note", {"title": "of"}))
self.assertTrue(frappe.db.get_value("Note", {"title": "sixpence"}))
self.assertIn("Sing", records)
self.assertIn("a", records)
self.assertIn("song", records)
self.assertIn("of", records)
self.assertIn("sixpence", records)
def test_create_doc(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
frappe.db.delete("Note", {"title": "test_create"})
frappe.db.commit()
response = server.insert({"doctype": "Note", "title": "test_create"})
server.insert({"doctype": "Note", "public": True, "title": "test_create"})
for field in default_fields:
self.assertIn(field, response)
self.assertTrue(frappe.db.get_value("Note", {"title": "test_create"}))
self.assertEqual(response.get("doctype"), "Note")
self.assertEqual(response.get("title"), "test_create")
def test_list_docs(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
@ -52,37 +53,41 @@ class TestFrappeClient(FrappeTestCase):
self.assertTrue(len(doc_list))
def test_get_doc(self):
USER = "Administrator"
TITLE = "get_this"
DOCTYPE = "Note"
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
frappe.db.delete("Note", {"title": "get_this"})
frappe.db.commit()
server.insert_many(
[
{"doctype": "Note", "public": True, "title": "get_this"},
]
)
doc = server.get_doc("Note", "get_this")
self.assertTrue(doc)
NAME = server.insert({"doctype": DOCTYPE, "title": TITLE}).get("name")
doc = server.get_doc(DOCTYPE, NAME)
def test_get_value(self):
for field in default_fields:
self.assertIn(field, doc)
self.assertEqual(doc.get("doctype"), DOCTYPE)
self.assertEqual(doc.get("name"), NAME)
self.assertEqual(doc.get("title"), TITLE)
self.assertEqual(doc.get("owner"), USER)
def test_get_value_by_filters(self):
CONTENT = "test get value"
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
frappe.db.delete("Note", {"title": "get_value"})
frappe.db.commit()
server.insert({"doctype": "Note", "title": "get_value", "content": CONTENT}).get("name")
test_content = "test get value"
server.insert_many(
[
{"doctype": "Note", "public": True, "title": "get_value", "content": test_content},
]
)
self.assertEqual(
server.get_value("Note", "content", {"title": "get_value"}).get("content"), test_content
server.get_value("Note", "content", {"title": "get_value"}).get("content"), CONTENT
)
name = server.get_value("Note", "name", {"title": "get_value"}).get("name")
# test by name
self.assertEqual(server.get_value("Note", "content", name).get("content"), test_content)
def test_get_value_by_name(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
CONTENT = "test get value"
NAME = server.insert({"doctype": "Note", "title": "get_value", "content": CONTENT}).get("name")
self.assertEqual(server.get_value("Note", "content", NAME).get("content"), CONTENT)
def test_get_value_with_malicious_query(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
server.insert({"doctype": "Note", "title": "get_value"})
self.assertRaises(
FrappeException,
@ -106,15 +111,13 @@ class TestFrappeClient(FrappeTestCase):
def test_update_doc(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
frappe.db.delete("Note", {"title": ("in", ("Sing", "sing"))})
frappe.db.commit()
resp = server.insert({"doctype": "Note", "title": "Sing"})
doc = server.get_doc("Note", resp.get("name"))
server.insert({"doctype": "Note", "public": True, "title": "Sing"})
doc = server.get_doc("Note", "Sing")
changed_title = "sing"
doc["title"] = changed_title
CONTENT = "<h1>Hello, World!</h1>"
doc["content"] = CONTENT
doc = server.update(doc)
self.assertTrue(doc["title"] == changed_title)
self.assertTrue(doc["content"] == CONTENT)
def test_update_child_doc(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
@ -160,17 +163,9 @@ class TestFrappeClient(FrappeTestCase):
def test_delete_doc(self):
server = FrappeClient(get_url(), "Administrator", self.PASSWORD, verify=False)
frappe.db.delete("Note", {"title": "delete"})
frappe.db.commit()
server.insert_many(
[
{"doctype": "Note", "public": True, "title": "delete"},
]
)
server.delete("Note", "delete")
self.assertFalse(frappe.db.get_value("Note", {"title": "delete"}))
NAME_TO_DELETE = server.insert({"doctype": "Note", "title": "Sing"}).get("name")
server.delete("Note", NAME_TO_DELETE)
self.assertFalse(frappe.db.get_value("Note", NAME_TO_DELETE))
def test_auth_via_api_key_secret(self):
# generate API key and API secret for administrator

View file

@ -31,16 +31,13 @@ class TestNaming(FrappeTestCase):
if Bottle-1 exists
Bottle -> Bottle-2
"""
TITLE = "Bottle"
DOCTYPE = "Note"
note = frappe.new_doc("Note")
note.title = "Test"
note.insert()
note = frappe.get_doc({"doctype": DOCTYPE, "title": TITLE}).insert()
title2 = append_number_if_name_exists("Note", "Test")
self.assertEqual(title2, "Test-1")
title2 = append_number_if_name_exists("Note", "Test", "title", "_")
self.assertEqual(title2, "Test_1")
self.assertEqual(append_number_if_name_exists(DOCTYPE, note.name), f"{note.name}-1")
self.assertEqual(append_number_if_name_exists(DOCTYPE, TITLE, "title", "_"), f"{TITLE}_1")
def test_field_autoname_name_sync(self):
@ -276,8 +273,8 @@ class TestNaming(FrappeTestCase):
# set by passing set_name as ToDo
self.assertRaises(frappe.NameError, make_invalid_todo)
# set new name - Note
note = frappe.get_doc({"doctype": "Note", "title": "Note"})
# name (via title field) cannot be the same as the doctype
note = frappe.get_doc({"doctype": "Currency", "currency_name": "Currency"})
self.assertRaises(frappe.NameError, note.insert)
# case 2: set name with "New ---"

View file

@ -77,10 +77,12 @@ def create_todo_records():
@whitelist_for_tests
def clear_notes():
def prepare_webform_test():
for note in frappe.get_all("Note", pluck="name"):
frappe.delete_doc("Note", note, force=True)
frappe.delete_doc_if_exists("Web Form", "note")
@whitelist_for_tests
def create_communication_record():
@ -536,12 +538,6 @@ def setup_default_view(view, force_reroute=None):
).insert()
@whitelist_for_tests
def create_note():
if not frappe.db.exists("Note", "Routing Test"):
frappe.get_doc({"doctype": "Note", "title": "Routing Test"}).insert()
@whitelist_for_tests
def create_kanban():
if not frappe.db.exists("Custom Field", "Note-kanban"):