admin key can read all images + fix env var for cloud function
This commit is contained in:
parent
f80505bd74
commit
348bcf93a7
1
deployment/terraform/.terraform.tfstate.lock.info
Normal file
1
deployment/terraform/.terraform.tfstate.lock.info
Normal file
@ -0,0 +1 @@
|
||||
{"ID":"9b771a70-f4b7-dbb4-f919-38d27ca55e23","Operation":"OperationTypeApply","Info":"","Who":"DESKTOP\\habal@Desktop","Version":"1.10.1","Created":"2025-05-24T22:38:22.6064375Z","Path":"terraform.tfstate"}
|
||||
@ -66,6 +66,8 @@ resource "google_cloudfunctions2_function" "image_processor" {
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL = "INFO"
|
||||
|
||||
PROJECT_ID = var.project_id
|
||||
}
|
||||
|
||||
service_account_email = local.cloud_function_service_account
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 4,
|
||||
"terraform_version": "1.10.1",
|
||||
"serial": 410,
|
||||
"serial": 415,
|
||||
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||
"outputs": {
|
||||
"cloud_function_name": {
|
||||
@ -98,16 +98,16 @@
|
||||
"attributes": {
|
||||
"exclude_symlink_directories": null,
|
||||
"excludes": null,
|
||||
"id": "7a7a706b5bba3a12744f2dd109eb18de7112f351",
|
||||
"output_base64sha256": "0wAfDV7tH41jEspQ3LBLvIEnrQ6XU2aEtK2GWsMdyCA=",
|
||||
"output_base64sha512": "glsNAiHzSTOy9mGDckkSyDJhBVFDtLh8Xr6+hSxtCT8nok9qNGO+61iTRLU42OPxaPS/BrbDAXJeT86F3riefA==",
|
||||
"id": "bfc4b3b9de401cd15676a09a067a8e4095b0bf4e",
|
||||
"output_base64sha256": "cXx9sC1kIbTDG7BlKAtf3FUasHLZ/wZPzVoyBvt8p9Q=",
|
||||
"output_base64sha512": "dcntRZ4Hz4dfBBj7YVsTzx+SEAqCXZCD8TAAh8cr5xa3uT2Lsmtf8zpxpyQEeMlsCNaF8dUohGQ7BD9LJYigPw==",
|
||||
"output_file_mode": null,
|
||||
"output_md5": "a5d3a7fe131c972bf8d0edf309545042",
|
||||
"output_md5": "46efa1aee5386e2f244b597289c7c4ba",
|
||||
"output_path": "./function-source.zip",
|
||||
"output_sha": "7a7a706b5bba3a12744f2dd109eb18de7112f351",
|
||||
"output_sha256": "d3001f0d5eed1f8d6312ca50dcb04bbc8127ad0e97536684b4ad865ac31dc820",
|
||||
"output_sha512": "825b0d0221f34933b2f66183724912c83261055143b4b87c5ebebe852c6d093f27a24f6a3463beeb589344b538d8e3f168f4bf06b6c301725e4fce85deb89e7c",
|
||||
"output_size": 4487,
|
||||
"output_sha": "bfc4b3b9de401cd15676a09a067a8e4095b0bf4e",
|
||||
"output_sha256": "717c7db02d6421b4c31bb065280b5fdc551ab072d9ff064fcd5a3206fb7ca7d4",
|
||||
"output_sha512": "75c9ed459e07cf875f0418fb615b13cf1f92100a825d9083f1300087c72be716b7b93d8bb26b5ff33a71a7240478c96c08d685f1d52884643b043f4b2588a03f",
|
||||
"output_size": 6734,
|
||||
"source": [],
|
||||
"source_content": null,
|
||||
"source_content_filename": null,
|
||||
@ -182,7 +182,7 @@
|
||||
"goog-terraform-provisioned": "true"
|
||||
},
|
||||
"generation": 1,
|
||||
"labels": null,
|
||||
"labels": {},
|
||||
"namespace": "gen-lang-client-0424120530",
|
||||
"resource_version": "AAY16UbSm4k",
|
||||
"self_link": "/apis/serving.knative.dev/v1/namespaces/761163285547/services/sereact",
|
||||
@ -256,8 +256,8 @@
|
||||
"container_concurrency": 80,
|
||||
"containers": [
|
||||
{
|
||||
"args": null,
|
||||
"command": null,
|
||||
"args": [],
|
||||
"command": [],
|
||||
"env": [
|
||||
{
|
||||
"name": "FIRESTORE_DATABASE_NAME",
|
||||
@ -332,7 +332,7 @@
|
||||
"cpu": "1",
|
||||
"memory": "1Gi"
|
||||
},
|
||||
"requests": null
|
||||
"requests": {}
|
||||
}
|
||||
],
|
||||
"startup_probe": [
|
||||
@ -354,7 +354,7 @@
|
||||
"working_dir": ""
|
||||
}
|
||||
],
|
||||
"node_selector": null,
|
||||
"node_selector": {},
|
||||
"service_account_name": "761163285547-compute@developer.gserviceaccount.com",
|
||||
"serving_state": "",
|
||||
"timeout_seconds": 300,
|
||||
@ -596,6 +596,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "google_compute_address",
|
||||
"name": "vector_db_static_ip",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||
"instances": []
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "google_compute_firewall",
|
||||
@ -822,7 +829,7 @@
|
||||
},
|
||||
{
|
||||
"type": "get_attr",
|
||||
"value": "disk_encryption_key_rsa"
|
||||
"value": "disk_encryption_key_raw"
|
||||
}
|
||||
],
|
||||
[
|
||||
@ -839,7 +846,7 @@
|
||||
},
|
||||
{
|
||||
"type": "get_attr",
|
||||
"value": "disk_encryption_key_raw"
|
||||
"value": "disk_encryption_key_rsa"
|
||||
}
|
||||
]
|
||||
],
|
||||
@ -868,8 +875,8 @@
|
||||
"database_edition": "STANDARD",
|
||||
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
||||
"deletion_policy": "ABANDON",
|
||||
"earliest_version_time": "2025-05-24T21:29:52.924798Z",
|
||||
"etag": "IPHgo4eUvY0DMKrW4vCEvY0D",
|
||||
"earliest_version_time": "2025-05-24T21:38:29.341046Z",
|
||||
"etag": "IOGow/2VvY0DMKrW4vCEvY0D",
|
||||
"id": "projects/gen-lang-client-0424120530/databases/sereact-imagedb",
|
||||
"key_prefix": "",
|
||||
"location_id": "us-central1",
|
||||
@ -989,18 +996,18 @@
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "google_project_iam_member",
|
||||
"name": "function_vision",
|
||||
"name": "function_vertex_ai",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||
"instances": [
|
||||
{
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"condition": [],
|
||||
"etag": "BwY16LCINIE=",
|
||||
"id": "gen-lang-client-0424120530/roles/ml.developer/serviceAccount:761163285547-compute@developer.gserviceaccount.com",
|
||||
"etag": "BwY16WAsDU4=",
|
||||
"id": "gen-lang-client-0424120530/roles/aiplatform.user/serviceAccount:761163285547-compute@developer.gserviceaccount.com",
|
||||
"member": "serviceAccount:761163285547-compute@developer.gserviceaccount.com",
|
||||
"project": "gen-lang-client-0424120530",
|
||||
"role": "roles/ml.developer"
|
||||
"role": "roles/aiplatform.user"
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "bnVsbA==",
|
||||
@ -1016,6 +1023,20 @@
|
||||
"name": "services",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||
"instances": [
|
||||
{
|
||||
"index_key": "aiplatform.googleapis.com",
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"disable_dependent_services": null,
|
||||
"disable_on_destroy": false,
|
||||
"id": "gen-lang-client-0424120530/aiplatform.googleapis.com",
|
||||
"project": "gen-lang-client-0424120530",
|
||||
"service": "aiplatform.googleapis.com",
|
||||
"timeouts": null
|
||||
},
|
||||
"sensitive_attributes": [],
|
||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||
},
|
||||
{
|
||||
"index_key": "cloudbuild.googleapis.com",
|
||||
"schema_version": 0,
|
||||
@ -1493,21 +1514,21 @@
|
||||
"content_encoding": "",
|
||||
"content_language": "",
|
||||
"content_type": "application/zip",
|
||||
"crc32c": "Y4Q5hw==",
|
||||
"crc32c": "kTROsA==",
|
||||
"customer_encryption": [],
|
||||
"detect_md5hash": "pdOn/hMclyv40O3zCVRQQg==",
|
||||
"detect_md5hash": "Ru+hruU4bi8kS1lyicfEug==",
|
||||
"event_based_hold": false,
|
||||
"generation": 1748125796837241,
|
||||
"id": "gen-lang-client-0424120530-cloud-function-source-function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"generation": 1748126317190781,
|
||||
"id": "gen-lang-client-0424120530-cloud-function-source-function-source-46efa1aee5386e2f244b597289c7c4ba.zip",
|
||||
"kms_key_name": "",
|
||||
"md5hash": "pdOn/hMclyv40O3zCVRQQg==",
|
||||
"md5hexhash": "a5d3a7fe131c972bf8d0edf309545042",
|
||||
"media_link": "https://storage.googleapis.com/download/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-a5d3a7fe131c972bf8d0edf309545042.zip?generation=1748125796837241\u0026alt=media",
|
||||
"md5hash": "Ru+hruU4bi8kS1lyicfEug==",
|
||||
"md5hexhash": "46efa1aee5386e2f244b597289c7c4ba",
|
||||
"media_link": "https://storage.googleapis.com/download/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-46efa1aee5386e2f244b597289c7c4ba.zip?generation=1748126317190781\u0026alt=media",
|
||||
"metadata": null,
|
||||
"name": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"output_name": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"name": "function-source-46efa1aee5386e2f244b597289c7c4ba.zip",
|
||||
"output_name": "function-source-46efa1aee5386e2f244b597289c7c4ba.zip",
|
||||
"retention": [],
|
||||
"self_link": "https://www.googleapis.com/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"self_link": "https://www.googleapis.com/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-46efa1aee5386e2f244b597289c7c4ba.zip",
|
||||
"source": "./function-source.zip",
|
||||
"storage_class": "STANDARD",
|
||||
"temporary_hold": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 4,
|
||||
"terraform_version": "1.10.1",
|
||||
"serial": 404,
|
||||
"serial": 410,
|
||||
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||
"outputs": {
|
||||
"cloud_function_name": {
|
||||
@ -98,16 +98,16 @@
|
||||
"attributes": {
|
||||
"exclude_symlink_directories": null,
|
||||
"excludes": null,
|
||||
"id": "045029ac803155784c12f8d587fee56b85b1fbe9",
|
||||
"output_base64sha256": "b/FgNMMT30JSXfrLRXNkWeNc6i22YAmT3YwQRTw1+A4=",
|
||||
"output_base64sha512": "7GDDTkHwwQVAlwSxe7yzgtGccMNIRCQ7t72ZRk7bcfDI1tzpruhJ5G/0AbrUMXWQO6LffnWtwumQ7XdFHAIzBA==",
|
||||
"id": "7a7a706b5bba3a12744f2dd109eb18de7112f351",
|
||||
"output_base64sha256": "0wAfDV7tH41jEspQ3LBLvIEnrQ6XU2aEtK2GWsMdyCA=",
|
||||
"output_base64sha512": "glsNAiHzSTOy9mGDckkSyDJhBVFDtLh8Xr6+hSxtCT8nok9qNGO+61iTRLU42OPxaPS/BrbDAXJeT86F3riefA==",
|
||||
"output_file_mode": null,
|
||||
"output_md5": "34d81725abbd4f423de71ecd4215d116",
|
||||
"output_md5": "a5d3a7fe131c972bf8d0edf309545042",
|
||||
"output_path": "./function-source.zip",
|
||||
"output_sha": "045029ac803155784c12f8d587fee56b85b1fbe9",
|
||||
"output_sha256": "6ff16034c313df42525dfacb45736459e35cea2db6600993dd8c10453c35f80e",
|
||||
"output_sha512": "ec60c34e41f0c105409704b17bbcb382d19c70c34844243bb7bd99464edb71f0c8d6dce9aee849e46ff401bad43175903ba2df7e75adc2e990ed77451c023304",
|
||||
"output_size": 5014,
|
||||
"output_sha": "7a7a706b5bba3a12744f2dd109eb18de7112f351",
|
||||
"output_sha256": "d3001f0d5eed1f8d6312ca50dcb04bbc8127ad0e97536684b4ad865ac31dc820",
|
||||
"output_sha512": "825b0d0221f34933b2f66183724912c83261055143b4b87c5ebebe852c6d093f27a24f6a3463beeb589344b538d8e3f168f4bf06b6c301725e4fce85deb89e7c",
|
||||
"output_size": 4487,
|
||||
"source": [],
|
||||
"source_content": null,
|
||||
"source_content_filename": null,
|
||||
@ -170,11 +170,9 @@
|
||||
"run.googleapis.com/ingress": "all"
|
||||
},
|
||||
"effective_annotations": {
|
||||
"run.googleapis.com/client-name": "gcloud",
|
||||
"run.googleapis.com/client-version": "431.0.0",
|
||||
"run.googleapis.com/ingress": "all",
|
||||
"run.googleapis.com/ingress-status": "all",
|
||||
"run.googleapis.com/operation-id": "e4d7484f-39e4-4dde-8105-28d285eb927b",
|
||||
"run.googleapis.com/operation-id": "7869f742-fe94-42d0-8d82-a1462681980d",
|
||||
"run.googleapis.com/urls": "[\"https://sereact-761163285547.us-central1.run.app\",\"https://sereact-p64zpdtkta-uc.a.run.app\"]",
|
||||
"serving.knative.dev/creator": "johnpccd3@gmail.com",
|
||||
"serving.knative.dev/lastModifier": "johnpccd3@gmail.com"
|
||||
@ -183,15 +181,15 @@
|
||||
"cloud.googleapis.com/location": "us-central1",
|
||||
"goog-terraform-provisioned": "true"
|
||||
},
|
||||
"generation": 2,
|
||||
"labels": {},
|
||||
"generation": 1,
|
||||
"labels": null,
|
||||
"namespace": "gen-lang-client-0424120530",
|
||||
"resource_version": "AAY16Gy+yWQ",
|
||||
"resource_version": "AAY16UbSm4k",
|
||||
"self_link": "/apis/serving.knative.dev/v1/namespaces/761163285547/services/sereact",
|
||||
"terraform_labels": {
|
||||
"goog-terraform-provisioned": "true"
|
||||
},
|
||||
"uid": "c67276c9-0c25-4a6c-8f39-4ea942599769"
|
||||
"uid": "d5532269-ab10-4b77-b90f-698306bf0919"
|
||||
}
|
||||
],
|
||||
"name": "sereact",
|
||||
@ -218,14 +216,14 @@
|
||||
"type": "RoutesReady"
|
||||
}
|
||||
],
|
||||
"latest_created_revision_name": "sereact-00002-cew",
|
||||
"latest_ready_revision_name": "sereact-00002-cew",
|
||||
"observed_generation": 2,
|
||||
"latest_created_revision_name": "sereact-00001-9rv",
|
||||
"latest_ready_revision_name": "sereact-00001-9rv",
|
||||
"observed_generation": 1,
|
||||
"traffic": [
|
||||
{
|
||||
"latest_revision": true,
|
||||
"percent": 100,
|
||||
"revision_name": "sereact-00002-cew",
|
||||
"revision_name": "sereact-00001-9rv",
|
||||
"tag": "",
|
||||
"url": ""
|
||||
}
|
||||
@ -246,7 +244,7 @@
|
||||
"labels": {
|
||||
"run.googleapis.com/startupProbeType": "Default"
|
||||
},
|
||||
"name": "sereact-00002-cew",
|
||||
"name": "",
|
||||
"namespace": "",
|
||||
"resource_version": "",
|
||||
"self_link": "",
|
||||
@ -258,8 +256,8 @@
|
||||
"container_concurrency": 80,
|
||||
"containers": [
|
||||
{
|
||||
"args": [],
|
||||
"command": [],
|
||||
"args": null,
|
||||
"command": null,
|
||||
"env": [
|
||||
{
|
||||
"name": "FIRESTORE_DATABASE_NAME",
|
||||
@ -334,7 +332,7 @@
|
||||
"cpu": "1",
|
||||
"memory": "1Gi"
|
||||
},
|
||||
"requests": {}
|
||||
"requests": null
|
||||
}
|
||||
],
|
||||
"startup_probe": [
|
||||
@ -356,7 +354,7 @@
|
||||
"working_dir": ""
|
||||
}
|
||||
],
|
||||
"node_selector": {},
|
||||
"node_selector": null,
|
||||
"service_account_name": "761163285547-compute@developer.gserviceaccount.com",
|
||||
"serving_state": "",
|
||||
"timeout_seconds": 300,
|
||||
@ -437,7 +435,7 @@
|
||||
"schema_version": 0,
|
||||
"attributes": {
|
||||
"condition": [],
|
||||
"etag": "BwY16Etxb+g=",
|
||||
"etag": "BwY16UdHJ00=",
|
||||
"id": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact/roles/run.invoker/allUsers",
|
||||
"location": "us-central1",
|
||||
"member": "allUsers",
|
||||
@ -471,7 +469,7 @@
|
||||
"automatic_update_policy": [
|
||||
{}
|
||||
],
|
||||
"build": "projects/761163285547/locations/us-central1/builds/1b8e28d1-ee4d-4d2f-acf2-47e2b03aa421",
|
||||
"build": "projects/761163285547/locations/us-central1/builds/b2b7e513-e00e-462a-8ac8-94abdfb4a0b9",
|
||||
"docker_repository": "projects/gen-lang-client-0424120530/locations/us-central1/repositories/gcf-artifacts",
|
||||
"entry_point": "process_image_embedding",
|
||||
"environment_variables": {},
|
||||
@ -485,7 +483,7 @@
|
||||
{
|
||||
"bucket": "gen-lang-client-0424120530-cloud-function-source",
|
||||
"generation": 1748123369545880,
|
||||
"object": "function-source-34d81725abbd4f423de71ecd4215d116.zip"
|
||||
"object": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -554,7 +552,7 @@
|
||||
"goog-terraform-provisioned": "true"
|
||||
},
|
||||
"timeouts": null,
|
||||
"update_time": "2025-05-24T22:08:16.899711009Z",
|
||||
"update_time": "2025-05-24T22:31:52.525335119Z",
|
||||
"url": "https://us-central1-gen-lang-client-0424120530.cloudfunctions.net/process-image-embedding"
|
||||
},
|
||||
"sensitive_attributes": [
|
||||
@ -598,13 +596,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "google_compute_address",
|
||||
"name": "vector_db_static_ip",
|
||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||
"instances": []
|
||||
},
|
||||
{
|
||||
"mode": "managed",
|
||||
"type": "google_compute_firewall",
|
||||
@ -877,8 +868,8 @@
|
||||
"database_edition": "STANDARD",
|
||||
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
||||
"deletion_policy": "ABANDON",
|
||||
"earliest_version_time": "2025-05-24T21:26:23.088753Z",
|
||||
"etag": "IOqynKOTvY0DMKrW4vCEvY0D",
|
||||
"earliest_version_time": "2025-05-24T21:29:52.924798Z",
|
||||
"etag": "IPHgo4eUvY0DMKrW4vCEvY0D",
|
||||
"id": "projects/gen-lang-client-0424120530/databases/sereact-imagedb",
|
||||
"key_prefix": "",
|
||||
"location_id": "us-central1",
|
||||
@ -1502,21 +1493,21 @@
|
||||
"content_encoding": "",
|
||||
"content_language": "",
|
||||
"content_type": "application/zip",
|
||||
"crc32c": "YXAlNA==",
|
||||
"crc32c": "Y4Q5hw==",
|
||||
"customer_encryption": [],
|
||||
"detect_md5hash": "NNgXJau9T0I95x7NQhXRFg==",
|
||||
"detect_md5hash": "pdOn/hMclyv40O3zCVRQQg==",
|
||||
"event_based_hold": false,
|
||||
"generation": 1748124439573408,
|
||||
"id": "gen-lang-client-0424120530-cloud-function-source-function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
||||
"generation": 1748125796837241,
|
||||
"id": "gen-lang-client-0424120530-cloud-function-source-function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"kms_key_name": "",
|
||||
"md5hash": "NNgXJau9T0I95x7NQhXRFg==",
|
||||
"md5hexhash": "34d81725abbd4f423de71ecd4215d116",
|
||||
"media_link": "https://storage.googleapis.com/download/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-34d81725abbd4f423de71ecd4215d116.zip?generation=1748124439573408\u0026alt=media",
|
||||
"metadata": {},
|
||||
"name": "function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
||||
"output_name": "function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
||||
"md5hash": "pdOn/hMclyv40O3zCVRQQg==",
|
||||
"md5hexhash": "a5d3a7fe131c972bf8d0edf309545042",
|
||||
"media_link": "https://storage.googleapis.com/download/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-a5d3a7fe131c972bf8d0edf309545042.zip?generation=1748125796837241\u0026alt=media",
|
||||
"metadata": null,
|
||||
"name": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"output_name": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"retention": [],
|
||||
"self_link": "https://www.googleapis.com/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
||||
"self_link": "https://www.googleapis.com/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||
"source": "./function-source.zip",
|
||||
"storage_class": "STANDARD",
|
||||
"temporary_hold": false,
|
||||
|
||||
@ -136,10 +136,22 @@ async def list_images(
|
||||
current_user: UserModel = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
List images for the current user's team
|
||||
List images for the current user's team, or all images if user is admin.
|
||||
|
||||
Regular users can only see images from their own team.
|
||||
Admin users can see all images across all teams.
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip for pagination
|
||||
limit: Maximum number of records to return (1-100)
|
||||
collection_id: Optional filter by collection ID
|
||||
tags: Optional comma-separated list of tags to filter by
|
||||
|
||||
Returns:
|
||||
List of images with pagination metadata
|
||||
"""
|
||||
log_request(
|
||||
{"path": request.url.path, "method": request.method, "skip": skip, "limit": limit},
|
||||
{"path": request.url.path, "method": request.method, "skip": skip, "limit": limit, "is_admin": current_user.is_admin},
|
||||
user_id=str(current_user.id),
|
||||
team_id=str(current_user.team_id)
|
||||
)
|
||||
@ -149,21 +161,37 @@ async def list_images(
|
||||
if tags:
|
||||
tag_filter = [tag.strip() for tag in tags.split(',') if tag.strip()]
|
||||
|
||||
# Get images
|
||||
images = await image_repository.get_by_team(
|
||||
current_user.team_id,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
collection_id=ObjectId(collection_id) if collection_id else None,
|
||||
tags=tag_filter
|
||||
)
|
||||
# Check if user is admin - if so, get all images across all teams
|
||||
if current_user.is_admin:
|
||||
# Admin users can see all images across all teams
|
||||
images = await image_repository.get_all_with_pagination(
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
collection_id=ObjectId(collection_id) if collection_id else None,
|
||||
tags=tag_filter
|
||||
)
|
||||
|
||||
# Get total count
|
||||
total = await image_repository.count_by_team(
|
||||
current_user.team_id,
|
||||
collection_id=ObjectId(collection_id) if collection_id else None,
|
||||
tags=tag_filter
|
||||
)
|
||||
# Get total count for admin
|
||||
total = await image_repository.count_all(
|
||||
collection_id=ObjectId(collection_id) if collection_id else None,
|
||||
tags=tag_filter
|
||||
)
|
||||
else:
|
||||
# Regular users only see images from their team
|
||||
images = await image_repository.get_by_team(
|
||||
current_user.team_id,
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
collection_id=ObjectId(collection_id) if collection_id else None,
|
||||
tags=tag_filter
|
||||
)
|
||||
|
||||
# Get total count for regular user
|
||||
total = await image_repository.count_by_team(
|
||||
current_user.team_id,
|
||||
collection_id=ObjectId(collection_id) if collection_id else None,
|
||||
tags=tag_filter
|
||||
)
|
||||
|
||||
# Convert to response
|
||||
response_images = []
|
||||
@ -211,7 +239,7 @@ async def get_image(
|
||||
Get image metadata by ID
|
||||
"""
|
||||
log_request(
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id},
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id, "is_admin": current_user.is_admin},
|
||||
user_id=str(current_user.id),
|
||||
team_id=str(current_user.team_id)
|
||||
)
|
||||
@ -226,8 +254,8 @@ async def get_image(
|
||||
if not image:
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
|
||||
# Check team access
|
||||
if image.team_id != current_user.team_id:
|
||||
# Check team access (admins can access any image)
|
||||
if not current_user.is_admin and image.team_id != current_user.team_id:
|
||||
raise HTTPException(status_code=403, detail="Not authorized to access this image")
|
||||
|
||||
# Update last accessed
|
||||
@ -278,7 +306,7 @@ async def download_image(
|
||||
Download image file
|
||||
"""
|
||||
log_request(
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id},
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id, "is_admin": current_user.is_admin},
|
||||
user_id=str(current_user.id),
|
||||
team_id=str(current_user.team_id)
|
||||
)
|
||||
@ -293,8 +321,8 @@ async def download_image(
|
||||
if not image:
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
|
||||
# Check team access
|
||||
if image.team_id != current_user.team_id:
|
||||
# Check team access (admins can access any image)
|
||||
if not current_user.is_admin and image.team_id != current_user.team_id:
|
||||
raise HTTPException(status_code=403, detail="Not authorized to access this image")
|
||||
|
||||
# Get file from storage
|
||||
@ -323,7 +351,7 @@ async def update_image(
|
||||
Update image metadata
|
||||
"""
|
||||
log_request(
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id},
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id, "is_admin": current_user.is_admin},
|
||||
user_id=str(current_user.id),
|
||||
team_id=str(current_user.team_id)
|
||||
)
|
||||
@ -338,8 +366,8 @@ async def update_image(
|
||||
if not image:
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
|
||||
# Check team access
|
||||
if image.team_id != current_user.team_id:
|
||||
# Check team access (admins can update any image)
|
||||
if not current_user.is_admin and image.team_id != current_user.team_id:
|
||||
raise HTTPException(status_code=403, detail="Not authorized to update this image")
|
||||
|
||||
# Update image
|
||||
@ -398,7 +426,7 @@ async def delete_image(
|
||||
Delete an image
|
||||
"""
|
||||
log_request(
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id},
|
||||
{"path": request.url.path, "method": request.method, "image_id": image_id, "is_admin": current_user.is_admin},
|
||||
user_id=str(current_user.id),
|
||||
team_id=str(current_user.team_id)
|
||||
)
|
||||
@ -413,8 +441,8 @@ async def delete_image(
|
||||
if not image:
|
||||
raise HTTPException(status_code=404, detail="Image not found")
|
||||
|
||||
# Check team access
|
||||
if image.team_id != current_user.team_id:
|
||||
# Check team access (admins can delete any image)
|
||||
if not current_user.is_admin and image.team_id != current_user.team_id:
|
||||
raise HTTPException(status_code=403, detail="Not authorized to delete this image")
|
||||
|
||||
# Delete from storage
|
||||
|
||||
@ -173,5 +173,80 @@ class FirestoreImageRepository(FirestoreRepository[ImageModel]):
|
||||
logger.error(f"Error getting images by tag: {e}")
|
||||
raise
|
||||
|
||||
async def get_all_with_pagination(
|
||||
self,
|
||||
skip: int = 0,
|
||||
limit: int = 50,
|
||||
collection_id: Optional[ObjectId] = None,
|
||||
tags: Optional[List[str]] = None
|
||||
) -> List[ImageModel]:
|
||||
"""
|
||||
Get all images across all teams with pagination and filtering (admin only)
|
||||
|
||||
Args:
|
||||
skip: Number of records to skip
|
||||
limit: Maximum number of records to return
|
||||
collection_id: Optional collection ID filter
|
||||
tags: Optional list of tags to filter by
|
||||
|
||||
Returns:
|
||||
List of images
|
||||
"""
|
||||
try:
|
||||
# Get all images
|
||||
images = await self.get_all()
|
||||
|
||||
# Filter by collection if specified
|
||||
if collection_id:
|
||||
images = [image for image in images if image.collection_id == collection_id]
|
||||
|
||||
# Filter by tags if specified
|
||||
if tags:
|
||||
images = [
|
||||
image for image in images
|
||||
if any(tag in image.tags for tag in tags)
|
||||
]
|
||||
|
||||
# Apply pagination
|
||||
return images[skip:skip + limit]
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting all images with pagination: {e}")
|
||||
raise
|
||||
|
||||
async def count_all(
|
||||
self,
|
||||
collection_id: Optional[ObjectId] = None,
|
||||
tags: Optional[List[str]] = None
|
||||
) -> int:
|
||||
"""
|
||||
Count all images across all teams with filtering (admin only)
|
||||
|
||||
Args:
|
||||
collection_id: Optional collection ID filter
|
||||
tags: Optional list of tags to filter by
|
||||
|
||||
Returns:
|
||||
Count of images
|
||||
"""
|
||||
try:
|
||||
# Get all images
|
||||
images = await self.get_all()
|
||||
|
||||
# Filter by collection if specified
|
||||
if collection_id:
|
||||
images = [image for image in images if image.collection_id == collection_id]
|
||||
|
||||
# Filter by tags if specified
|
||||
if tags:
|
||||
images = [
|
||||
image for image in images
|
||||
if any(tag in image.tags for tag in tags)
|
||||
]
|
||||
|
||||
return len(images)
|
||||
except Exception as e:
|
||||
logger.error(f"Error counting all images: {e}")
|
||||
raise
|
||||
|
||||
# Create a singleton repository
|
||||
firestore_image_repository = FirestoreImageRepository()
|
||||
201
test_admin_images.py
Normal file
201
test_admin_images.py
Normal file
@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script to verify admin image access functionality.
|
||||
This script tests that:
|
||||
1. Regular users can only see images from their own team
|
||||
2. Admin users can see all images across all teams
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime
|
||||
from bson import ObjectId
|
||||
|
||||
# Add the src directory to the path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
|
||||
|
||||
from src.models.image import ImageModel
|
||||
from src.models.user import UserModel
|
||||
from src.db.repositories.image_repository import image_repository
|
||||
from src.db.repositories.user_repository import user_repository
|
||||
from src.db.providers.firestore_provider import firestore_db
|
||||
|
||||
|
||||
async def setup_test_data():
|
||||
"""Set up test data for the admin functionality test"""
|
||||
print("Setting up test data...")
|
||||
|
||||
# Create two teams
|
||||
team1_id = ObjectId()
|
||||
team2_id = ObjectId()
|
||||
|
||||
# Create users
|
||||
regular_user = UserModel(
|
||||
email="regular@test.com",
|
||||
name="Regular User",
|
||||
team_id=team1_id,
|
||||
is_admin=False
|
||||
)
|
||||
|
||||
admin_user = UserModel(
|
||||
email="admin@test.com",
|
||||
name="Admin User",
|
||||
team_id=team1_id,
|
||||
is_admin=True
|
||||
)
|
||||
|
||||
# Create test images for team 1
|
||||
image1_team1 = ImageModel(
|
||||
filename="team1-image1.jpg",
|
||||
original_filename="team1_image1.jpg",
|
||||
file_size=1024,
|
||||
content_type="image/jpeg",
|
||||
storage_path="images/team1-image1.jpg",
|
||||
team_id=team1_id,
|
||||
uploader_id=regular_user.id,
|
||||
description="Team 1 Image 1",
|
||||
tags=["team1", "test"]
|
||||
)
|
||||
|
||||
image2_team1 = ImageModel(
|
||||
filename="team1-image2.jpg",
|
||||
original_filename="team1_image2.jpg",
|
||||
file_size=2048,
|
||||
content_type="image/jpeg",
|
||||
storage_path="images/team1-image2.jpg",
|
||||
team_id=team1_id,
|
||||
uploader_id=admin_user.id,
|
||||
description="Team 1 Image 2",
|
||||
tags=["team1", "admin"]
|
||||
)
|
||||
|
||||
# Create test images for team 2
|
||||
image1_team2 = ImageModel(
|
||||
filename="team2-image1.jpg",
|
||||
original_filename="team2_image1.jpg",
|
||||
file_size=1536,
|
||||
content_type="image/jpeg",
|
||||
storage_path="images/team2-image1.jpg",
|
||||
team_id=team2_id,
|
||||
uploader_id=ObjectId(), # Different user from team 2
|
||||
description="Team 2 Image 1",
|
||||
tags=["team2", "test"]
|
||||
)
|
||||
|
||||
return {
|
||||
'regular_user': regular_user,
|
||||
'admin_user': admin_user,
|
||||
'team1_id': team1_id,
|
||||
'team2_id': team2_id,
|
||||
'images': [image1_team1, image2_team1, image1_team2]
|
||||
}
|
||||
|
||||
|
||||
async def test_regular_user_access(regular_user, team1_id):
|
||||
"""Test that regular users only see their team's images"""
|
||||
print("\n=== Testing Regular User Access ===")
|
||||
|
||||
# Simulate getting images for regular user (team-filtered)
|
||||
team1_images = await image_repository.get_by_team(team1_id, skip=0, limit=50)
|
||||
team1_count = await image_repository.count_by_team(team1_id)
|
||||
|
||||
print(f"Regular user sees {len(team1_images)} images from their team")
|
||||
print(f"Total count for team: {team1_count}")
|
||||
|
||||
for image in team1_images:
|
||||
print(f" - {image.filename} (Team: {image.team_id})")
|
||||
|
||||
# Verify all images belong to the user's team
|
||||
for image in team1_images:
|
||||
assert image.team_id == team1_id, f"Regular user should not see image from different team: {image.filename}"
|
||||
|
||||
print("✅ Regular user access test passed - only sees team images")
|
||||
return len(team1_images)
|
||||
|
||||
|
||||
async def test_admin_user_access(admin_user):
|
||||
"""Test that admin users see all images across all teams"""
|
||||
print("\n=== Testing Admin User Access ===")
|
||||
|
||||
# Simulate getting all images for admin user
|
||||
all_images = await image_repository.get_all_with_pagination(skip=0, limit=50)
|
||||
all_count = await image_repository.count_all()
|
||||
|
||||
print(f"Admin user sees {len(all_images)} images across all teams")
|
||||
print(f"Total count across all teams: {all_count}")
|
||||
|
||||
teams_seen = set()
|
||||
for image in all_images:
|
||||
teams_seen.add(str(image.team_id))
|
||||
print(f" - {image.filename} (Team: {image.team_id})")
|
||||
|
||||
print(f"Admin sees images from {len(teams_seen)} different teams")
|
||||
|
||||
# Verify admin sees more images than regular user would
|
||||
assert len(all_images) >= 2, "Admin should see images from multiple teams"
|
||||
assert len(teams_seen) >= 2, "Admin should see images from at least 2 teams"
|
||||
|
||||
print("✅ Admin user access test passed - sees all images across teams")
|
||||
return len(all_images)
|
||||
|
||||
|
||||
async def main():
|
||||
"""Main test function"""
|
||||
print("🧪 Testing Admin Image Access Functionality")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
# Connect to database
|
||||
firestore_db.connect()
|
||||
print("✅ Connected to Firestore")
|
||||
|
||||
# Set up test data
|
||||
test_data = await setup_test_data()
|
||||
|
||||
# Create test images in database
|
||||
created_images = []
|
||||
for image in test_data['images']:
|
||||
created_image = await image_repository.create(image)
|
||||
created_images.append(created_image)
|
||||
print(f"Created test image: {created_image.filename}")
|
||||
|
||||
# Test regular user access
|
||||
regular_count = await test_regular_user_access(
|
||||
test_data['regular_user'],
|
||||
test_data['team1_id']
|
||||
)
|
||||
|
||||
# Test admin user access
|
||||
admin_count = await test_admin_user_access(test_data['admin_user'])
|
||||
|
||||
# Verify admin sees more images than regular user
|
||||
print(f"\n=== Summary ===")
|
||||
print(f"Regular user images: {regular_count}")
|
||||
print(f"Admin user images: {admin_count}")
|
||||
|
||||
if admin_count > regular_count:
|
||||
print("✅ SUCCESS: Admin sees more images than regular user")
|
||||
else:
|
||||
print("❌ FAILURE: Admin should see more images than regular user")
|
||||
|
||||
# Clean up test data
|
||||
print(f"\n=== Cleanup ===")
|
||||
for image in created_images:
|
||||
await image_repository.delete(image.id)
|
||||
print(f"Deleted test image: {image.filename}")
|
||||
|
||||
print("✅ Test completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Test failed with error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
# Disconnect from database
|
||||
firestore_db.disconnect()
|
||||
print("✅ Disconnected from Firestore")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Loading…
x
Reference in New Issue
Block a user