diff --git a/frappe/commands/site.py b/frappe/commands/site.py old mode 100755 new mode 100644 index c5d2257d75..b54f369e34 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -1,7 +1,7 @@ # imports - standard imports import os -import sys import shutil +import sys # imports - third party imports import click @@ -65,11 +65,11 @@ def restore(context, sql_file_path, encryption_key=None, db_root_username=None, "Restore site database from an sql file" from frappe.installer import ( _new_site, - extract_sql_from_archive, extract_files, + extract_sql_from_archive, is_downgrade, is_partial, - validate_database_sql + validate_database_sql, ) from frappe.utils.backups import Backup if not os.path.exists(sql_file_path): @@ -207,7 +207,7 @@ def restore(context, sql_file_path, encryption_key=None, db_root_username=None, @click.option('--encryption-key', help='Backup encryption key') @pass_context def partial_restore(context, sql_file_path, verbose, encryption_key=None): - from frappe.installer import partial_restore, extract_sql_from_archive + from frappe.installer import extract_sql_from_archive, partial_restore from frappe.utils.backups import Backup if not os.path.exists(sql_file_path): @@ -545,7 +545,7 @@ def _use(site, sites_path='.'): def use(site, sites_path='.'): if os.path.exists(os.path.join(sites_path, site)): - with open(os.path.join(sites_path, "currentsite.txt"), "w") as sitefile: + with open(os.path.join(sites_path, "currentsite.txt"), "w") as sitefile: sitefile.write(site) print("Current Site set to {}".format(site)) else: @@ -751,6 +751,7 @@ def set_admin_password(context, admin_password=None, logout_all_sessions=False): def set_user_password(site, user, password, logout_all_sessions=False): import getpass + from frappe.utils.password import update_password try: @@ -881,15 +882,16 @@ def stop_recording(context): raise SiteNotSpecifiedError @click.command('ngrok') +@click.option('--bind-tls', is_flag=True, default=False, help='Returns a reference to the https tunnel.') @pass_context -def start_ngrok(context): +def start_ngrok(context, bind_tls): from pyngrok import ngrok site = get_site(context) frappe.init(site=site) port = frappe.conf.http_port or frappe.conf.webserver_port - tunnel = ngrok.connect(addr=str(port), host_header=site) + tunnel = ngrok.connect(addr=str(port), host_header=site, bind_tls=bind_tls) print(f'Public URL: {tunnel.public_url}') print('Inspect logs at http://localhost:4040') diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index f89f0d8765..475762f39d 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -18,6 +18,7 @@ from urllib.parse import unquote from frappe.utils.user import is_system_user from frappe.contacts.doctype.contact.contact import get_contact_name from frappe.automation.doctype.assignment_rule.assignment_rule import apply as apply_assignment_rule +from parse import compile exclude_from_linked_with = True @@ -114,6 +115,44 @@ class Communication(Document, CommunicationEmailMixin): frappe.publish_realtime('new_message', self.as_dict(), user=self.reference_name, after_commit=True) + def set_signature_in_email_content(self): + """Set sender's User.email_signature or default outgoing's EmailAccount.signature to the email + """ + if not self.content: + return + + quill_parser = compile('
{}
') + email_body = quill_parser.parse(self.content) + + if not email_body: + return + + email_body = email_body[0] + + user_email_signature = frappe.db.get_value( + "User", + self.sender, + "email_signature", + ) if self.sender else None + + signature = user_email_signature or frappe.db.get_value( + "Email Account", + {"default_outgoing": 1, "add_signature": 1}, + "signature", + ) + + if not signature: + return + + _signature = quill_parser.parse(signature)[0] if "ql-editor" in signature else None + + if (_signature or signature) not in self.content: + self.content = f'{self.content}


