From efa09f4a7340a1d3251c8b2a72786beb1c12b30e Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Tue, 10 Dec 2024 17:06:55 +0100
Subject: [PATCH 01/15] fix: clarify error message for child tables

---
 frappe/model/document.py | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/frappe/model/document.py b/frappe/model/document.py
index 745bbd4a7d8a..f3037277cf7a 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -1603,8 +1603,16 @@ def validate_from_to_dates(self, from_date_field: str, to_date_field: str) -> No
 			return
 
 		if date_diff(to_date, from_date) < 0:
+			table_row = ""
+			if self.meta.istable:
+				table_row = _("{0} row #{1}: ").format(
+					_(frappe.unscrub(self.parentfield)),
+					self.idx,
+				)
+
 			frappe.throw(
-				_("{0} must be after {1}").format(
+				table_row
+				+ _("{0} must be after {1}").format(
 					frappe.bold(_(self.meta.get_label(to_date_field))),
 					frappe.bold(_(self.meta.get_label(from_date_field))),
 				),

From 50ec3e8073492f68444e9e52b7252dee0c5baee9 Mon Sep 17 00:00:00 2001
From: Akhil Narang <me@akhilnarang.dev>
Date: Wed, 11 Dec 2024 17:59:13 +0530
Subject: [PATCH 02/15] fix: set `currency` system setting in webform
 `frappe.boot.sysdefaults`

Otherwise this resulted in the fallback `USD` showing for some currency fields in webforms

(cherry picked from commit a63cd10387cf2c019722246bc1170f7fd864a6c0)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
---
 frappe/website/utils.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/frappe/website/utils.py b/frappe/website/utils.py
index 35e909367062..ff764ec9dcdf 100644
--- a/frappe/website/utils.py
+++ b/frappe/website/utils.py
@@ -180,6 +180,7 @@ def get_boot_data():
 			"time_format": frappe.get_system_settings("time_format") or "HH:mm:ss",
 			"first_day_of_the_week": frappe.get_system_settings("first_day_of_the_week") or "Sunday",
 			"number_format": frappe.get_system_settings("number_format") or "#,###.##",
+			"currency": frappe.get_system_settings("currency"),
 		},
 		"time_zone": {
 			"system": get_system_timezone(),

From 30374b3b4e631e86c898f7753e31ab4bca9fb42f Mon Sep 17 00:00:00 2001
From: Akhil Narang <me@akhilnarang.dev>
Date: Mon, 25 Nov 2024 13:33:46 +0530
Subject: [PATCH 03/15] chore: update pre-commit config

Otherwise there was always a warning:

```
[WARNING] top-level `default_stages` uses deprecated stage names (commit) which will be removed in a future version.  run: `pre-commit migrate-config` to automatically fix this.
```

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
(cherry picked from commit 0f27bb495c5b67043e0eb68640d06fab9a87232c)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index bc20e86ebaac..51f0318cf88f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,5 +1,5 @@
 exclude: 'node_modules|.git'
-default_stages: [commit]
+default_stages: [pre-commit]
 fail_fast: false
 
 

From 363fa92feb59e517653a87533a5b123d0f4ac564 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot <developers@erpnext.com>
Date: Thu, 12 Dec 2024 05:46:10 +0530
Subject: [PATCH 04/15] fix: sync translations from crowdin (#28700)

---
 frappe/locale/es.po |  4 ++--
 frappe/locale/fa.po | 18 +++++++++---------
 frappe/locale/sv.po | 16 ++++++++--------
 frappe/locale/tr.po |  4 ++--
 4 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/frappe/locale/es.po b/frappe/locale/es.po
index da15b70017a6..982a0b19f35a 100644
--- a/frappe/locale/es.po
+++ b/frappe/locale/es.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: frappe\n"
 "Report-Msgid-Bugs-To: developers@frappe.io\n"
 "POT-Creation-Date: 2024-12-01 17:58+0000\n"
-"PO-Revision-Date: 2024-12-04 19:52\n"
+"PO-Revision-Date: 2024-12-08 20:00\n"
 "Last-Translator: developers@frappe.io\n"
 "Language-Team: Spanish\n"
 "MIME-Version: 1.0\n"
@@ -24188,7 +24188,7 @@ msgstr "Hora de inicio"
 
 #: frappe/templates/includes/comments/comments.html:8
 msgid "Start a new discussion"
-msgstr "Empezar un nuevo debate"
+msgstr "Empezar una nueva conversación"
 
 #: frappe/core/doctype/data_export/exporter.py:22
 msgid "Start entering data below this line"
diff --git a/frappe/locale/fa.po b/frappe/locale/fa.po
index da9f2f8d06dc..d6db686d6f68 100644
--- a/frappe/locale/fa.po
+++ b/frappe/locale/fa.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: frappe\n"
 "Report-Msgid-Bugs-To: developers@frappe.io\n"
 "POT-Creation-Date: 2024-12-01 17:58+0000\n"
-"PO-Revision-Date: 2024-12-04 19:52\n"
+"PO-Revision-Date: 2024-12-11 20:01\n"
 "Last-Translator: developers@frappe.io\n"
 "Language-Team: Persian\n"
 "MIME-Version: 1.0\n"
@@ -3562,7 +3562,7 @@ msgstr "ساخته شده در {0}"
 #. Label of a Check field in DocType 'User'
 #: frappe/core/doctype/user/user.json
 msgid "Bulk Actions"
-msgstr "اعمال توده"
+msgstr "اعمال انبوه"
 
 #: frappe/core/doctype/user_permission/user_permission_list.js:142
 msgid "Bulk Delete"
@@ -12795,7 +12795,7 @@ msgstr "قالب CSV نامعتبر است"
 
 #: frappe/integrations/frappe_providers/frappecloud_billing.py:121
 msgid "Invalid Code. Please try again."
-msgstr ""
+msgstr "کد نامعتبر. لطفا دوباره امتحان کنید."
 
 #: frappe/integrations/doctype/webhook/webhook.py:90
 msgid "Invalid Condition: {}"
@@ -14841,7 +14841,7 @@ msgstr ""
 
 #: frappe/public/js/frappe/data_import/import_preview.js:290
 msgid "Map columns from {0} to fields in {1}"
-msgstr "ستون‌های نقشه از {0} تا فیلدها در {1}"
+msgstr "نگاشت ستون‌ها از {0} به فیلدها در {1}"
 
 #. Description of the 'Dynamic Route' (Check) field in DocType 'Web Page'
 #: frappe/website/doctype/web_page/web_page.json
@@ -15666,7 +15666,7 @@ msgstr "فیلد ضرب"
 #. Import'
 #: frappe/core/doctype/data_import/data_import.json
 msgid "Must be a publicly accessible Google Sheets URL"
-msgstr "باید یک URL برای عموم کاربرگ‌نگار باشد"
+msgstr "باید یک URL کاربرگ‌نگار در دسترس عموم باشد"
 
 #. Description of the 'LDAP Search String' (Data) field in DocType 'LDAP
 #. Settings'
@@ -24497,7 +24497,7 @@ msgstr ""
 
 #: frappe/core/doctype/data_import/data_import.js:151
 msgid "Successfully {0} {1} records."
-msgstr ""
+msgstr "{1} رکورد با موفقیت {0} شد."
 
 #: frappe/core/doctype/recorder/recorder.js:15
 msgid "Suggest Optimizations"
@@ -29133,7 +29133,7 @@ msgstr "برای ارسال این فرم باید وارد شوید"
 
 #: frappe/model/document.py:238
 msgid "You need the '{0}' permission on {1} {2} to perform this action."
-msgstr ""
+msgstr "برای انجام این عمل به مجوز \"{0}\" در {1} {2} نیاز دارید."
 
 #: frappe/desk/doctype/workspace/workspace.py:113
 msgid "You need to be Workspace Manager to delete a public workspace."
@@ -29185,11 +29185,11 @@ msgstr "باید یک پوشه IMAP برای {0} تنظیم کنید"
 
 #: frappe/model/rename_doc.py:388
 msgid "You need write permission on {0} {1} to merge"
-msgstr ""
+msgstr "برای ادغام به اجازه نوشتن در {0} {1} نیاز دارید"
 
 #: frappe/model/rename_doc.py:383
 msgid "You need write permission on {0} {1} to rename"
-msgstr ""
+msgstr "برای تغییر نام به اجازه نوشتن در {0} {1} نیاز دارید"
 
 #: frappe/client.py:458
 msgid "You need {0} permission to fetch values from {1} {2}"
diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po
index b9c3c0f39ef9..6bf870a47933 100644
--- a/frappe/locale/sv.po
+++ b/frappe/locale/sv.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: frappe\n"
 "Report-Msgid-Bugs-To: developers@frappe.io\n"
 "POT-Creation-Date: 2024-12-01 17:58+0000\n"
-"PO-Revision-Date: 2024-12-04 19:52\n"
+"PO-Revision-Date: 2024-12-09 20:00\n"
 "Last-Translator: developers@frappe.io\n"
 "Language-Team: Swedish\n"
 "MIME-Version: 1.0\n"
@@ -4418,12 +4418,12 @@ msgstr "Kedjehash"
 #: frappe/public/js/frappe/form/templates/form_sidebar.html:11
 #: frappe/tests/test_translate.py:98
 msgid "Change"
-msgstr "Växel"
+msgstr "Ändra"
 
 #: frappe/tests/test_translate.py:99
 msgctxt "Coins"
 msgid "Change"
-msgstr "Växel"
+msgstr "Ändra"
 
 #: frappe/public/js/print_format_builder/LetterHeadEditor.vue:38
 msgid "Change Image"
@@ -8741,7 +8741,7 @@ msgstr "E-post "
 
 #: frappe/email/queue.py:137
 msgid "Emails are muted"
-msgstr "E-post är Dämpad"
+msgstr "E-post är dämpad"
 
 #. Description of the 'Send Email Alert' (Check) field in DocType 'Workflow'
 #: frappe/workflow/doctype/workflow/workflow.json
@@ -11017,7 +11017,7 @@ msgstr "Hämta Fält"
 
 #: frappe/printing/doctype/letter_head/letter_head.js:32
 msgid "Get Header and Footer wkhtmltopdf variables"
-msgstr "Hämta wkhtmltopdf variabler för sidhuvud och sidfot"
+msgstr "Hämta Sidhuvud och Sidfot wkhtmltopdf variabler"
 
 #: frappe/public/js/frappe/form/multi_select_dialog.js:87
 msgid "Get Items"
@@ -11572,7 +11572,7 @@ msgstr "Sidhuvud, Robotar"
 
 #: frappe/printing/doctype/letter_head/letter_head.js:30
 msgid "Header/Footer scripts can be used to add dynamic behaviours."
-msgstr "Skript för Brevhuvud/Sidfot kan användas för att lägga till dynamisk beteende."
+msgstr "Skript för Sidhuvud/Sidfot kan användas för att lägga till dynamisk beteende."
 
 #. Label of a Table field in DocType 'Webhook'
 #. Label of a Code field in DocType 'Webhook Request Log'
@@ -24775,7 +24775,7 @@ msgstr "Ändra Tema"
 
 #: frappe/templates/includes/navbar/navbar_login.html:17
 msgid "Switch To Desk"
-msgstr "Ändra till Skrivbord"
+msgstr "Växla till Skrivbord"
 
 #: frappe/public/js/frappe/ui/capture.js:273
 msgid "Switching Camera"
@@ -31359,7 +31359,7 @@ msgstr "{0} är inte Direkt Utskrift Mall."
 
 #: frappe/public/js/frappe/views/calendar/calendar.js:82
 msgid "{0} is not a valid Calendar. Redirecting to default Calendar."
-msgstr "{0} är inte en giltig kalender. Omdirigerar till standardkalendern."
+msgstr "{0} är inte giltig Kalender. Omdirigerar till standard Kalender."
 
 #: frappe/core/doctype/scheduled_job_type/scheduled_job_type.py:65
 msgid "{0} is not a valid Cron expression."
diff --git a/frappe/locale/tr.po b/frappe/locale/tr.po
index 7d10d819718b..1453c06bcd4f 100644
--- a/frappe/locale/tr.po
+++ b/frappe/locale/tr.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: frappe\n"
 "Report-Msgid-Bugs-To: developers@frappe.io\n"
 "POT-Creation-Date: 2024-12-01 17:58+0000\n"
-"PO-Revision-Date: 2024-12-05 19:58\n"
+"PO-Revision-Date: 2024-12-10 20:05\n"
 "Last-Translator: developers@frappe.io\n"
 "Language-Team: Turkish\n"
 "MIME-Version: 1.0\n"
@@ -23337,7 +23337,7 @@ msgstr "Paylaş"
 
 #: frappe/public/js/frappe/form/templates/set_sharing.html:49
 msgid "Share this document with"
-msgstr "Dökümanı Şu Kişiyle Paylaş"
+msgstr "Dökümanı Paylaş"
 
 #: frappe/public/js/frappe/form/sidebar/share.js:45
 msgid "Share {0} with"

From b50b8707a1a299be8b26bc9cfb66a8cafbc18af2 Mon Sep 17 00:00:00 2001
From: UmakanthKaspa <kaspaumakanth1999@gmail.com>
Date: Wed, 4 Dec 2024 06:16:01 +0000
Subject: [PATCH 05/15] fix: exclude 'no copy' fields when duplicating child
 table rows

(cherry picked from commit 3934f119f94c2a68697f63d81a57c5a1b806a3b7)
---
 frappe/public/js/frappe/form/grid.js | 31 ++++++++++++++++------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js
index 75e6f8d671f9..82e5d667d214 100644
--- a/frappe/public/js/frappe/form/grid.js
+++ b/frappe/public/js/frappe/form/grid.js
@@ -881,20 +881,25 @@ export default class Grid {
 	}
 
 	duplicate_row(d, copy_doc) {
+		const noCopyFields = new Set([
+			"creation",
+			"modified",
+			"modified_by",
+			"idx",
+			"owner",
+			"parent",
+			"doctype",
+			"name",
+			"parentfield",
+		]);
+
+		const docfields = frappe.get_meta(this.doctype).fields || [];
+		$.each(docfields, function (_index, df) {
+			if (cint(df.no_copy)) noCopyFields.add(df.fieldname);
+		});
+
 		$.each(copy_doc, function (key, value) {
-			if (
-				![
-					"creation",
-					"modified",
-					"modified_by",
-					"idx",
-					"owner",
-					"parent",
-					"doctype",
-					"name",
-					"parentfield",
-				].includes(key)
-			) {
+			if (!noCopyFields.has(key)) {
 				d[key] = value;
 			}
 		});

From 106186f360a3fea0b14bf6845ef7e4454c2b372c Mon Sep 17 00:00:00 2001
From: Ankush Menat <ankush@frappe.io>
Date: Mon, 16 Dec 2024 13:52:44 +0530
Subject: [PATCH 06/15] ci: Don't specify client version

Clients work on mysql protocol ABI which works for huge ranges of
servers.

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
---
 .github/helper/install_dependencies.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/helper/install_dependencies.sh b/.github/helper/install_dependencies.sh
index f382b61dda88..930006113f2d 100644
--- a/.github/helper/install_dependencies.sh
+++ b/.github/helper/install_dependencies.sh
@@ -6,7 +6,7 @@ echo "Setting Up System Dependencies..."
 echo "::group::apt packages"
 sudo apt update
 sudo apt remove mysql-server mysql-client
-sudo apt install libcups2-dev redis-server mariadb-client-10.6
+sudo apt install libcups2-dev redis-server mariadb-client
 
 install_wkhtmltopdf() {
   wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb

From f7a5e54650a34c5a29245e5cb4ddd0a40bef9184 Mon Sep 17 00:00:00 2001
From: Akhil Narang <me@akhilnarang.dev>
Date: Mon, 16 Dec 2024 16:42:03 +0530
Subject: [PATCH 07/15] chore(ci): bump wkhtmltox from focal to jammy

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
---
 .github/helper/install_dependencies.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/helper/install_dependencies.sh b/.github/helper/install_dependencies.sh
index 930006113f2d..ac8015a88dc7 100644
--- a/.github/helper/install_dependencies.sh
+++ b/.github/helper/install_dependencies.sh
@@ -9,8 +9,8 @@ sudo apt remove mysql-server mysql-client
 sudo apt install libcups2-dev redis-server mariadb-client
 
 install_wkhtmltopdf() {
-  wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
-  sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb
+  wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb
+  sudo apt install ./wkhtmltox_0.12.6.1-2.jammy_amd64.deb
 }
 install_wkhtmltopdf &
 echo "::endgroup::"

From 08b9b8dd892338fbcaf721bc44b6bd6b2d480e80 Mon Sep 17 00:00:00 2001
From: Akhil Narang <me@akhilnarang.dev>
Date: Fri, 13 Dec 2024 11:08:48 +0530
Subject: [PATCH 08/15] fix: convert frappe.boot to JSON properly

We have `frappe.as_json` set as the jinja filter for json

(cherry picked from commit 4509e75179889024e08eb6b013064cfc6040b195)
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
---
 frappe/templates/base.html                              | 2 +-
 frappe/website/doctype/web_form/templates/web_form.html | 2 +-
 frappe/website/doctype/web_form/templates/web_list.html | 2 +-
 frappe/www/app.html                                     | 2 +-
 frappe/www/app.py                                       | 3 +--
 5 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/frappe/templates/base.html b/frappe/templates/base.html
index 2c992c082f39..e547e2665787 100644
--- a/frappe/templates/base.html
+++ b/frappe/templates/base.html
@@ -91,7 +91,7 @@
 	{% block base_scripts %}
 	<!-- js should be loaded in body! -->
 	<script>
-		frappe.boot = {{ boot }}
+		frappe.boot = {{ boot | json }}
 		// for backward compatibility of some libs
 		frappe.sys_defaults = frappe.boot.sysdefaults;
 	</script>
diff --git a/frappe/website/doctype/web_form/templates/web_form.html b/frappe/website/doctype/web_form/templates/web_form.html
index f852ec2c4235..f58bec0c31aa 100644
--- a/frappe/website/doctype/web_form/templates/web_form.html
+++ b/frappe/website/doctype/web_form/templates/web_form.html
@@ -160,7 +160,7 @@ <h2 class="success-title">{{ _(success_title) or _("Submitted") }}</h2>
 
 {% block script %}
 	<script>
-		frappe.boot = {{ boot }};
+		frappe.boot = {{ boot | json }};
 		frappe._messages = {{ translated_messages }};
 		frappe.web_form_doc = {{ web_form_doc | json }};
 		frappe.reference_doc = {{ reference_doc | json }};
diff --git a/frappe/website/doctype/web_form/templates/web_list.html b/frappe/website/doctype/web_form/templates/web_list.html
index e9505605f6eb..807353a54a8d 100644
--- a/frappe/website/doctype/web_form/templates/web_list.html
+++ b/frappe/website/doctype/web_form/templates/web_list.html
@@ -24,7 +24,7 @@ <h1 class="ellipsis">{{ _(list_title or title) }}</h1>
 
 {% block script %}
 	<script>
-		frappe.boot = {{ boot }};
+		frappe.boot = {{ boot | json }};
 		frappe._messages = {{ translated_messages }};
 		frappe.web_form_doc = {{ web_form_doc | json }};
 	</script>
diff --git a/frappe/www/app.html b/frappe/www/app.html
index a2fef3362ddb..fd13f130760d 100644
--- a/frappe/www/app.html
+++ b/frappe/www/app.html
@@ -51,7 +51,7 @@
 
 			if (!window.frappe) window.frappe = {};
 
-			frappe.boot = JSON.parse({{ boot }});
+			frappe.boot = {{ boot | json }};
 			frappe._messages = frappe.boot["__messages"];
 			frappe.csrf_token = "{{ csrf_token }}";
 
diff --git a/frappe/www/app.py b/frappe/www/app.py
index 93ecb2a8c63d..45c011659f81 100644
--- a/frappe/www/app.py
+++ b/frappe/www/app.py
@@ -43,7 +43,6 @@ def get_context(context):
 
 	# TODO: Find better fix
 	boot_json = CLOSING_SCRIPT_TAG_PATTERN.sub("", boot_json)
-	boot_json = json.dumps(boot_json)
 
 	include_js = hooks.get("app_include_js", []) + frappe.conf.get("app_include_js", [])
 	include_css = hooks.get("app_include_css", []) + frappe.conf.get("app_include_css", [])
@@ -63,7 +62,7 @@ def get_context(context):
 			"layout_direction": "rtl" if is_rtl() else "ltr",
 			"lang": frappe.local.lang,
 			"sounds": hooks["sounds"],
-			"boot": boot if context.get("for_mobile") else boot_json,
+			"boot": boot if context.get("for_mobile") else json.loads(boot_json),
 			"desk_theme": boot.get("desk_theme") or "Light",
 			"csrf_token": csrf_token,
 			"google_analytics_id": frappe.conf.get("google_analytics_id"),

From be5aa7723b772f9664d80e22c5dcb84fea60710f Mon Sep 17 00:00:00 2001
From: Akhil Narang <me@akhilnarang.dev>
Date: Mon, 16 Dec 2024 16:00:10 +0530
Subject: [PATCH 09/15] fix(package): validate package name, export path

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
(cherry picked from commit fae07e4bbbb35eef4b9e54319755a654674e9b23)
---
 frappe/core/doctype/package/package.py                |  5 +++++
 .../core/doctype/package_release/package_release.py   | 11 ++++++++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/frappe/core/doctype/package/package.py b/frappe/core/doctype/package/package.py
index ddf6e92e793f..69879ca94216 100644
--- a/frappe/core/doctype/package/package.py
+++ b/frappe/core/doctype/package/package.py
@@ -2,6 +2,7 @@
 # For license information, please see license.txt
 
 import os
+from string import ascii_letters, digits
 
 import frappe
 from frappe.model.document import Document
@@ -34,6 +35,10 @@ def validate(self):
 		if not self.package_name:
 			self.package_name = self.name.lower().replace(" ", "-")
 
+		allowed_characters = ascii_letters + digits + "-"
+		if not all(c in allowed_characters for c in self.package_name):
+			frappe.throw("Package name can only contain letters, digits and hyphens")
+
 
 @frappe.whitelist()
 def get_license_text(license_type: str) -> str | None:
diff --git a/frappe/core/doctype/package_release/package_release.py b/frappe/core/doctype/package_release/package_release.py
index 807872e69ce6..8425ffedf2fd 100644
--- a/frappe/core/doctype/package_release/package_release.py
+++ b/frappe/core/doctype/package_release/package_release.py
@@ -3,6 +3,7 @@
 
 import os
 import subprocess
+from pathlib import Path
 
 import frappe
 from frappe.model.document import Document
@@ -65,12 +66,16 @@ def autoname(self):
 		)
 
 	def validate(self):
+		package = frappe.get_doc("Package", self.package)
+		package_path = Path(frappe.get_site_path("packages", package.package_name))
+		if not package_path.resolve().is_relative_to(Path(frappe.get_site_path()).resolve()):
+			frappe.throw("Invalid package path: " + package_path.as_posix())
+
 		if self.publish:
-			self.export_files()
+			self.export_files(package)
 
-	def export_files(self):
+	def export_files(self, package):
 		"""Export all the documents in this package to site/packages folder"""
-		package = frappe.get_doc("Package", self.package)
 
 		self.export_modules()
 		self.export_package_files(package)

From e7c4e017231f08b41e0f4a52cbe9d771053df057 Mon Sep 17 00:00:00 2001
From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com>
Date: Tue, 17 Dec 2024 06:21:54 +0000
Subject: [PATCH 10/15] perf: Avoid patching QB in every request (backport
 #28799) (#28801)

* perf: Avoid patching QB in every request

(cherry picked from commit 5bf50b6bc298d7df997850b1f56aa516eb4b2095)

# Conflicts:
#	frappe/__init__.py

* chore: conflicts

---------

Co-authored-by: Ankush Menat <ankush@frappe.io>
---
 frappe/__init__.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/frappe/__init__.py b/frappe/__init__.py
index a012952638ae..59ba5970e211 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -88,7 +88,7 @@
 cache = None
 STANDARD_USERS = ("Guest", "Administrator")
 
-_qb_patched = {}
+_one_time_setup = {}
 _dev_server = int(sbool(os.environ.get("DEV_SERVER", False)))
 _tune_gc = bool(sbool(os.environ.get("FRAPPE_TUNE_GC", True)))
 
@@ -249,10 +249,11 @@ def init(site: str, sites_path: str = ".", new_site: bool = False, force=False)
 	local.qb.get_query = get_query
 	setup_redis_cache_connection()
 
-	if not _qb_patched.get(local.conf.db_type):
+	if not _one_time_setup.get(local.conf.db_type):
 		patch_query_execute()
 		patch_query_aggregation()
 		_register_fault_handler()
+		_one_time_setup[local.conf.db_type] = True
 
 	setup_module_map(include_all_apps=not (frappe.request or frappe.job or frappe.flags.in_migrate))
 

From 3118e45fed7f1dbb0e84aec1e68e951fa72a165d Mon Sep 17 00:00:00 2001
From: Akhil Narang <me@akhilnarang.dev>
Date: Tue, 17 Dec 2024 16:04:05 +0530
Subject: [PATCH 11/15] fix(email): don't try to parse flags that seem to be
 invalid

Sometimes we get invalid flags from `imap.uid()`, like `[b'System Error (Failure)']`

This leads to the flag getting parsed as 83 (`ord('S')`)

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
(cherry picked from commit d285dd5cbf48fb5dd742c5551f9e5f99841a2a02)
---
 frappe/email/receive.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/frappe/email/receive.py b/frappe/email/receive.py
index 4cb5c654c5da..9bdfe28940ef 100644
--- a/frappe/email/receive.py
+++ b/frappe/email/receive.py
@@ -280,7 +280,7 @@ def retrieve_message(self, uid, msg_num):
 
 	def get_email_seen_status(self, uid, flag_string):
 		"""parse the email FLAGS response"""
-		if not flag_string:
+		if not flag_string or not isinstance(flag_string, str | bytes):
 			return None
 
 		flags = []

From 11a4a777c3ec594c23ede9b3cd7b2c3b5487060a Mon Sep 17 00:00:00 2001
From: RitvikSardana <ritvik.sardana11@gmail.com>
Date: Tue, 17 Dec 2024 13:06:21 +0530
Subject: [PATCH 12/15] fix: add support for CSV files for non desk users

(cherry picked from commit 15f64fa7bc081e92ae7fca31de385df0ebb9d4a7)
---
 frappe/handler.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/frappe/handler.py b/frappe/handler.py
index 39dd15c9cb7f..e51896be9751 100644
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -36,6 +36,7 @@
 	"text/plain",
 	"video/quicktime",
 	"video/mp4",
+	"text/csv",
 )
 
 

From 3a5919db786ef8a87ca3a61267e669e31035a48d Mon Sep 17 00:00:00 2001
From: RitvikSardana <ritvik.sardana11@gmail.com>
Date: Tue, 17 Dec 2024 13:10:27 +0530
Subject: [PATCH 13/15] fix: change error message

(cherry picked from commit f6637d7ef07c98010a555e7b2270fdadaf6cb72a)
---
 frappe/handler.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/frappe/handler.py b/frappe/handler.py
index e51896be9751..e1263e26ed8a 100644
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -36,7 +36,6 @@
 	"text/plain",
 	"video/quicktime",
 	"video/mp4",
-	"text/csv",
 )
 
 
@@ -227,7 +226,7 @@ def upload_file():
 	if content is not None and (frappe.session.user == "Guest" or (user and not user.has_desk_access())):
 		filetype = guess_type(filename)[0]
 		if filetype not in ALLOWED_MIMETYPES:
-			frappe.throw(_("You can only upload JPG, PNG, PDF, TXT or Microsoft documents."))
+			frappe.throw(_("You can only upload JPG, PNG, PDF, TXT, CSV or Microsoft documents."))
 
 	if method:
 		method = frappe.get_attr(method)

From e74be96573f55bd9e606666438ee01cda1c7533c Mon Sep 17 00:00:00 2001
From: RitvikSardana <ritvik.sardana11@gmail.com>
Date: Tue, 17 Dec 2024 13:11:57 +0530
Subject: [PATCH 14/15] chore: code cleanup

(cherry picked from commit 6e524ada8f1b4bea8694fcb82494cdcc15894a99)
---
 frappe/handler.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/frappe/handler.py b/frappe/handler.py
index e1263e26ed8a..6f1a13676d4f 100644
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -36,6 +36,7 @@
 	"text/plain",
 	"video/quicktime",
 	"video/mp4",
+	"text/csv",
 )
 
 

From 93ee9cac58a4d3c5e6f715ab8f56470a9e4e3742 Mon Sep 17 00:00:00 2001
From: Frappe PR Bot <developers@frappe.io>
Date: Wed, 18 Dec 2024 05:05:56 +0000
Subject: [PATCH 15/15] chore(release): Bumped to Version 15.50.1

## [15.50.1](https://github.com/frappe/frappe/compare/v15.50.0...v15.50.1) (2024-12-18)

### Bug Fixes

* add support for CSV files for non desk users ([11a4a77](https://github.com/frappe/frappe/commit/11a4a777c3ec594c23ede9b3cd7b2c3b5487060a))
* change error message ([3a5919d](https://github.com/frappe/frappe/commit/3a5919db786ef8a87ca3a61267e669e31035a48d))
* clarify error message for child tables ([efa09f4](https://github.com/frappe/frappe/commit/efa09f4a7340a1d3251c8b2a72786beb1c12b30e))
* convert frappe.boot to JSON properly ([08b9b8d](https://github.com/frappe/frappe/commit/08b9b8dd892338fbcaf721bc44b6bd6b2d480e80))
* **email:** don't try to parse flags that seem to be invalid ([3118e45](https://github.com/frappe/frappe/commit/3118e45fed7f1dbb0e84aec1e68e951fa72a165d))
* exclude 'no copy' fields when duplicating child table rows ([b50b870](https://github.com/frappe/frappe/commit/b50b8707a1a299be8b26bc9cfb66a8cafbc18af2))
* **package:** validate package name, export path ([be5aa77](https://github.com/frappe/frappe/commit/be5aa7723b772f9664d80e22c5dcb84fea60710f))
* set `currency` system setting in webform `frappe.boot.sysdefaults` ([50ec3e8](https://github.com/frappe/frappe/commit/50ec3e8073492f68444e9e52b7252dee0c5baee9))
* sync translations from crowdin ([#28700](https://github.com/frappe/frappe/issues/28700)) ([363fa92](https://github.com/frappe/frappe/commit/363fa92feb59e517653a87533a5b123d0f4ac564))

### Performance Improvements

* Avoid patching QB in every request (backport [#28799](https://github.com/frappe/frappe/issues/28799)) ([#28801](https://github.com/frappe/frappe/issues/28801)) ([e7c4e01](https://github.com/frappe/frappe/commit/e7c4e017231f08b41e0f4a52cbe9d771053df057))
---
 frappe/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/frappe/__init__.py b/frappe/__init__.py
index 78987077693f..5963f8841596 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -51,7 +51,7 @@
 )
 from .utils.lazy_loader import lazy_import
 
-__version__ = "15.50.0"
+__version__ = "15.50.1"
 __title__ = "Frappe Framework"
 
 # This if block is never executed when running the code. It is only used for