diff --git a/diagnose_permissions.py b/diagnose_permissions.py deleted file mode 100644 index b47d6ef..0000000 --- a/diagnose_permissions.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -""" -PlateOrder PATCH 权限诊断脚本 -用于检查用户是否有正确的权限 -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flower.settings') -django.setup() - -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Permission -from printing.models import PlateOrder - -User = get_user_model() - -def diagnose_user_permissions(username): - """诊断用户权限""" - print(f"\n{'='*60}") - print(f"诊断用户: {username}") - print(f"{'='*60}\n") - - try: - user = User.objects.get(username=username) - except User.DoesNotExist: - print(f"❌ 用户 '{username}' 不存在!") - return - - print(f"✅ 用户存在: {user.username} ({user.email})") - print(f" - is_active: {user.is_active}") - print(f" - is_staff: {user.is_staff}") - print(f" - is_superuser: {user.is_superuser}") - - if user.is_superuser: - print("\n✅ 用户是超级管理员,拥有所有权限!") - return - - # 检查 PlateOrder 相关权限 - required_perms = [ - 'printing.view_plateorder', - 'printing.add_plateorder', - 'printing.change_plateorder', # ⚠️ PATCH 需要这个 - 'printing.delete_plateorder', - ] - - print("\n📋 PlateOrder 权限检查:") - print("-" * 60) - - for perm in required_perms: - has_perm = user.has_perm(perm) - icon = "✅" if has_perm else "❌" - action = perm.split('.')[1].replace('_', ' ').title() - print(f"{icon} {action:30} ({perm})") - - if perm == 'printing.change_plateorder' and not has_perm: - print(" ⚠️ 缺少此权限会导致 PATCH/PUT 请求返回 401/403!") - - # 检查用户所属组 - groups = user.groups.all() - if groups.exists(): - print(f"\n👥 用户所属组: {', '.join(g.name for g in groups)}") - for group in groups: - print(f"\n 组 '{group.name}' 的权限:") - group_perms = group.permissions.filter( - content_type__app_label='printing', - content_type__model='plateorder' - ) - for perm in group_perms: - print(f" - {perm.codename}") - else: - print("\n👥 用户不属于任何组") - - # 检查直接授予的权限 - direct_perms = user.user_permissions.filter( - content_type__app_label='printing', - content_type__model='plateorder' - ) - if direct_perms.exists(): - print(f"\n🔑 直接授予的权限:") - for perm in direct_perms: - print(f" - {perm.codename}") - else: - print("\n🔑 没有直接授予的权限") - - print("\n" + "="*60) - - # 提供修复建议 - if not user.has_perm('printing.change_plateorder'): - print("\n💡 修复方法:") - print("-" * 60) - print("在 Django shell 中运行以下代码:") - print(f""" -from django.contrib.auth import get_user_model -from django.contrib.auth.models import Permission - -User = get_user_model() -user = User.objects.get(username='{username}') -change_perm = Permission.objects.get(codename='change_plateorder') -user.user_permissions.add(change_perm) -print("✅ 权限已添加!") -""") - - -def list_all_users(): - """列出所有用户""" - users = User.objects.all() - if not users.exists(): - print("❌ 系统中没有用户!") - return - - print(f"\n{'='*60}") - print("系统中的所有用户:") - print(f"{'='*60}\n") - - for user in users: - has_change = user.has_perm('printing.change_plateorder') - icon = "✅" if has_change else "❌" - print(f"{icon} {user.username:20} (is_active: {user.is_active}, has_change_plateorder: {has_change})") - - -if __name__ == '__main__': - import sys - - if len(sys.argv) > 1: - username = sys.argv[1] - diagnose_user_permissions(username) - else: - list_all_users() - print("\n💡 使用方法: python diagnose_permissions.py ") - diff --git a/CHANGELOG_process_nodes.md b/docs/CHANGELOG_process_nodes.md similarity index 100% rename from CHANGELOG_process_nodes.md rename to docs/CHANGELOG_process_nodes.md diff --git a/REFACTOR_CURRENT_STATE_2025-11-19.md b/docs/REFACTOR_CURRENT_STATE_2025-11-19.md similarity index 100% rename from REFACTOR_CURRENT_STATE_2025-11-19.md rename to docs/REFACTOR_CURRENT_STATE_2025-11-19.md diff --git a/REFACTOR_REMOVE_NOT_STARTED_2025-11-19.md b/docs/REFACTOR_REMOVE_NOT_STARTED_2025-11-19.md similarity index 100% rename from REFACTOR_REMOVE_NOT_STARTED_2025-11-19.md rename to docs/REFACTOR_REMOVE_NOT_STARTED_2025-11-19.md diff --git a/api_backend.md b/docs/api_backend.md similarity index 100% rename from api_backend.md rename to docs/api_backend.md diff --git a/bug-fix-20251122-stateflow.md b/docs/bug-fix-20251122-stateflow.md similarity index 100% rename from bug-fix-20251122-stateflow.md rename to docs/bug-fix-20251122-stateflow.md diff --git a/printing_job_workflow_api.yml b/docs/printing_job_workflow_api.yml similarity index 100% rename from printing_job_workflow_api.yml rename to docs/printing_job_workflow_api.yml diff --git a/开版管理字段.md b/docs/开版管理字段.md similarity index 100% rename from 开版管理字段.md rename to docs/开版管理字段.md diff --git a/uv.lock b/uv.lock index 38ec459..014de76 100644 --- a/uv.lock +++ b/uv.lock @@ -23,6 +23,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + [[package]] name = "asgiref" version = "3.10.0" @@ -339,12 +352,14 @@ dependencies = [ { name = "drf-spectacular" }, { name = "markdown" }, { name = "pillow" }, + { name = "psycopg", extra = ["binary"] }, + { name = "redis" }, { name = "uvicorn" }, + { name = "watchfiles" }, ] [package.dev-dependencies] dev = [ - { name = "psycopg", extra = ["binary"] }, { name = "pytest" }, ] @@ -364,14 +379,14 @@ requires-dist = [ { name = "drf-spectacular", specifier = ">=0.29.0" }, { name = "markdown", specifier = ">=3.10" }, { name = "pillow", specifier = ">=12.0.0" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.2.12" }, + { name = "redis", specifier = ">=5.0.0" }, { name = "uvicorn", specifier = ">=0.38.0" }, + { name = "watchfiles", specifier = ">=0.22.0" }, ] [package.metadata.requires-dev] -dev = [ - { name = "psycopg", extras = ["binary"], specifier = ">=3.2.12" }, - { name = "pytest", specifier = ">=9.0.1" }, -] +dev = [{ name = "pytest", specifier = ">=9.0.1" }] [[package]] name = "h11" @@ -685,6 +700,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/1d/bd3703fe3c1c2efc1eff9314a9d2f5dd276ecb78d303634942756e231b0c/qiniu-7.17.0-py3-none-any.whl", hash = "sha256:3cd3d25ba1fb9abd2eefb98d5669873d7199e9d84decb25ff5db7968a08a9fb9", size = 81769, upload-time = "2025-07-11T07:32:41.665Z" }, ] +[[package]] +name = "redis" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/c8/983d5c6579a411d8a99bc5823cc5712768859b5ce2c8afe1a65b37832c81/redis-7.1.0.tar.gz", hash = "sha256:b1cc3cfa5a2cb9c2ab3ba700864fb0ad75617b41f01352ce5779dabf6d5f9c3c", size = 4796669, upload-time = "2025-11-19T15:54:39.961Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/f0/8956f8a86b20d7bb9d6ac0187cf4cd54d8065bc9a1a09eb8011d4d326596/redis-7.1.0-py3-none-any.whl", hash = "sha256:23c52b208f92b56103e17c5d06bdc1a6c2c0b3106583985a76a18f83b265de2b", size = 354159, upload-time = "2025-11-19T15:54:38.064Z" }, +] + [[package]] name = "referencing" version = "0.37.0" @@ -759,6 +783,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + [[package]] name = "sqlparse" version = "0.5.3" @@ -838,6 +871,40 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc", size = 9636, upload-time = "2023-11-05T08:46:51.205Z" }, ] +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, + { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, + { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, + { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, + { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, + { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, +] + [[package]] name = "wcwidth" version = "0.2.14" diff --git a/verify_file_upload_fix.sh b/verify_file_upload_fix.sh deleted file mode 100755 index 9803bba..0000000 --- a/verify_file_upload_fix.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# PlateOrder 文件上传修复验证脚本 - -echo "================================================" -echo "PlateOrder 文件上传功能验证" -echo "================================================" -echo "" - -echo "1️⃣ 运行文件上传测试..." -python manage.py test api_v1.views.printing.test_plate_order_file_upload --keepdb -v 1 - -echo "" -echo "2️⃣ 运行完整的 PlateOrder API 测试..." -python manage.py test api_v1.views.printing.test_plate_order_api --keepdb -v 1 - -echo "" -echo "================================================" -echo "✅ 如果所有测试通过,说明修复成功!" -echo "================================================" -echo "" -echo "📝 修复内容:" -echo " - 添加了 MultiPartParser, FormParser, JSONParser" -echo " - PlateOrderViewSet 现在支持文件上传" -echo " - 支持 multipart/form-data 和 application/json" -echo "" -echo "📖 详细文档:" -echo " - docs/FIX_FILE_UPLOAD_401.md" -echo " - docs/TROUBLESHOOT_401_PATCH.md" -echo "" -