{signature}' + + def before_save(self): + if not self.flags.skip_add_signature: + self.set_signature_in_email_content() + def on_update(self): # add to _comment property of the doctype, so it shows up in # comments count for the list view diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 46ef7bf5d2..b51749ccb7 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -22,12 +22,30 @@ OUTGOING_EMAIL_ACCOUNT_MISSING = _(""" @frappe.whitelist() -def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", - sender=None, sender_full_name=None, recipients=None, communication_medium="Email", send_email=False, - print_html=None, print_format=None, attachments='[]', send_me_a_copy=False, cc=None, bcc=None, - flags=None, read_receipt=None, print_letterhead=True, email_template=None, communication_type=None, - ignore_permissions=False) -> Dict[str, str]: - """Make a new communication. +def make( + doctype=None, + name=None, + content=None, + subject=None, + sent_or_received="Sent", + sender=None, + sender_full_name=None, + recipients=None, + communication_medium="Email", + send_email=False, + print_html=None, + print_format=None, + attachments="[]", + send_me_a_copy=False, + cc=None, + bcc=None, + read_receipt=None, + print_letterhead=True, + email_template=None, + communication_type=None, + **kwargs, +) -> Dict[str, str]: + """Make a new communication. Checks for email permissions for specified Document. :param doctype: Reference DocType. :param name: Reference Document name. @@ -44,17 +62,71 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = :param send_me_a_copy: Send a copy to the sender (default **False**). :param email_template: Template which is used to compose mail . """ - is_error_report = (doctype=="User" and name==frappe.session.user and subject=="Error Report") - send_me_a_copy = cint(send_me_a_copy) + if kwargs: + from frappe.utils.commands import warn + warn( + f"Options {kwargs} used in frappe.core.doctype.communication.email.make " + "are deprecated or unsupported", + category=DeprecationWarning + ) + + if doctype and name and not frappe.has_permission(doctype=doctype, ptype="email", doc=name): + raise frappe.PermissionError( + f"You are not allowed to send emails related to: {doctype} {name}" + ) + + return _make( + doctype=doctype, + name=name, + content=content, + subject=subject, + sent_or_received=sent_or_received, + sender=sender, + sender_full_name=sender_full_name, + recipients=recipients, + communication_medium=communication_medium, + send_email=send_email, + print_html=print_html, + print_format=print_format, + attachments=attachments, + send_me_a_copy=cint(send_me_a_copy), + cc=cc, + bcc=bcc, + read_receipt=read_receipt, + print_letterhead=print_letterhead, + email_template=email_template, + communication_type=communication_type, + add_signature=False, + ) - if not ignore_permissions: - if doctype and name and not is_error_report and not frappe.has_permission(doctype, "email", name) and not (flags or {}).get('ignore_doctype_permissions'): - raise frappe.PermissionError("You are not allowed to send emails related to: {doctype} {name}".format( - doctype=doctype, name=name)) - if not sender: - sender = get_formatted_email(frappe.session.user) +def _make( + doctype=None, + name=None, + content=None, + subject=None, + sent_or_received="Sent", + sender=None, + sender_full_name=None, + recipients=None, + communication_medium="Email", + send_email=False, + print_html=None, + print_format=None, + attachments="[]", + send_me_a_copy=False, + cc=None, + bcc=None, + read_receipt=None, + print_letterhead=True, + email_template=None, + communication_type=None, + add_signature=True, +) -> Dict[str, str]: + """Internal method to make a new communication that ignores Permission checks. + """ + sender = sender or get_formatted_email(frappe.session.user) recipients = list_to_str(recipients) if isinstance(recipients, list) else recipients cc = list_to_str(cc) if isinstance(cc, list) else cc bcc = list_to_str(bcc) if isinstance(bcc, list) else bcc @@ -77,7 +149,9 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "read_receipt":read_receipt, "has_attachment": 1 if attachments else 0, "communication_type": communication_type, - }).insert(ignore_permissions=True) + }) + comm.flags.skip_add_signature = not add_signature + comm.insert(ignore_permissions=True) # if not committed, delayed task doesn't find the communication if attachments: @@ -87,17 +161,21 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = if cint(send_email): if not comm.get_outgoing_email_account(): - frappe.throw(msg=OUTGOING_EMAIL_ACCOUNT_MISSING, exc=frappe.OutgoingEmailError) + frappe.throw( + msg=OUTGOING_EMAIL_ACCOUNT_MISSING, exc=frappe.OutgoingEmailError + ) - comm.send_email(print_html=print_html, print_format=print_format, - send_me_a_copy=send_me_a_copy, print_letterhead=print_letterhead) + comm.send_email( + print_html=print_html, + print_format=print_format, + send_me_a_copy=send_me_a_copy, + print_letterhead=print_letterhead, + ) emails_not_sent_to = comm.exclude_emails_list(include_sender=send_me_a_copy) - return { - "name": comm.name, - "emails_not_sent_to": ", ".join(emails_not_sent_to) - } + return {"name": comm.name, "emails_not_sent_to": ", ".join(emails_not_sent_to)} + def validate_email(doc: "Communication") -> None: """Validate Email Addresses of Recipients and CC""" diff --git a/frappe/core/doctype/user/user.json b/frappe/core/doctype/user/user.json index a47f539466..9e9529cd5e 100644 --- a/frappe/core/doctype/user/user.json +++ b/frappe/core/doctype/user/user.json @@ -668,8 +668,7 @@ "link_fieldname": "user" } ], - "max_attachments": 5, - "modified": "2022-01-03 11:53:25.250822", + "modified": "2022-03-09 01:47:56.745069", "modified_by": "Administrator", "module": "Core", "name": "User", diff --git a/frappe/desk/form/linked_with.py b/frappe/desk/form/linked_with.py index 572d3f2a94..010d65c95b 100644 --- a/frappe/desk/form/linked_with.py +++ b/frappe/desk/form/linked_with.py @@ -1,9 +1,10 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE + import json from collections import defaultdict import itertools -from typing import List +from typing import Dict, List, Optional import frappe import frappe.desk.form.load @@ -367,7 +368,7 @@ def get_exempted_doctypes(): @frappe.whitelist() -def get_linked_docs(doctype, name, linkinfo=None, for_doctype=None): +def get_linked_docs(doctype: str, name: str, linkinfo: Optional[Dict] = None) -> Dict[str, List]: if isinstance(linkinfo, str): # additional fields are added in linkinfo linkinfo = json.loads(linkinfo) @@ -377,23 +378,21 @@ def get_linked_docs(doctype, name, linkinfo=None, for_doctype=None): if not linkinfo: return results - if for_doctype: - links = frappe.get_doc(doctype, name).get_link_filters(for_doctype) - - if links: - linkinfo = links - - if for_doctype in linkinfo: - # only get linked with for this particular doctype - linkinfo = { for_doctype: linkinfo.get(for_doctype) } - else: - return results - for dt, link in linkinfo.items(): filters = [] link["doctype"] = dt - link_meta_bundle = frappe.desk.form.load.get_meta_bundle(dt) + try: + link_meta_bundle = frappe.desk.form.load.get_meta_bundle(dt) + except Exception as e: + if isinstance(e, frappe.DoesNotExistError): + if frappe.local.message_log: + frappe.local.message_log.pop() + continue linkmeta = link_meta_bundle[0] + + if not linkmeta.has_permission(): + continue + if not linkmeta.get("issingle"): fields = [d.fieldname for d in linkmeta.get("fields", { "in_list_view": 1, @@ -456,6 +455,13 @@ def get_linked_docs(doctype, name, linkinfo=None, for_doctype=None): return results + +@frappe.whitelist() +def get(doctype, docname): + linked_doctypes = get_linked_doctypes(doctype=doctype) + return get_linked_docs(doctype=doctype, name=docname, linkinfo=linked_doctypes) + + @frappe.whitelist() def get_linked_doctypes(doctype, without_ignore_user_permissions_enabled=False): """add list of doctypes this doctype is 'linked' with. @@ -470,6 +476,7 @@ def get_linked_doctypes(doctype, without_ignore_user_permissions_enabled=False): else: return frappe.cache().hget("linked_doctypes", doctype, lambda: _get_linked_doctypes(doctype)) + def _get_linked_doctypes(doctype, without_ignore_user_permissions_enabled=False): ret = {} # find fields where this doctype is linked @@ -499,6 +506,7 @@ def _get_linked_doctypes(doctype, without_ignore_user_permissions_enabled=False) return ret + def get_linked_fields(doctype, without_ignore_user_permissions_enabled=False): filters = [['fieldtype','=', 'Link'], ['options', '=', doctype]] @@ -529,6 +537,7 @@ def get_linked_fields(doctype, without_ignore_user_permissions_enabled=False): return ret + def get_dynamic_linked_fields(doctype, without_ignore_user_permissions_enabled=False): ret = {} diff --git a/frappe/email/doctype/newsletter/newsletter.json b/frappe/email/doctype/newsletter/newsletter.json index baabd4991e..b42f4755cb 100644 --- a/frappe/email/doctype/newsletter/newsletter.json +++ b/frappe/email/doctype/newsletter/newsletter.json @@ -236,8 +236,7 @@ "index_web_pages_for_search": 1, "is_published_field": "published", "links": [], - "max_attachments": 3, - "modified": "2021-12-06 20:09:37.963141", + "modified": "2022-03-09 01:48:16.741603", "modified_by": "Administrator", "module": "Email", "name": "Newsletter", diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index 2b62530847..bad32fb68f 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -186,7 +186,7 @@ def get_context(context): def send_an_email(self, doc, context): from email.utils import formataddr - from frappe.core.doctype.communication.email import make as make_communication + from frappe.core.doctype.communication.email import _make as make_communication subject = self.subject if "{" in subject: subject = frappe.render_template(self.subject, context) @@ -216,7 +216,8 @@ def get_context(context): # Add mail notification to communication list # No need to add if it is already a communication. if doc.doctype != 'Communication': - make_communication(doctype=doc.doctype, + make_communication( + doctype=doc.doctype, name=doc.name, content=message, subject=subject, @@ -228,7 +229,7 @@ def get_context(context): cc=cc, bcc=bcc, communication_type='Automated Message', - ignore_permissions=True) + ) def send_a_slack_msg(self, doc, context): send_slack_message( diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index c25e996bd3..0f45e42aac 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -259,17 +259,12 @@ def get_formatted_html(subject, message, footer=None, print_html=None, email_account = email_account or EmailAccount.find_outgoing(match_by_email=sender) - signature = None - if "" not in message: - signature = get_signature(email_account) - rendered_email = frappe.get_template("templates/emails/standard.html").render({ "brand_logo": get_brand_logo(email_account) if with_container or header else None, "with_container": with_container, "site_url": get_url(), "header": get_header(header), "content": message, - "signature": signature, "footer": get_footer(email_account, footer), "title": subject, "print_html": print_html, @@ -281,8 +276,7 @@ def get_formatted_html(subject, message, footer=None, print_html=None, if unsubscribe_link: html = html.replace("", unsubscribe_link.html) - html = inline_style_in_html(html) - return html + return inline_style_in_html(html) @frappe.whitelist() def get_email_html(template, args, subject, header=None, with_container=False): diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py index faa3859c91..b4a53e3131 100644 --- a/frappe/model/rename_doc.py +++ b/frappe/model/rename_doc.py @@ -43,8 +43,8 @@ def update_document_title( title_field = doc.meta.get_title_field() - title_updated = (title_field != "name") and (updated_title != doc.get(title_field)) - name_updated = updated_name != doc.name + title_updated = updated_title and (title_field != "name") and (updated_title != doc.get(title_field)) + name_updated = updated_name and (updated_name != doc.name) if name_updated: docname = rename_doc(doctype=doctype, old=docname, new=updated_name, merge=merge) diff --git a/frappe/public/js/frappe/form/linked_with.js b/frappe/public/js/frappe/form/linked_with.js index 20db7bdb7c..c47a6e0c86 100644 --- a/frappe/public/js/frappe/form/linked_with.js +++ b/frappe/public/js/frappe/form/linked_with.js @@ -1,9 +1,8 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// MIT License. See license.txt +// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors +// MIT License. See LICENSE frappe.ui.form.LinkedWith = class LinkedWith { - constructor(opts) { $.extend(this, opts); } @@ -21,29 +20,23 @@ frappe.ui.form.LinkedWith = class LinkedWith { } make_dialog() { - this.dialog = new frappe.ui.Dialog({ title: __("Linked With") }); this.dialog.on_page_show = () => { - // execute ajax calls sequentially - // 1. get linked doctypes - // 2. load all doctypes - // 3. load linked docs - this.get_linked_doctypes() - .then(() => this.load_doctypes()) - .then(() => this.links_not_permitted_or_missing()) - .then(() => this.get_linked_docs()) - .then(() => this.make_html()); + frappe.xcall( + "frappe.desk.form.linked_with.get", + {"doctype": cur_frm.doctype, "docname": cur_frm.docname}, + ).then(r => { + this.frm.__linked_docs = r; + }).then(() => this.make_html()); }; } make_html() { - const linked_docs = this.frm.__linked_docs; - let html = ''; - + const linked_docs = this.frm.__linked_docs; const linked_doctypes = Object.keys(linked_docs); if (linked_doctypes.length === 0) { @@ -63,88 +56,6 @@ frappe.ui.form.LinkedWith = class LinkedWith { $(this.dialog.body).html(html); } - load_doctypes() { - const already_loaded = Object.keys(locals.DocType); - let doctypes_to_load = []; - - if (this.frm.__linked_doctypes) { - doctypes_to_load = - Object.keys(this.frm.__linked_doctypes) - .filter(doctype => !already_loaded.includes(doctype)); - } - - // load all doctypes asynchronously using with_doctype - const promises = doctypes_to_load.map(dt => { - return frappe.model.with_doctype(dt, () => { - if(frappe.listview_settings[dt]) { - // add additional fields to __linked_doctypes - this.frm.__linked_doctypes[dt].add_fields = - frappe.listview_settings[dt].add_fields; - } - }); - }); - - return Promise.all(promises); - } - - links_not_permitted_or_missing() { - let links = null; - - if (this.frm.__linked_doctypes) { - links = - Object.keys(this.frm.__linked_doctypes) - .filter(frappe.model.can_get_report); - } - - let flag; - if(!links) { - $(this.dialog.body).html(`${this.frm.__linked_doctypes - ? __("Not enough permission to see links") - : __("Not Linked to any record")}`); - flag = true; - } - flag = false; - - // reject Promise if not_permitted or missing - return new Promise( - (resolve, reject) => flag ? reject() : resolve() - ); - } - - get_linked_doctypes() { - return new Promise((resolve) => { - if (this.frm.__linked_doctypes) { - resolve(); - } - - frappe.call({ - method: "frappe.desk.form.linked_with.get_linked_doctypes", - args: { - doctype: this.frm.doctype - }, - callback: (r) => { - this.frm.__linked_doctypes = r.message; - resolve(); - } - }); - }); - } - - get_linked_docs() { - return frappe.call({ - method: "frappe.desk.form.linked_with.get_linked_docs", - args: { - doctype: this.frm.doctype, - name: this.frm.docname, - linkinfo: this.frm.__linked_doctypes, - for_doctype: this.for_doctype - }, - callback: (r) => { - this.frm.__linked_docs = r.message || {}; - } - }); - } - make_doc_head(heading) { return `

diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index 75063cc53f..d5ee82acce 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -760,6 +760,10 @@ class FilterArea { const doctype_fields = this.list_view.meta.fields; const title_field = this.list_view.meta.title_field; + const has_existing_filters = ( + this.list_view.filters + && this.list_view.filters.length > 0 + ); fields = fields.concat( doctype_fields @@ -794,13 +798,17 @@ class FilterArea { options = options.join("\n"); } } - let default_value = - fieldtype === "Link" - ? frappe.defaults.get_user_default(options) - : null; + + let default_value; + + if (fieldtype === "Link" && !has_existing_filters) { + default_value = frappe.defaults.get_user_default(options); + } + if (["__default", "__global"].includes(default_value)) { default_value = null; } + return { fieldtype: fieldtype, label: __(df.label), diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 5cfc7c75d4..98553a4a3e 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -83,32 +83,15 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { this.sort_by = this.view_user_settings.sort_by || "modified"; this.sort_order = this.view_user_settings.sort_order || "desc"; - // set filters from user_settings or list_settings - if ( - this.view_user_settings.filters && - this.view_user_settings.filters.length - ) { - // Priority 1: user_settings - const saved_filters = this.view_user_settings.filters; - this.filters = this.validate_filters(saved_filters); - } else { - // Priority 2: filters in listview_settings - this.filters = (this.settings.filters || []).map((f) => { - if (f.length === 3) { - f = [this.doctype, f[0], f[1], f[2]]; - } - return f; - }); - } - // build menu items this.menu_items = this.menu_items.concat(this.get_menu_items()); + // set filters from view_user_settings or list_settings if ( this.view_user_settings.filters && this.view_user_settings.filters.length ) { - // Priority 1: saved filters + // Priority 1: view_user_settings const saved_filters = this.view_user_settings.filters; this.filters = this.validate_filters(saved_filters); } else { diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index d073f5c7f2..f80d59350f 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -125,11 +125,12 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { } after_render() { - if (this.report_doc) { - this.set_dirty_state_for_custom_report(); - } else { + if (!this.report_doc) { this.save_report_settings(); + } else if (!$.isEmptyObject(this.report_doc.json)) { + this.set_dirty_state_for_custom_report(); } + if (!this.group_by) { this.init_chart(); } diff --git a/frappe/templates/emails/standard.html b/frappe/templates/emails/standard.html index 4a47c9cf90..2a2093e1e9 100644 --- a/frappe/templates/emails/standard.html +++ b/frappe/templates/emails/standard.html @@ -37,7 +37,6 @@

{{ content }}

-

{{ signature }}

diff --git a/frappe/website/doctype/blog_post/blog_post.json b/frappe/website/doctype/blog_post/blog_post.json index b05293f28b..5e3cc78d70 100644 --- a/frappe/website/doctype/blog_post/blog_post.json +++ b/frappe/website/doctype/blog_post/blog_post.json @@ -213,8 +213,7 @@ "index_web_pages_for_search": 1, "is_published_field": "published", "links": [], - "max_attachments": 5, - "modified": "2021-11-23 10:42:01.759723", + "modified": "2022-03-09 01:48:25.227295", "modified_by": "Administrator", "module": "Website", "name": "Blog Post", diff --git a/frappe/website/doctype/web_page/web_page.json b/frappe/website/doctype/web_page/web_page.json index b1fdd02af7..e7bd705272 100644 --- a/frappe/website/doctype/web_page/web_page.json +++ b/frappe/website/doctype/web_page/web_page.json @@ -338,8 +338,7 @@ "index_web_pages_for_search": 1, "is_published_field": "published", "links": [], - "max_attachments": 20, - "modified": "2022-01-03 13:01:48.182645", + "modified": "2022-03-09 01:45:28.548671", "modified_by": "Administrator", "module": "Website", "name": "Web Page", diff --git a/frappe/website/doctype/website_settings/website_settings.json b/frappe/website/doctype/website_settings/website_settings.json index 3b199a4b58..b628437315 100644 --- a/frappe/website/doctype/website_settings/website_settings.json +++ b/frappe/website/doctype/website_settings/website_settings.json @@ -420,8 +420,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "max_attachments": 10, - "modified": "2022-02-24 15:37:22.360138", + "modified": "2022-03-09 01:47:31.094462", "modified_by": "Administrator", "module": "Website", "name": "Website Settings", diff --git a/requirements.txt b/requirements.txt index ba4a1a598b..c77ab1d424 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,6 +29,7 @@ maxminddb-geolite2==2018.703 num2words~=0.5.10 oauthlib~=3.1.0 openpyxl~=3.0.7 +parse~=1.19.0 passlib~=1.7.4 paytmchecksum~=1.7.0 pdfkit~=0.6.1