fix(routing): removed /space from routingversion-14
@@ -2,7 +2,7 @@ context('API Resources', () => { | |||||
before(() => { | before(() => { | ||||
cy.visit('/login'); | cy.visit('/login'); | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
it('Creates two Comments', () => { | it('Creates two Comments', () => { | ||||
@@ -2,7 +2,7 @@ context('Awesome Bar', () => { | |||||
before(() => { | before(() => { | ||||
cy.visit('/login'); | cy.visit('/login'); | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
beforeEach(() => { | beforeEach(() => { | ||||
@@ -1,7 +1,7 @@ | |||||
context('Control Barcode', () => { | context('Control Barcode', () => { | ||||
beforeEach(() => { | beforeEach(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
function get_dialog_with_barcode() { | function get_dialog_with_barcode() { | ||||
@@ -1,7 +1,7 @@ | |||||
context('Control Duration', () => { | context('Control Duration', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
function get_dialog_with_duration(hide_days = 0, hide_seconds = 0) { | function get_dialog_with_duration(hide_days = 0, hide_seconds = 0) { | ||||
@@ -1,11 +1,11 @@ | |||||
context('Control Link', () => { | context('Control Link', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
beforeEach(() => { | beforeEach(() => { | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
cy.create_records({ | cy.create_records({ | ||||
doctype: 'ToDo', | doctype: 'ToDo', | ||||
description: 'this is a test todo for link' | description: 'this is a test todo for link' | ||||
@@ -1,7 +1,7 @@ | |||||
context('Control Rating', () => { | context('Control Rating', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
function get_dialog_with_rating() { | function get_dialog_with_rating() { | ||||
@@ -4,7 +4,7 @@ const doctype_name = datetime_doctype.name; | |||||
context('Control Date, Time and DateTime', () => { | context('Control Date, Time and DateTime', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
return cy.insert_doc('DocType', datetime_doctype, true); | return cy.insert_doc('DocType', datetime_doctype, true); | ||||
}); | }); | ||||
@@ -1,7 +1,7 @@ | |||||
context('Depends On', () => { | context('Depends On', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
return cy.window().its('frappe').then(frappe => { | return cy.window().its('frappe').then(frappe => { | ||||
return frappe.call('frappe.tests.ui_test_helpers.create_doctype', { | return frappe.call('frappe.tests.ui_test_helpers.create_doctype', { | ||||
name: 'Test Depends On', | name: 'Test Depends On', | ||||
@@ -1,7 +1,7 @@ | |||||
context('FileUploader', () => { | context('FileUploader', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
function open_upload_dialog() { | function open_upload_dialog() { | ||||
@@ -1,7 +1,7 @@ | |||||
context('Form', () => { | context('Form', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
return cy.window().its('frappe').then(frappe => { | return cy.window().its('frappe').then(frappe => { | ||||
return frappe.call("frappe.tests.ui_test_helpers.create_contact_records"); | return frappe.call("frappe.tests.ui_test_helpers.create_contact_records"); | ||||
}); | }); | ||||
@@ -1,11 +1,11 @@ | |||||
context('Grid Pagination', () => { | context('Grid Pagination', () => { | ||||
beforeEach(() => { | beforeEach(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
return cy.window().its('frappe').then(frappe => { | return cy.window().its('frappe').then(frappe => { | ||||
return frappe.call("frappe.tests.ui_test_helpers.create_contact_phone_nos_records"); | return frappe.call("frappe.tests.ui_test_helpers.create_contact_phone_nos_records"); | ||||
}); | }); | ||||
@@ -1,7 +1,7 @@ | |||||
context('List View', () => { | context('List View', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
return cy.window().its('frappe').then(frappe => { | return cy.window().its('frappe').then(frappe => { | ||||
return frappe.xcall("frappe.tests.ui_test_helpers.setup_workflow"); | return frappe.xcall("frappe.tests.ui_test_helpers.setup_workflow"); | ||||
}); | }); | ||||
@@ -1,7 +1,7 @@ | |||||
context('List View Settings', () => { | context('List View Settings', () => { | ||||
beforeEach(() => { | beforeEach(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
it('Default settings', () => { | it('Default settings', () => { | ||||
cy.visit('/app/List/DocType/List'); | cy.visit('/app/List/DocType/List'); | ||||
@@ -35,7 +35,7 @@ context('Login', () => { | |||||
cy.get('#login_password').type(Cypress.config('adminPassword')); | cy.get('#login_password').type(Cypress.config('adminPassword')); | ||||
cy.get('.btn-login:visible').click(); | cy.get('.btn-login:visible').click(); | ||||
cy.location('pathname').should('eq', '/app/space/Home'); | |||||
cy.location('pathname').should('eq', '/app/home'); | |||||
cy.window().its('frappe.session.user').should('eq', 'Administrator'); | cy.window().its('frappe.session.user').should('eq', 'Administrator'); | ||||
}); | }); | ||||
@@ -1,7 +1,7 @@ | |||||
context('Query Report', () => { | context('Query Report', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
}); | }); | ||||
it('add custom column in report', () => { | it('add custom column in report', () => { | ||||
@@ -4,7 +4,7 @@ context('Recorder', () => { | |||||
}); | }); | ||||
it('Navigate to Recorder', () => { | it('Navigate to Recorder', () => { | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
cy.awesomebar('recorder'); | cy.awesomebar('recorder'); | ||||
cy.get('h1').should('contain', 'Recorder'); | cy.get('h1').should('contain', 'Recorder'); | ||||
cy.location('pathname').should('eq', '#recorder'); | cy.location('pathname').should('eq', '#recorder'); | ||||
@@ -4,7 +4,7 @@ context('Relative Timeframe', () => { | |||||
}); | }); | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
cy.window().its('frappe').then(frappe => { | cy.window().its('frappe').then(frappe => { | ||||
frappe.call("frappe.tests.ui_test_helpers.create_todo_records"); | frappe.call("frappe.tests.ui_test_helpers.create_todo_records"); | ||||
}); | }); | ||||
@@ -4,7 +4,7 @@ const doctype_name = custom_submittable_doctype.name; | |||||
context('Report View', () => { | context('Report View', () => { | ||||
before(() => { | before(() => { | ||||
cy.login(); | cy.login(); | ||||
cy.visit('/app/space/Website'); | |||||
cy.visit('/app/website'); | |||||
cy.insert_doc('DocType', custom_submittable_doctype, true); | cy.insert_doc('DocType', custom_submittable_doctype, true); | ||||
cy.clear_cache(); | cy.clear_cache(); | ||||
cy.insert_doc(doctype_name, { | cy.insert_doc(doctype_name, { | ||||
@@ -109,7 +109,7 @@ def load_conf_settings(bootinfo): | |||||
def load_desktop_data(bootinfo): | def load_desktop_data(bootinfo): | ||||
from frappe.desk.desktop import get_desk_sidebar_items | from frappe.desk.desktop import get_desk_sidebar_items | ||||
bootinfo.allowed_workspaces = get_desk_sidebar_items(flatten=True, cache=False) | |||||
bootinfo.allowed_workspaces = get_desk_sidebar_items() | |||||
bootinfo.module_page_map = get_controller("Workspace").get_module_page_map() | bootinfo.module_page_map = get_controller("Workspace").get_module_page_map() | ||||
bootinfo.dashboards = frappe.get_all("Dashboard") | bootinfo.dashboards = frappe.get_all("Dashboard") | ||||
@@ -250,13 +250,12 @@ def add_home_page(bootinfo, docs): | |||||
try: | try: | ||||
page = frappe.desk.desk_page.get(home_page) | page = frappe.desk.desk_page.get(home_page) | ||||
docs.append(page) | |||||
bootinfo['home_page'] = page.name | |||||
except (frappe.DoesNotExistError, frappe.PermissionError): | except (frappe.DoesNotExistError, frappe.PermissionError): | ||||
if frappe.message_log: | if frappe.message_log: | ||||
frappe.message_log.pop() | frappe.message_log.pop() | ||||
page = frappe.desk.desk_page.get('space') | |||||
bootinfo['home_page'] = page.name | |||||
docs.append(page) | |||||
bootinfo['home_page'] = 'Workspaces' | |||||
def add_timezone_info(bootinfo): | def add_timezone_info(bootinfo): | ||||
system = bootinfo.sysdefaults.get("time_zone") | system = bootinfo.sysdefaults.get("time_zone") | ||||
@@ -26,6 +26,7 @@ from frappe.database.schema import validate_column_name, validate_column_length | |||||
from frappe.model.docfield import supports_translation | from frappe.model.docfield import supports_translation | ||||
from frappe.modules.import_file import get_file_path | from frappe.modules.import_file import get_file_path | ||||
from frappe.model.meta import Meta | from frappe.model.meta import Meta | ||||
from frappe.desk.utils import validate_route_conflict | |||||
class InvalidFieldNameError(frappe.ValidationError): pass | class InvalidFieldNameError(frappe.ValidationError): pass | ||||
class UniqueFieldnameError(frappe.ValidationError): pass | class UniqueFieldnameError(frappe.ValidationError): pass | ||||
@@ -648,6 +649,8 @@ class DocType(Document): | |||||
if not re.match("^(?![\W])[^\d_\s][\w ]+$", name, **flags): | if not re.match("^(?![\W])[^\d_\s][\w ]+$", name, **flags): | ||||
frappe.throw(_("DocType's name should start with a letter and it can only consist of letters, numbers, spaces and underscores"), frappe.NameError) | frappe.throw(_("DocType's name should start with a letter and it can only consist of letters, numbers, spaces and underscores"), frappe.NameError) | ||||
validate_route_conflict(self.doctype, self.name) | |||||
def validate_links_table_fieldnames(meta): | def validate_links_table_fieldnames(meta): | ||||
"""Validate fieldnames in Links table""" | """Validate fieldnames in Links table""" | ||||
if frappe.flags.in_patch: return | if frappe.flags.in_patch: return | ||||
@@ -1,7 +1,7 @@ | |||||
import frappe | import frappe | ||||
from frappe.desk.utils import get_doctype_route | |||||
from frappe.desk.utils import slug | |||||
def execute(): | def execute(): | ||||
for doctype in frappe.get_all('DocType', ['name', 'route'], dict(istable=0)): | for doctype in frappe.get_all('DocType', ['name', 'route'], dict(istable=0)): | ||||
if not doctype.route: | if not doctype.route: | ||||
frappe.db.set_value('DocType', doctype.name, 'route', get_doctype_route(doctype.name), update_modified = False) | |||||
frappe.db.set_value('DocType', doctype.name, 'route', slug(doctype.name), update_modified = False) |
@@ -9,6 +9,7 @@ from frappe.build import html_to_js_template | |||||
from frappe.model.utils import render_include | from frappe.model.utils import render_include | ||||
from frappe import conf, _, safe_decode | from frappe import conf, _, safe_decode | ||||
from frappe.desk.form.meta import get_code_files_via_hooks, get_js | from frappe.desk.form.meta import get_code_files_via_hooks, get_js | ||||
from frappe.desk.utils import validate_route_conflict | |||||
from frappe.core.doctype.custom_role.custom_role import get_custom_allowed_roles | from frappe.core.doctype.custom_role.custom_role import get_custom_allowed_roles | ||||
from six import text_type | from six import text_type | ||||
@@ -33,10 +34,7 @@ class Page(Document): | |||||
self.name += '-' + str(cnt) | self.name += '-' + str(cnt) | ||||
def validate(self): | def validate(self): | ||||
if frappe.db.get_value('DocType', self.name): | |||||
frappe.throw( | |||||
_("{} is the name of a DocType. DocType names cannot be the same as a Page name, please choose another name.").format(self.page_name) | |||||
) | |||||
validate_route_conflict(self.doctype, self.name) | |||||
if self.is_new() and not getattr(conf,'developer_mode', 0): | if self.is_new() and not getattr(conf,'developer_mode', 0): | ||||
frappe.throw(_("Not in Developer Mode")) | frappe.throw(_("Not in Developer Mode")) | ||||
@@ -0,0 +1,5 @@ | |||||
import frappe | |||||
def execute(): | |||||
for name in ('desktop', 'space'): | |||||
frappe.delete_doc('Page', name) |
@@ -8,4 +8,6 @@ import unittest | |||||
test_records = frappe.get_test_records('Page') | test_records = frappe.get_test_records('Page') | ||||
class TestPage(unittest.TestCase): | class TestPage(unittest.TestCase): | ||||
pass | |||||
def test_naming(self): | |||||
self.assertRaises(frappe.NameError, frappe.get_doc(dict(doctype='Page', page_name='DocType', module='Core')).insert) | |||||
self.assertRaises(frappe.NameError, frappe.get_doc(dict(doctype='Page', page_name='Settings', module='Core')).insert) |
@@ -81,6 +81,7 @@ class TestServerScript(unittest.TestCase): | |||||
def tearDownClass(cls): | def tearDownClass(cls): | ||||
frappe.db.commit() | frappe.db.commit() | ||||
frappe.db.sql('truncate `tabServer Script`') | frappe.db.sql('truncate `tabServer Script`') | ||||
frappe.cache().delete_value('server_script_map') | |||||
def setUp(self): | def setUp(self): | ||||
frappe.cache().delete_value('server_script_map') | frappe.cache().delete_value('server_script_map') | ||||
@@ -1,3 +0,0 @@ | |||||
frappe.pages['desktop'].on_page_load = function() { | |||||
frappe.utils.set_title(__("Home")); | |||||
}; |
@@ -1,24 +0,0 @@ | |||||
{ | |||||
"content": null, | |||||
"creation": "2019-01-29 13:11:48.872579", | |||||
"docstatus": 0, | |||||
"doctype": "Page", | |||||
"icon": "icon-th", | |||||
"idx": 0, | |||||
"modified": "2019-01-29 13:11:48.872579", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "desktop", | |||||
"owner": "Administrator", | |||||
"page_name": "desktop", | |||||
"roles": [ | |||||
{ | |||||
"role": "All" | |||||
} | |||||
], | |||||
"script": null, | |||||
"standard": "Yes", | |||||
"style": null, | |||||
"system_page": 0, | |||||
"title": "Desktop" | |||||
} |
@@ -1,12 +0,0 @@ | |||||
frappe.pages['space'].on_page_load = function (wrapper) { | |||||
frappe.ui.make_app_page({ | |||||
parent: wrapper, | |||||
name: 'space', | |||||
title: __("Workspace"), | |||||
}); | |||||
frappe.workspace = new frappe.views.Workspace(wrapper); | |||||
$(wrapper).bind('show', function () { | |||||
frappe.workspace.show(); | |||||
}); | |||||
} |
@@ -1,23 +0,0 @@ | |||||
{ | |||||
"content": null, | |||||
"creation": "2020-02-27 15:07:57.124916", | |||||
"docstatus": 0, | |||||
"doctype": "Page", | |||||
"icon": "icon-th", | |||||
"idx": 0, | |||||
"modified": "2020-12-16 14:22:05.591912", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "space", | |||||
"owner": "Administrator", | |||||
"page_name": "space", | |||||
"roles": [ | |||||
{ | |||||
"role": "All" | |||||
} | |||||
], | |||||
"script": null, | |||||
"standard": "Yes", | |||||
"style": null, | |||||
"system_page": 0 | |||||
} |
@@ -7,9 +7,9 @@ from __future__ import unicode_literals | |||||
import frappe | import frappe | ||||
from frappe.model.document import Document | from frappe.model.document import Document | ||||
from frappe.desk.utils import get_doctype_route | |||||
from frappe.desk.utils import slug | |||||
class DocTypeLayout(Document): | class DocTypeLayout(Document): | ||||
def validate(self): | def validate(self): | ||||
if not self.route: | if not self.route: | ||||
self.route = get_doctype_route(self.name) | |||||
self.route = slug(self.name) |
@@ -361,57 +361,39 @@ def get_desktop_page(page): | |||||
} | } | ||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def get_desk_sidebar_items(flatten=False, cache=True): | |||||
"""Get list of sidebar items for desk | |||||
""" | |||||
pages = [] | |||||
_cache = frappe.cache() | |||||
if cache: | |||||
pages = _cache.get_value("desk_sidebar_items", user=frappe.session.user) | |||||
if not pages or not cache: | |||||
# don't get domain restricted pages | |||||
blocked_modules = frappe.get_doc('User', frappe.session.user).get_blocked_modules() | |||||
filters = { | |||||
'restrict_to_domain': ['in', frappe.get_active_domains()], | |||||
'extends_another_page': 0, | |||||
'for_user': '', | |||||
'module': ['not in', blocked_modules] | |||||
} | |||||
def get_desk_sidebar_items(): | |||||
"""Get list of sidebar items for desk""" | |||||
if not frappe.local.conf.developer_mode: | |||||
filters['developer_mode_only'] = '0' | |||||
# don't get domain restricted pages | |||||
blocked_modules = frappe.get_doc('User', frappe.session.user).get_blocked_modules() | |||||
# pages sorted based on pinned to top and then by name | |||||
order_by = "pin_to_top desc, pin_to_bottom asc, name asc" | |||||
all_pages = frappe.get_all("Workspace", fields=["name", "category", "icon", "module"], | |||||
filters=filters, order_by=order_by, ignore_permissions=True) | |||||
pages = [] | |||||
# Filter Page based on Permission | |||||
for page in all_pages: | |||||
try: | |||||
wspace = Workspace(page.get('name'), True) | |||||
if wspace.is_page_allowed(): | |||||
pages.append(page) | |||||
except frappe.PermissionError: | |||||
pass | |||||
_cache.set_value("desk_sidebar_items", pages, frappe.session.user) | |||||
filters = { | |||||
'restrict_to_domain': ['in', frappe.get_active_domains()], | |||||
'extends_another_page': 0, | |||||
'for_user': '', | |||||
'module': ['not in', blocked_modules] | |||||
} | |||||
if flatten: | |||||
return pages | |||||
if not frappe.local.conf.developer_mode: | |||||
filters['developer_mode_only'] = '0' | |||||
from collections import defaultdict | |||||
sidebar_items = defaultdict(list) | |||||
# pages sorted based on pinned to top and then by name | |||||
order_by = "pin_to_top desc, pin_to_bottom asc, name asc" | |||||
all_pages = frappe.get_all("Workspace", fields=["name", "category", "icon", "module"], | |||||
filters=filters, order_by=order_by, ignore_permissions=True) | |||||
pages = [] | |||||
# The order will be maintained while categorizing | |||||
for page in pages: | |||||
# Translate label | |||||
page['label'] = _(page.get('name')) | |||||
sidebar_items[page["category"]].append(page) | |||||
return sidebar_items | |||||
# Filter Page based on Permission | |||||
for page in all_pages: | |||||
try: | |||||
wspace = Workspace(page.get('name'), True) | |||||
if wspace.is_page_allowed(): | |||||
pages.append(page) | |||||
page['label'] = _(page.get('name')) | |||||
except frappe.PermissionError: | |||||
pass | |||||
return pages | |||||
def get_table_with_counts(): | def get_table_with_counts(): | ||||
counts = frappe.cache().get_value("information_schema:counts") | counts = frappe.cache().get_value("information_schema:counts") | ||||
@@ -8,6 +8,7 @@ from frappe import _, _dict | |||||
from frappe.utils.data import validate_json_string | from frappe.utils.data import validate_json_string | ||||
from frappe.modules.export_file import export_to_files | from frappe.modules.export_file import export_to_files | ||||
from frappe.model.document import Document | from frappe.model.document import Document | ||||
from frappe.desk.utils import validate_route_conflict | |||||
from json import loads, dumps | from json import loads, dumps | ||||
@@ -15,6 +16,7 @@ class Workspace(Document): | |||||
def validate(self): | def validate(self): | ||||
if (self.is_standard and not frappe.conf.developer_mode and not disable_saving_as_standard()): | if (self.is_standard and not frappe.conf.developer_mode and not disable_saving_as_standard()): | ||||
frappe.throw(_("You need to be in developer mode to edit this document")) | frappe.throw(_("You need to be in developer mode to edit this document")) | ||||
validate_route_conflict(self.doctype, self.name) | |||||
def on_update(self): | def on_update(self): | ||||
if disable_saving_as_standard(): | if disable_saving_as_standard(): | ||||
@@ -3,5 +3,17 @@ | |||||
import frappe | import frappe | ||||
def get_doctype_route(name): | |||||
def validate_route_conflict(doctype, name): | |||||
''' | |||||
Raises exception if name clashes with routes from other documents for /app routing | |||||
''' | |||||
all_names = [] | |||||
for _doctype in ['Page', 'Workspace', 'DocType']: | |||||
all_names.extend([slug(d) for d in frappe.get_all(_doctype, pluck='name') if (doctype != _doctype and d != name)]) | |||||
if slug(name) in all_names: | |||||
frappe.msgprint(frappe._('Name already taken, please set a new name')) | |||||
raise frappe.NameError | |||||
def slug(name): | |||||
return name.lower().replace(' ', '-') | return name.lower().replace(' ', '-') |
@@ -15,21 +15,7 @@ emails = ["test_subscriber1@example.com", "test_subscriber2@example.com", | |||||
class TestNewsletter(unittest.TestCase): | class TestNewsletter(unittest.TestCase): | ||||
def setUp(self): | def setUp(self): | ||||
frappe.set_user("Administrator") | |||||
frappe.db.sql('delete from `tabEmail Group Member`') | |||||
group_exist=frappe.db.exists("Email Group", "_Test Email Group") | |||||
if len(group_exist) == 0: | |||||
frappe.get_doc({ | |||||
"doctype": "Email Group", | |||||
"title": "_Test Email Group" | |||||
}).insert() | |||||
for email in emails: | |||||
frappe.get_doc({ | |||||
"doctype": "Email Group Member", | |||||
"email": email, | |||||
"email_group": "_Test Email Group" | |||||
}).insert() | |||||
self.make_email_group() | |||||
def test_send(self): | def test_send(self): | ||||
name = self.send_newsletter() | name = self.send_newsletter() | ||||
@@ -46,8 +32,9 @@ class TestNewsletter(unittest.TestCase): | |||||
from frappe.email.queue import flush | from frappe.email.queue import flush | ||||
flush(from_test=True) | flush(from_test=True) | ||||
to_unsubscribe = unquote(frappe.local.flags.signed_query_string.split("email=")[1].split("&")[0]) | to_unsubscribe = unquote(frappe.local.flags.signed_query_string.split("email=")[1].split("&")[0]) | ||||
group = frappe.get_all("Newsletter Email Group", filters={"parent" : name}, fields=["email_group"]) | |||||
confirmed_unsubscribe(to_unsubscribe, group[0].email_group) | |||||
email_group = frappe.db.get_value('Newsletter Email Group', dict(parent=name), 'email_group') | |||||
confirmed_unsubscribe(to_unsubscribe, email_group) | |||||
name = self.send_newsletter() | name = self.send_newsletter() | ||||
@@ -58,6 +45,36 @@ class TestNewsletter(unittest.TestCase): | |||||
if email != to_unsubscribe: | if email != to_unsubscribe: | ||||
self.assertTrue(email in recipients) | self.assertTrue(email in recipients) | ||||
frappe.db.set_value('Email Group Member', dict(email=to_unsubscribe), 'unsubscribed', 0) | |||||
def test_portal(self): | |||||
self.send_newsletter(1) | |||||
frappe.set_user("test1@example.com") | |||||
from frappe.email.doctype.newsletter.newsletter import get_newsletter_list | |||||
newsletters = get_newsletter_list("Newsletter", None, None, 0) | |||||
self.assertEqual(len(newsletters), 1) | |||||
frappe.set_user("Administrator") | |||||
def test_newsletter_context(self): | |||||
context = frappe._dict() | |||||
newsletter_name = self.send_newsletter(1) | |||||
frappe.set_user("test2@example.com") | |||||
doc = frappe.get_doc("Newsletter", newsletter_name) | |||||
doc.get_context(context) | |||||
self.assertEqual(context.no_cache, 1) | |||||
self.assertTrue("attachments" not in list(context)) | |||||
frappe.set_user("Administrator") | |||||
def test_schedule_send(self): | |||||
self.send_newsletter(schedule_send=add_days(getdate(), -1)) | |||||
email_queue_list = [frappe.get_doc('Email Queue', e.name) for e in frappe.get_all("Email Queue")] | |||||
self.assertEqual(len(email_queue_list), 4) | |||||
recipients = [e.recipients[0].recipient for e in email_queue_list] | |||||
for email in emails: | |||||
self.assertTrue(email in recipients) | |||||
@staticmethod | @staticmethod | ||||
def send_newsletter(published=0, schedule_send=None): | def send_newsletter(published=0, schedule_send=None): | ||||
frappe.db.sql("delete from `tabEmail Queue`") | frappe.db.sql("delete from `tabEmail Queue`") | ||||
@@ -83,27 +100,15 @@ class TestNewsletter(unittest.TestCase): | |||||
newsletter.send_emails() | newsletter.send_emails() | ||||
return newsletter.name | return newsletter.name | ||||
def test_portal(self): | |||||
self.send_newsletter(1) | |||||
frappe.set_user("test1@example.com") | |||||
from frappe.email.doctype.newsletter.newsletter import get_newsletter_list | |||||
newsletters = get_newsletter_list("Newsletter", None, None, 0) | |||||
self.assertEqual(len(newsletters), 1) | |||||
def test_newsletter_context(self): | |||||
context = frappe._dict() | |||||
newsletter_name = self.send_newsletter(1) | |||||
frappe.set_user("test2@example.com") | |||||
doc = frappe.get_doc("Newsletter", newsletter_name) | |||||
doc.get_context(context) | |||||
self.assertEqual(context.no_cache, 1) | |||||
self.assertTrue("attachments" not in list(context)) | |||||
def test_schedule_send(self): | |||||
self.send_newsletter(schedule_send=add_days(getdate(), -1)) | |||||
email_queue_list = [frappe.get_doc('Email Queue', e.name) for e in frappe.get_all("Email Queue")] | |||||
self.assertEqual(len(email_queue_list), 4) | |||||
recipients = [e.recipients[0].recipient for e in email_queue_list] | |||||
def make_email_group(self): | |||||
email_group = "_Test Email Group" | |||||
if not frappe.db.exists("Email Group", email_group): | |||||
frappe.get_doc("Email Group", email_group).insert() | |||||
for email in emails: | for email in emails: | ||||
self.assertTrue(email in recipients) | |||||
if not frappe.db.exists('Email Group Member', dict(email=email, email_group = email_group)): | |||||
frappe.get_doc({ | |||||
"doctype": "Email Group Member", | |||||
"email": email, | |||||
"email_group": email_group | |||||
}).insert() |
@@ -323,3 +323,4 @@ frappe.patches.v13_0.update_icons_in_customized_desk_pages | |||||
execute:frappe.db.set_default('desktop:home_page', 'space') | execute:frappe.db.set_default('desktop:home_page', 'space') | ||||
execute:frappe.delete_doc_if_exists('Page', 'workspace') | execute:frappe.delete_doc_if_exists('Page', 'workspace') | ||||
execute:frappe.delete_doc_if_exists('Page', 'dashboard', force=1) | execute:frappe.delete_doc_if_exists('Page', 'dashboard', force=1) | ||||
frappe.core.doctype.page.patches.drop_unused_pages |
@@ -253,10 +253,7 @@ frappe.Application = Class.extend({ | |||||
}, | }, | ||||
load_bootinfo: function() { | load_bootinfo: function() { | ||||
if(frappe.boot) { | if(frappe.boot) { | ||||
frappe.modules = {}; | |||||
(frappe.boot.allowed_workspaces || []).forEach(function(m) { | |||||
frappe.modules[m.module]=m; | |||||
}); | |||||
this.setup_workspaces(); | |||||
frappe.model.sync(frappe.boot.docs); | frappe.model.sync(frappe.boot.docs); | ||||
$.extend(frappe._messages, frappe.boot.__messages); | $.extend(frappe._messages, frappe.boot.__messages); | ||||
this.check_metadata_cache_status(); | this.check_metadata_cache_status(); | ||||
@@ -278,6 +275,19 @@ frappe.Application = Class.extend({ | |||||
} | } | ||||
}, | }, | ||||
setup_workspaces() { | |||||
frappe.modules = {}; | |||||
frappe.workspaces = {}; | |||||
for (let page of frappe.boot.allowed_workspaces || []) { | |||||
frappe.modules[page.module]=page; | |||||
frappe.workspaces[frappe.router.slug(page.name)] = page; | |||||
} | |||||
if (!frappe.workspaces['home']) { | |||||
// default workspace is settings for Frappe | |||||
frappe.workspaces['home'] = frappe.workspaces['settings']; | |||||
} | |||||
}, | |||||
load_user_permissions: function() { | load_user_permissions: function() { | ||||
frappe.defaults.update_user_permissions(); | frappe.defaults.update_user_permissions(); | ||||
@@ -35,7 +35,7 @@ frappe.views.Views = class Views { | |||||
} | } | ||||
set_route(view, calendar_name) { | set_route(view, calendar_name) { | ||||
const route = [this.get_doctype_route(), 'view', view]; | |||||
const route = [this.slug(), 'view', view]; | |||||
if (calendar_name) route.push(calendar_name); | if (calendar_name) route.push(calendar_name); | ||||
frappe.set_route(route); | frappe.set_route(route); | ||||
} | } | ||||
@@ -233,11 +233,11 @@ frappe.views.Views = class Views { | |||||
// has standard calendar view | // has standard calendar view | ||||
calendars.push({ | calendars.push({ | ||||
name: 'Default', | name: 'Default', | ||||
route: `/app/${this.get_doctype_route()}/view/calendar/default` | |||||
route: `/app/${this.slug()}/view/calendar/default` | |||||
}); | }); | ||||
} | } | ||||
result.map(calendar => { | result.map(calendar => { | ||||
calendars.push({name: calendar.name, route: `/app/${this.get_doctype_route()}/view/calendar/${calendar.name}`}); | |||||
calendars.push({name: calendar.name, route: `/app/${this.slug()}/view/calendar/${calendar.name}`}); | |||||
}); | }); | ||||
return calendars; | return calendars; | ||||
@@ -263,7 +263,7 @@ frappe.views.Views = class Views { | |||||
return accounts_to_add; | return accounts_to_add; | ||||
} | } | ||||
get_doctype_route() { | |||||
slug() { | |||||
return frappe.router.slug(frappe.router.doctype_layout || this.doctype); | return frappe.router.slug(frappe.router.doctype_layout || this.doctype); | ||||
} | } | ||||
} | } |
@@ -117,40 +117,50 @@ frappe.router = { | |||||
}, | }, | ||||
convert_to_standard_route(route) { | convert_to_standard_route(route) { | ||||
// /app/settings = ["Workspaces", "Settings"] | |||||
// /app/user = ["List", "User"] | // /app/user = ["List", "User"] | ||||
// /app/user/view/report = ["List", "User", "Report"] | // /app/user/view/report = ["List", "User", "Report"] | ||||
// /app/user/view/tree = ["Tree", "User"] | // /app/user/view/tree = ["Tree", "User"] | ||||
// /app/user/user-001 = ["Form", "User", "user-001"] | // /app/user/user-001 = ["Form", "User", "user-001"] | ||||
// /app/user/user-001 = ["Form", "User", "user-001"] | // /app/user/user-001 = ["Form", "User", "user-001"] | ||||
// /app/event/view/calendar/default = ["List", "Event", "Calendar", "Default"] | // /app/event/view/calendar/default = ["List", "Event", "Calendar", "Default"] | ||||
let standard_route = route; | |||||
let doctype_route = this.routes[route[0]]; | |||||
if (doctype_route) { | |||||
// doctype route | |||||
if (route[1]) { | |||||
if (route[2] && route[1]==='view') { | |||||
standard_route = this.get_standard_route_for_list(route, doctype_route); | |||||
} else { | |||||
let docname = route[1]; | |||||
if (route.length > 2) { | |||||
docname = route.slice(1).join('/'); | |||||
} | |||||
standard_route = ['Form', doctype_route.doctype, docname]; | |||||
} | |||||
} else if (frappe.model.is_single(doctype_route.doctype)) { | |||||
standard_route = ['Form', doctype_route.doctype, doctype_route.doctype]; | |||||
if (frappe.workspaces[route[0]]) { | |||||
// workspace | |||||
route = ['Workspaces', frappe.workspaces[route[0]].name]; | |||||
} else if (this.routes[route[0]]) { | |||||
// route | |||||
route = this.set_doctype_route(route); | |||||
} | |||||
return route; | |||||
}, | |||||
set_doctype_route(route) { | |||||
let doctype_route = this.routes[route[0]]; | |||||
// doctype route | |||||
if (route[1]) { | |||||
if (route[2] && route[1]==='view') { | |||||
route = this.get_standard_route_for_list(route, doctype_route); | |||||
} else { | } else { | ||||
standard_route = ['List', doctype_route.doctype, 'List']; | |||||
let docname = route[1]; | |||||
if (route.length > 2) { | |||||
docname = route.slice(1).join('/'); | |||||
} | |||||
route = ['Form', doctype_route.doctype, docname]; | |||||
} | } | ||||
} else if (frappe.model.is_single(doctype_route.doctype)) { | |||||
route = ['Form', doctype_route.doctype, doctype_route.doctype]; | |||||
} else { | |||||
route = ['List', doctype_route.doctype, 'List']; | |||||
} | |||||
if (doctype_route.doctype_layout) { | |||||
// set the layout | |||||
this.doctype_layout = doctype_route.doctype_layout; | |||||
} | |||||
if (doctype_route.doctype_layout) { | |||||
// set the layout | |||||
this.doctype_layout = doctype_route.doctype_layout; | |||||
} | } | ||||
return standard_route; | |||||
return route; | |||||
}, | }, | ||||
get_standard_route_for_list(route, doctype_route) { | get_standard_route_for_list(route, doctype_route) { | ||||
@@ -186,14 +196,8 @@ frappe.router = { | |||||
// create the page generator (factory) object and call `show` | // create the page generator (factory) object and call `show` | ||||
// if there is no generator, render the `Page` object | // if there is no generator, render the `Page` object | ||||
// first the router needs to know if its a "page", "doctype", "space" | |||||
const route = this.current_route; | const route = this.current_route; | ||||
const factory = frappe.utils.to_title_case(route[0]); | const factory = frappe.utils.to_title_case(route[0]); | ||||
if (factory === 'Workspace') { | |||||
frappe.views.pageview.show(''); | |||||
return; | |||||
} | |||||
if (route[1] && frappe.views[factory + "Factory"]) { | if (route[1] && frappe.views[factory + "Factory"]) { | ||||
route[0] = factory; | route[0] = factory; | ||||
@@ -329,7 +333,7 @@ frappe.router = { | |||||
}, | }, | ||||
make_url(params) { | make_url(params) { | ||||
return '/app/' + $.map(params, function(a) { | |||||
let path_string = $.map(params, function(a) { | |||||
if ($.isPlainObject(a)) { | if ($.isPlainObject(a)) { | ||||
frappe.route_options = a; | frappe.route_options = a; | ||||
return null; | return null; | ||||
@@ -342,6 +346,8 @@ frappe.router = { | |||||
return a; | return a; | ||||
} | } | ||||
}).join('/'); | }).join('/'); | ||||
return '/app/' + (path_string || 'home'); | |||||
}, | }, | ||||
push_state(url) { | push_state(url) { | ||||
@@ -88,8 +88,7 @@ frappe.breadcrumbs = { | |||||
if (breadcrumbs.workspace) { | if (breadcrumbs.workspace) { | ||||
if(!breadcrumbs.module_info.blocked && frappe.visible_modules.includes(breadcrumbs.module_info.module)) { | if(!breadcrumbs.module_info.blocked && frappe.visible_modules.includes(breadcrumbs.module_info.module)) { | ||||
$(repl('<li><a href="/app/space/%(module)s">%(label)s</a></li>', | |||||
{ module: breadcrumbs.workspace, label: __(breadcrumbs.workspace) })) | |||||
$(`<li><a href="/app/${frappe.router.slug(breadcrumbs.workspace)}">${__(breadcrumbs.workspace)}</a></li>`) | |||||
.appendTo(this.$breadcrumbs); | .appendTo(this.$breadcrumbs); | ||||
} | } | ||||
} | } | ||||
@@ -6,18 +6,18 @@ frappe.provide("frappe.standard_pages"); | |||||
frappe.views.pageview = { | frappe.views.pageview = { | ||||
with_page: function(name, callback) { | with_page: function(name, callback) { | ||||
if(in_list(Object.keys(frappe.standard_pages), name)) { | |||||
if(!frappe.pages[name]) { | |||||
if (frappe.standard_pages[name]) { | |||||
if (!frappe.pages[name]) { | |||||
frappe.standard_pages[name](); | frappe.standard_pages[name](); | ||||
} | } | ||||
callback(); | callback(); | ||||
return; | return; | ||||
} | } | ||||
if((locals.Page && locals.Page[name] && locals.Page[name].script) || name==window.page_name) { | |||||
if ((locals.Page && locals.Page[name] && locals.Page[name].script) || name==window.page_name) { | |||||
// already loaded | // already loaded | ||||
callback(); | callback(); | ||||
} else if(localStorage["_page:" + name] && frappe.boot.developer_mode!=1) { | |||||
} else if (localStorage["_page:" + name] && frappe.boot.developer_mode!=1) { | |||||
// cached in local storage | // cached in local storage | ||||
frappe.model.sync(JSON.parse(localStorage["_page:" + name])); | frappe.model.sync(JSON.parse(localStorage["_page:" + name])); | ||||
callback(); | callback(); | ||||
@@ -27,7 +27,7 @@ frappe.views.pageview = { | |||||
method: 'frappe.desk.desk_page.getpage', | method: 'frappe.desk.desk_page.getpage', | ||||
args: {'name':name }, | args: {'name':name }, | ||||
callback: function(r) { | callback: function(r) { | ||||
if(!r.docs._dynamic_page) { | |||||
if (!r.docs._dynamic_page) { | |||||
localStorage["_page:" + name] = JSON.stringify(r.docs); | localStorage["_page:" + name] = JSON.stringify(r.docs); | ||||
} | } | ||||
callback(); | callback(); | ||||
@@ -61,14 +61,14 @@ frappe.views.Page = class Page { | |||||
var me = this; | var me = this; | ||||
// web home page | // web home page | ||||
if(name==window.page_name) { | |||||
if (name==window.page_name) { | |||||
this.wrapper = document.getElementById('page-' + name); | this.wrapper = document.getElementById('page-' + name); | ||||
this.wrapper.label = document.title || window.page_name; | this.wrapper.label = document.title || window.page_name; | ||||
this.wrapper.page_name = window.page_name; | this.wrapper.page_name = window.page_name; | ||||
frappe.pages[window.page_name] = this.wrapper; | frappe.pages[window.page_name] = this.wrapper; | ||||
} else { | } else { | ||||
this.pagedoc = locals.Page[this.name]; | this.pagedoc = locals.Page[this.name]; | ||||
if(!this.pagedoc) { | |||||
if (!this.pagedoc) { | |||||
frappe.show_not_found(name); | frappe.show_not_found(name); | ||||
return; | return; | ||||
} | } | ||||
@@ -77,7 +77,7 @@ frappe.views.Page = class Page { | |||||
this.wrapper.page_name = this.pagedoc.name; | this.wrapper.page_name = this.pagedoc.name; | ||||
// set content, script and style | // set content, script and style | ||||
if(this.pagedoc.content) | |||||
if (this.pagedoc.content) | |||||
this.wrapper.innerHTML = this.pagedoc.content; | this.wrapper.innerHTML = this.pagedoc.content; | ||||
frappe.dom.eval(this.pagedoc.__script || this.pagedoc.script || ''); | frappe.dom.eval(this.pagedoc.__script || this.pagedoc.script || ''); | ||||
frappe.dom.set_style(this.pagedoc.style || ''); | frappe.dom.set_style(this.pagedoc.style || ''); | ||||
@@ -98,7 +98,7 @@ frappe.views.Page = class Page { | |||||
trigger_page_event(eventname) { | trigger_page_event(eventname) { | ||||
var me = this; | var me = this; | ||||
if(me.wrapper[eventname]) { | |||||
if (me.wrapper[eventname]) { | |||||
me.wrapper[eventname](me.wrapper); | me.wrapper[eventname](me.wrapper); | ||||
} | } | ||||
} | } | ||||
@@ -123,11 +123,11 @@ frappe.show_not_permitted = function(page_name) { | |||||
frappe.show_message_page = function(opts) { | frappe.show_message_page = function(opts) { | ||||
// opts can include `page_name`, `message`, `icon` or `img` | // opts can include `page_name`, `message`, `icon` or `img` | ||||
if(!opts.page_name) { | |||||
if (!opts.page_name) { | |||||
opts.page_name = frappe.get_route_str(); | opts.page_name = frappe.get_route_str(); | ||||
} | } | ||||
if(opts.icon) { | |||||
if (opts.icon) { | |||||
opts.img = repl('<span class="%(icon)s message-page-icon"></span> ', opts); | opts.img = repl('<span class="%(icon)s message-page-icon"></span> ', opts); | ||||
} else if (opts.img) { | } else if (opts.img) { | ||||
opts.img = repl('<img src="%(img)s" class="message-page-image">', opts); | opts.img = repl('<img src="%(img)s" class="message-page-image">', opts); | ||||
@@ -1,3 +1,18 @@ | |||||
frappe.standard_pages['Workspaces'] = function() { | |||||
var wrapper = frappe.container.add_page('Workspaces'); | |||||
frappe.ui.make_app_page({ | |||||
parent: wrapper, | |||||
name: 'Workspaces', | |||||
title: __("Workspace"), | |||||
}); | |||||
frappe.workspace = new frappe.views.Workspace(wrapper); | |||||
$(wrapper).bind('show', function () { | |||||
frappe.workspace.show(); | |||||
}); | |||||
}; | |||||
frappe.views.Workspace = class Workspace { | frappe.views.Workspace = class Workspace { | ||||
constructor(wrapper) { | constructor(wrapper) { | ||||
this.wrapper = $(wrapper); | this.wrapper = $(wrapper); | ||||
@@ -14,15 +29,24 @@ frappe.views.Workspace = class Workspace { | |||||
"Administration" | "Administration" | ||||
]; | ]; | ||||
this.fetch_desktop_settings().then(() => { | |||||
this.make_sidebar(); | |||||
}) | |||||
this.setup_workspaces(); | |||||
this.make_sidebar(); | |||||
} | |||||
setup_workspaces() { | |||||
// workspaces grouped by categories | |||||
this.workspaces = {}; | |||||
for (let page of frappe.boot.allowed_workspaces) { | |||||
if (!this.workspaces[page.category]) { | |||||
this.workspaces[page.category] = []; | |||||
} | |||||
this.workspaces[page.category].push(page); | |||||
} | |||||
} | } | ||||
show() { | show() { | ||||
let page = this.get_page_to_show(); | let page = this.get_page_to_show(); | ||||
this.page.set_title(`${__(page)}`); | this.page.set_title(`${__(page)}`); | ||||
frappe.set_route('space', page); | |||||
this.show_page(page); | this.show_page(page); | ||||
} | } | ||||
@@ -40,44 +64,22 @@ frappe.views.Workspace = class Workspace { | |||||
if (localStorage.current_workspace) { | if (localStorage.current_workspace) { | ||||
default_page = localStorage.current_workspace; | default_page = localStorage.current_workspace; | ||||
} else if (this.desktop_settings) { | |||||
default_page = this.desktop_settings["Modules"][0].name; | |||||
} else if (this.workspaces) { | |||||
default_page = this.workspaces["Modules"][0].name; | |||||
} else if (frappe.boot.allowed_workspaces) { | } else if (frappe.boot.allowed_workspaces) { | ||||
default_page = frappe.boot.allowed_workspaces[0].name; | default_page = frappe.boot.allowed_workspaces[0].name; | ||||
} else { | } else { | ||||
default_page = "Website"; | |||||
default_page = "Settings"; | |||||
} | } | ||||
let page = frappe.get_route()[1] || default_page; | let page = frappe.get_route()[1] || default_page; | ||||
return page; | return page; | ||||
} | } | ||||
fetch_desktop_settings() { | |||||
return frappe | |||||
.call("frappe.desk.desktop.get_desk_sidebar_items") | |||||
.then(response => { | |||||
if (response.message) { | |||||
this.desktop_settings = response.message; | |||||
} else { | |||||
frappe.throw({ | |||||
title: __("Couldn't Load Desk"), | |||||
message: | |||||
__("Something went wrong while loading Desk. <b>Please relaod the page</b>. If the problem persists, contact the Administrator"), | |||||
indicator: "red", | |||||
primary_action: { | |||||
label: __("Reload"), | |||||
action: () => location.reload() | |||||
} | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
make_sidebar() { | make_sidebar() { | ||||
this.sidebar_categories.forEach(category => { | this.sidebar_categories.forEach(category => { | ||||
if (this.desktop_settings[category]) { | |||||
this.build_sidebar_section(category, this.desktop_settings[category]) | |||||
if (this.workspaces[category]) { | |||||
this.build_sidebar_section(category, this.workspaces[category]); | |||||
} | } | ||||
}); | }); | ||||
} | } | ||||
@@ -94,7 +96,7 @@ frappe.views.Workspace = class Workspace { | |||||
const get_sidebar_item = function (item) { | const get_sidebar_item = function (item) { | ||||
return $(` | return $(` | ||||
<a | <a | ||||
href="/app/space/${item.name}" | |||||
href="/app/${frappe.router.slug(item.name)}" | |||||
class="desk-sidebar-item standard-sidebar-item ${item.selected ? "selected" : ""}" | class="desk-sidebar-item standard-sidebar-item ${item.selected ? "selected" : ""}" | ||||
> | > | ||||
<span>${frappe.utils.icon(item.icon || "folder-normal", "md")}</span> | <span>${frappe.utils.icon(item.icon || "folder-normal", "md")}</span> | ||||
@@ -31,7 +31,7 @@ class WebsiteSearch(FullTextSearch): | |||||
self (object): FullTextSearch Instance | self (object): FullTextSearch Instance | ||||
""" | """ | ||||
routes = get_static_pages_from_all_apps() | routes = get_static_pages_from_all_apps() | ||||
routes += get_doctype_routes_with_web_view() | |||||
routes += slugs_with_web_view() | |||||
documents = [self.get_document_to_index(route) for route in routes] | documents = [self.get_document_to_index(route) for route in routes] | ||||
return documents | return documents | ||||
@@ -74,7 +74,7 @@ class WebsiteSearch(FullTextSearch): | |||||
) | ) | ||||
def get_doctype_routes_with_web_view(): | |||||
def slugs_with_web_view(): | |||||
all_routes = [] | all_routes = [] | ||||
filters = { "has_web_view": 1, "allow_guest_to_view": 1, "index_web_pages_for_search": 1} | filters = { "has_web_view": 1, "allow_guest_to_view": 1, "index_web_pages_for_search": 1} | ||||
fields = ["name", "is_published_field"] | fields = ["name", "is_published_field"] | ||||
@@ -41,15 +41,15 @@ class TestSearch(unittest.TestCase): | |||||
#Search for the word "pay", part of the word "pays" (country) in french. | #Search for the word "pay", part of the word "pays" (country) in french. | ||||
def test_link_search_in_foreign_language(self): | def test_link_search_in_foreign_language(self): | ||||
frappe.local.lang = 'fr' | |||||
search_widget(doctype="DocType", txt="pay", page_length=20) | |||||
output = frappe.response["values"] | |||||
result = [['found' for x in y if x=="Country"] for y in output] | |||||
self.assertTrue(['found'] in result) | |||||
def tearDown(self): | |||||
frappe.local.lang = 'en' | |||||
try: | |||||
frappe.local.lang = 'fr' | |||||
search_widget(doctype="DocType", txt="pay", page_length=20) | |||||
output = frappe.response["values"] | |||||
result = [['found' for x in y if x=="Country"] for y in output] | |||||
self.assertTrue(['found'] in result) | |||||
finally: | |||||
frappe.local.lang = 'en' | |||||
def test_validate_and_sanitize_search_inputs(self): | def test_validate_and_sanitize_search_inputs(self): | ||||
@@ -15,9 +15,12 @@ class TestTranslate(unittest.TestCase): | |||||
self.assertListEqual(data, expected_output) | self.assertListEqual(data, expected_output) | ||||
def test_translation_with_context(self): | def test_translation_with_context(self): | ||||
frappe.local.lang = 'fr' | |||||
self.assertEqual(_('Change'), 'Changement') | |||||
self.assertEqual(_('Change', context='Coins'), 'la monnaie') | |||||
try: | |||||
frappe.local.lang = 'fr' | |||||
self.assertEqual(_('Change'), 'Changement') | |||||
self.assertEqual(_('Change', context='Coins'), 'la monnaie') | |||||
finally: | |||||
frappe.local.lang = 'en' | |||||
expected_output = [ | expected_output = [ | ||||
('apps/frappe/frappe/tests/translation_test_file.txt', 'Warning: Unable to find {0} in any table related to {1}', 'This is some context', 2), | ('apps/frappe/frappe/tests/translation_test_file.txt', 'Warning: Unable to find {0} in any table related to {1}', 'This is some context', 2), | ||||
@@ -17,7 +17,7 @@ from six.moves.urllib.parse import quote, urljoin | |||||
from html2text import html2text | from html2text import html2text | ||||
from markdown2 import markdown, MarkdownError | from markdown2 import markdown, MarkdownError | ||||
from six import iteritems, text_type, string_types, integer_types | from six import iteritems, text_type, string_types, integer_types | ||||
from frappe.desk.utils import get_doctype_route | |||||
from frappe.desk.utils import slug | |||||
DATE_FORMAT = "%Y-%m-%d" | DATE_FORMAT = "%Y-%m-%d" | ||||
TIME_FORMAT = "%H:%M:%S.%f" | TIME_FORMAT = "%H:%M:%S.%f" | ||||
@@ -1059,17 +1059,17 @@ def get_link_to_report(name, label=None, report_type=None, doctype=None, filters | |||||
return """<a href='{0}'>{1}</a>""".format(get_url_to_report(name, report_type, doctype), label) | return """<a href='{0}'>{1}</a>""".format(get_url_to_report(name, report_type, doctype), label) | ||||
def get_absolute_url(doctype, name): | def get_absolute_url(doctype, name): | ||||
return "/app/{0}/{1}".format(quoted(get_doctype_route(doctype)), quoted(name)) | |||||
return "/app/{0}/{1}".format(quoted(slug(doctype)), quoted(name)) | |||||
def get_url_to_form(doctype, name): | def get_url_to_form(doctype, name): | ||||
return get_url(uri = "/app/{0}/{1}".format(quoted(get_doctype_route(doctype)), quoted(name))) | |||||
return get_url(uri = "/app/{0}/{1}".format(quoted(slug(doctype)), quoted(name))) | |||||
def get_url_to_list(doctype): | def get_url_to_list(doctype): | ||||
return get_url(uri = "/app/{0}".format(quoted(get_doctype_route(doctype)))) | |||||
return get_url(uri = "/app/{0}".format(quoted(slug(doctype)))) | |||||
def get_url_to_report(name, report_type = None, doctype = None): | def get_url_to_report(name, report_type = None, doctype = None): | ||||
if report_type == "Report Builder": | if report_type == "Report Builder": | ||||
return get_url(uri = "/app/{0}/view/report/{1}".format(quoted(get_doctype_route(doctype)), quoted(name))) | |||||
return get_url(uri = "/app/{0}/view/report/{1}".format(quoted(slug(doctype)), quoted(name))) | |||||
else: | else: | ||||
return get_url(uri = "/app/query-report/{0}".format(quoted(name))) | return get_url(uri = "/app/query-report/{0}".format(quoted(name))) | ||||
@@ -441,4 +441,4 @@ def get_doctypes_with_web_view(): | |||||
return frappe.cache().get_value('doctypes_with_web_view', _get) | return frappe.cache().get_value('doctypes_with_web_view', _get) | ||||
def get_start_folders(): | def get_start_folders(): | ||||
return frappe.local.flags.web_pages_folders or ('www', 'templates/pages') | |||||
return frappe.local.flags.web_pages_folders or ('www', 'templates/pages') |