cp
This commit is contained in:
parent
d894100d4d
commit
b3954a2ba1
@ -124,7 +124,8 @@ class ApiClient {
|
|||||||
|
|
||||||
// Images API
|
// Images API
|
||||||
async getImages(page = 1, limit = 20, tags = null) {
|
async getImages(page = 1, limit = 20, tags = null) {
|
||||||
let endpoint = `/images?page=${page}&limit=${limit}`;
|
const skip = (page - 1) * limit;
|
||||||
|
let endpoint = `/images?skip=${skip}&limit=${limit}`;
|
||||||
if (tags) {
|
if (tags) {
|
||||||
endpoint += `&tags=${encodeURIComponent(tags)}`;
|
endpoint += `&tags=${encodeURIComponent(tags)}`;
|
||||||
}
|
}
|
||||||
@ -173,18 +174,6 @@ class ApiClient {
|
|||||||
const response = await fetch(`${this.baseUrl}/health`);
|
const response = await fetch(`${this.baseUrl}/health`);
|
||||||
return response.ok;
|
return response.ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get image URL for display
|
|
||||||
getImageUrl(imageId) {
|
|
||||||
this.updateConfig();
|
|
||||||
return `${this.baseUrl}/api/v1/images/${imageId}/file`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get image thumbnail URL
|
|
||||||
getThumbnailUrl(imageId, size = 'medium') {
|
|
||||||
this.updateConfig();
|
|
||||||
return `${this.baseUrl}/api/v1/images/${imageId}/thumbnail?size=${size}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global API client instance
|
// Global API client instance
|
||||||
|
|||||||
@ -48,14 +48,14 @@ function displayImages(images) {
|
|||||||
|
|
||||||
const imagesHtml = images.map(image => `
|
const imagesHtml = images.map(image => `
|
||||||
<div class="image-card card">
|
<div class="image-card card">
|
||||||
<img src="${apiClient.getThumbnailUrl(image.id)}"
|
<img src="${image.public_url || '/placeholder-image.png'}"
|
||||||
alt="${escapeHtml(image.description || 'Image')}"
|
alt="${escapeHtml(image.description || 'Image')}"
|
||||||
onclick="viewImage('${image.id}')"
|
onclick="viewImage('${image.id}')"
|
||||||
style="cursor: pointer;">
|
style="cursor: pointer;">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h6 class="card-title">${escapeHtml(truncateText(image.description || 'Untitled', 50))}</h6>
|
<h6 class="card-title">${escapeHtml(truncateText(image.description || 'Untitled', 50))}</h6>
|
||||||
<p class="card-text small text-muted">
|
<p class="card-text small text-muted">
|
||||||
<i class="fas fa-calendar me-1"></i>${formatDate(image.created_at)}
|
<i class="fas fa-calendar me-1"></i>${formatDate(image.upload_date)}
|
||||||
</p>
|
</p>
|
||||||
${image.tags && image.tags.length > 0 ? `
|
${image.tags && image.tags.length > 0 ? `
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
@ -212,7 +212,7 @@ async function uploadImage() {
|
|||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
formData.append('description', description);
|
formData.append('description', description);
|
||||||
if (tags.length > 0) {
|
if (tags.length > 0) {
|
||||||
formData.append('tags', JSON.stringify(tags));
|
formData.append('tags', tags.join(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
await apiClient.uploadImage(formData);
|
await apiClient.uploadImage(formData);
|
||||||
@ -238,7 +238,7 @@ async function viewImage(imageId) {
|
|||||||
|
|
||||||
const modalBody = `
|
const modalBody = `
|
||||||
<div class="text-center mb-3">
|
<div class="text-center mb-3">
|
||||||
<img src="${apiClient.getImageUrl(imageId)}" class="img-fluid rounded"
|
<img src="${image.public_url || '/placeholder-image.png'}" class="img-fluid rounded"
|
||||||
style="max-height: 400px;">
|
style="max-height: 400px;">
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -248,9 +248,9 @@ async function viewImage(imageId) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6>Details</h6>
|
<h6>Details</h6>
|
||||||
<p><strong>Created:</strong> ${formatDate(image.created_at)}</p>
|
<p><strong>Created:</strong> ${formatDate(image.upload_date)}</p>
|
||||||
<p><strong>Size:</strong> ${formatFileSize(image.file_size)}</p>
|
<p><strong>Size:</strong> ${formatFileSize(image.file_size)}</p>
|
||||||
<p><strong>Dimensions:</strong> ${image.width} × ${image.height}</p>
|
<p><strong>Type:</strong> ${image.content_type}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${image.tags && image.tags.length > 0 ? `
|
${image.tags && image.tags.length > 0 ? `
|
||||||
@ -287,7 +287,7 @@ async function editImage(imageId) {
|
|||||||
const modalBody = `
|
const modalBody = `
|
||||||
<form id="editImageForm">
|
<form id="editImageForm">
|
||||||
<div class="mb-3 text-center">
|
<div class="mb-3 text-center">
|
||||||
<img src="${apiClient.getThumbnailUrl(imageId)}" class="img-fluid rounded"
|
<img src="${image.public_url || '/placeholder-image.png'}" class="img-fluid rounded"
|
||||||
style="max-height: 200px;">
|
style="max-height: 200px;">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
|||||||
@ -86,7 +86,7 @@ function displaySearchResults(results, query) {
|
|||||||
<div class="col-md-6 col-lg-4 mb-4">
|
<div class="col-md-6 col-lg-4 mb-4">
|
||||||
<div class="card search-result h-100">
|
<div class="card search-result h-100">
|
||||||
<div class="position-relative">
|
<div class="position-relative">
|
||||||
<img src="${apiClient.getThumbnailUrl(result.image.id)}"
|
<img src="${result.image.public_url || '/placeholder-image.png'}"
|
||||||
class="card-img-top"
|
class="card-img-top"
|
||||||
alt="${escapeHtml(result.image.description || 'Image')}"
|
alt="${escapeHtml(result.image.description || 'Image')}"
|
||||||
style="height: 200px; object-fit: cover; cursor: pointer;"
|
style="height: 200px; object-fit: cover; cursor: pointer;"
|
||||||
@ -100,7 +100,7 @@ function displaySearchResults(results, query) {
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h6 class="card-title">${escapeHtml(truncateText(result.image.description || 'Untitled', 60))}</h6>
|
<h6 class="card-title">${escapeHtml(truncateText(result.image.description || 'Untitled', 60))}</h6>
|
||||||
<p class="card-text small text-muted">
|
<p class="card-text small text-muted">
|
||||||
<i class="fas fa-calendar me-1"></i>${formatDate(result.image.created_at)}
|
<i class="fas fa-calendar me-1"></i>${formatDate(result.image.upload_date)}
|
||||||
</p>
|
</p>
|
||||||
${result.image.tags && result.image.tags.length > 0 ? `
|
${result.image.tags && result.image.tags.length > 0 ? `
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
|
|||||||
@ -1,3 +1,14 @@
|
|||||||
|
# Compute default service accounts
|
||||||
|
locals {
|
||||||
|
cloud_run_service_account = var.cloud_run_service_account != "" ? var.cloud_run_service_account : "${data.google_project.current.number}-compute@developer.gserviceaccount.com"
|
||||||
|
cloud_function_service_account = var.cloud_function_service_account != "" ? var.cloud_function_service_account : "${data.google_project.current.number}-compute@developer.gserviceaccount.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get current project information
|
||||||
|
data "google_project" "current" {
|
||||||
|
project_id = var.project_id
|
||||||
|
}
|
||||||
|
|
||||||
# Pub/Sub topic for image processing tasks
|
# Pub/Sub topic for image processing tasks
|
||||||
resource "google_pubsub_topic" "image_processing" {
|
resource "google_pubsub_topic" "image_processing" {
|
||||||
name = var.pubsub_topic_name
|
name = var.pubsub_topic_name
|
||||||
@ -73,7 +84,7 @@ resource "google_pubsub_topic_iam_binding" "image_processing_publisher" {
|
|||||||
role = "roles/pubsub.publisher"
|
role = "roles/pubsub.publisher"
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"serviceAccount:${var.cloud_run_service_account}",
|
"serviceAccount:${local.cloud_run_service_account}",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +94,7 @@ resource "google_pubsub_subscription_iam_binding" "image_processing_subscriber"
|
|||||||
role = "roles/pubsub.subscriber"
|
role = "roles/pubsub.subscriber"
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"serviceAccount:${var.cloud_function_service_account}",
|
"serviceAccount:${local.cloud_function_service_account}",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,371 @@
|
|||||||
{
|
{
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"terraform_version": "1.10.1",
|
"terraform_version": "1.10.1",
|
||||||
"serial": 28,
|
"serial": 41,
|
||||||
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||||
"outputs": {},
|
"outputs": {
|
||||||
"resources": [],
|
"container_registry_url": {
|
||||||
|
"value": "gcr.io/gen-lang-client-0424120530/sereact",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pubsub_dlq_topic_name": {
|
||||||
|
"value": "image-processing-topic-dlq",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pubsub_subscription_name": {
|
||||||
|
"value": "image-processing-topic-subscription",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pubsub_topic_name": {
|
||||||
|
"value": "image-processing-topic",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"storage_bucket_name": {
|
||||||
|
"value": "sereact-storage-bucket",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"mode": "data",
|
||||||
|
"type": "google_project",
|
||||||
|
"name": "current",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"auto_create_network": null,
|
||||||
|
"billing_account": "00CA97-62E5BD-4A62B5",
|
||||||
|
"deletion_policy": "PREVENT",
|
||||||
|
"effective_labels": {
|
||||||
|
"generative-language": "enabled"
|
||||||
|
},
|
||||||
|
"folder_id": null,
|
||||||
|
"id": "projects/gen-lang-client-0424120530",
|
||||||
|
"labels": {
|
||||||
|
"generative-language": "enabled"
|
||||||
|
},
|
||||||
|
"name": "Gemini API",
|
||||||
|
"number": "761163285547",
|
||||||
|
"org_id": null,
|
||||||
|
"project_id": "gen-lang-client-0424120530",
|
||||||
|
"tags": null,
|
||||||
|
"terraform_labels": {
|
||||||
|
"generative-language": "enabled"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensitive_attributes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_project_service",
|
||||||
|
"name": "services",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"index_key": "cloudresourcemanager.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/cloudresourcemanager.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "cloudresourcemanager.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "containerregistry.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/containerregistry.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "containerregistry.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "firestore.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/firestore.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "firestore.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "run.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/run.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "run.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_key": "storage.googleapis.com",
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"disable_dependent_services": null,
|
||||||
|
"disable_on_destroy": false,
|
||||||
|
"id": "gen-lang-client-0424120530/storage.googleapis.com",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"service": "storage.googleapis.com",
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_pubsub_subscription",
|
||||||
|
"name": "image_processing_dlq",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"ack_deadline_seconds": 10,
|
||||||
|
"bigquery_config": [],
|
||||||
|
"cloud_storage_config": [],
|
||||||
|
"dead_letter_policy": [],
|
||||||
|
"effective_labels": {
|
||||||
|
"component": "image-processing-dlq",
|
||||||
|
"environment": "dev",
|
||||||
|
"goog-terraform-provisioned": "true",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"enable_exactly_once_delivery": false,
|
||||||
|
"enable_message_ordering": false,
|
||||||
|
"expiration_policy": [
|
||||||
|
{
|
||||||
|
"ttl": "2678400s"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filter": "",
|
||||||
|
"id": "projects/gen-lang-client-0424120530/subscriptions/image-processing-topic-dlq-subscription",
|
||||||
|
"labels": {
|
||||||
|
"component": "image-processing-dlq",
|
||||||
|
"environment": "dev",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"message_retention_duration": "2592000s",
|
||||||
|
"name": "image-processing-topic-dlq-subscription",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"push_config": [],
|
||||||
|
"retain_acked_messages": true,
|
||||||
|
"retry_policy": [],
|
||||||
|
"terraform_labels": {
|
||||||
|
"component": "image-processing-dlq",
|
||||||
|
"environment": "dev",
|
||||||
|
"goog-terraform-provisioned": "true",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"timeouts": null,
|
||||||
|
"topic": "projects/gen-lang-client-0424120530/topics/image-processing-topic-dlq"
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19",
|
||||||
|
"dependencies": [
|
||||||
|
"google_pubsub_topic.image_processing_dlq"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_pubsub_topic",
|
||||||
|
"name": "image_processing",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"effective_labels": {
|
||||||
|
"component": "image-processing",
|
||||||
|
"environment": "dev",
|
||||||
|
"goog-terraform-provisioned": "true",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"id": "projects/gen-lang-client-0424120530/topics/image-processing-topic",
|
||||||
|
"ingestion_data_source_settings": [],
|
||||||
|
"kms_key_name": "",
|
||||||
|
"labels": {
|
||||||
|
"component": "image-processing",
|
||||||
|
"environment": "dev",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"message_retention_duration": "",
|
||||||
|
"message_storage_policy": [],
|
||||||
|
"name": "image-processing-topic",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"schema_settings": [],
|
||||||
|
"terraform_labels": {
|
||||||
|
"component": "image-processing",
|
||||||
|
"environment": "dev",
|
||||||
|
"goog-terraform-provisioned": "true",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_pubsub_topic",
|
||||||
|
"name": "image_processing_dlq",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"effective_labels": {
|
||||||
|
"component": "image-processing-dlq",
|
||||||
|
"environment": "dev",
|
||||||
|
"goog-terraform-provisioned": "true",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"id": "projects/gen-lang-client-0424120530/topics/image-processing-topic-dlq",
|
||||||
|
"ingestion_data_source_settings": [],
|
||||||
|
"kms_key_name": "",
|
||||||
|
"labels": {
|
||||||
|
"component": "image-processing-dlq",
|
||||||
|
"environment": "dev",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"message_retention_duration": "",
|
||||||
|
"message_storage_policy": [],
|
||||||
|
"name": "image-processing-topic-dlq",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"schema_settings": [],
|
||||||
|
"terraform_labels": {
|
||||||
|
"component": "image-processing-dlq",
|
||||||
|
"environment": "dev",
|
||||||
|
"goog-terraform-provisioned": "true",
|
||||||
|
"service": "sereact"
|
||||||
|
},
|
||||||
|
"timeouts": null
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_pubsub_topic_iam_binding",
|
||||||
|
"name": "image_processing_publisher",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 0,
|
||||||
|
"attributes": {
|
||||||
|
"condition": [],
|
||||||
|
"etag": "BwY14zaElfE=",
|
||||||
|
"id": "projects/gen-lang-client-0424120530/topics/image-processing-topic/roles/pubsub.publisher",
|
||||||
|
"members": [
|
||||||
|
"serviceAccount:761163285547-compute@developer.gserviceaccount.com"
|
||||||
|
],
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"role": "roles/pubsub.publisher",
|
||||||
|
"topic": "projects/gen-lang-client-0424120530/topics/image-processing-topic"
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "bnVsbA==",
|
||||||
|
"dependencies": [
|
||||||
|
"data.google_project.current",
|
||||||
|
"google_pubsub_topic.image_processing"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_storage_bucket",
|
||||||
|
"name": "app_bucket",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"schema_version": 3,
|
||||||
|
"attributes": {
|
||||||
|
"autoclass": [],
|
||||||
|
"cors": [],
|
||||||
|
"custom_placement_config": [],
|
||||||
|
"default_event_based_hold": false,
|
||||||
|
"effective_labels": {
|
||||||
|
"goog-terraform-provisioned": "true"
|
||||||
|
},
|
||||||
|
"enable_object_retention": false,
|
||||||
|
"encryption": [],
|
||||||
|
"force_destroy": false,
|
||||||
|
"hierarchical_namespace": [
|
||||||
|
{
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "sereact-storage-bucket",
|
||||||
|
"labels": null,
|
||||||
|
"lifecycle_rule": [],
|
||||||
|
"location": "US-CENTRAL1",
|
||||||
|
"logging": [],
|
||||||
|
"name": "sereact-storage-bucket",
|
||||||
|
"project": "gen-lang-client-0424120530",
|
||||||
|
"project_number": 761163285547,
|
||||||
|
"public_access_prevention": "inherited",
|
||||||
|
"requester_pays": false,
|
||||||
|
"retention_policy": [],
|
||||||
|
"rpo": null,
|
||||||
|
"self_link": "https://www.googleapis.com/storage/v1/b/sereact-storage-bucket",
|
||||||
|
"soft_delete_policy": [
|
||||||
|
{
|
||||||
|
"effective_time": "2025-05-24T15:17:40.181Z",
|
||||||
|
"retention_duration_seconds": 604800
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storage_class": "STANDARD",
|
||||||
|
"terraform_labels": {
|
||||||
|
"goog-terraform-provisioned": "true"
|
||||||
|
},
|
||||||
|
"time_created": "2025-05-24T15:17:40.181Z",
|
||||||
|
"timeouts": null,
|
||||||
|
"uniform_bucket_level_access": true,
|
||||||
|
"updated": "2025-05-24T15:17:40.181Z",
|
||||||
|
"url": "gs://sereact-storage-bucket",
|
||||||
|
"versioning": [],
|
||||||
|
"website": []
|
||||||
|
},
|
||||||
|
"sensitive_attributes": [],
|
||||||
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsInJlYWQiOjI0MDAwMDAwMDAwMCwidXBkYXRlIjoyNDAwMDAwMDAwMDB9LCJzY2hlbWFfdmVyc2lvbiI6IjMifQ==",
|
||||||
|
"dependencies": [
|
||||||
|
"google_project_service.services"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"check_results": null
|
"check_results": null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,416 +1,9 @@
|
|||||||
{
|
{
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"terraform_version": "1.10.1",
|
"terraform_version": "1.10.1",
|
||||||
"serial": 18,
|
"serial": 28,
|
||||||
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||||
"outputs": {
|
"outputs": {},
|
||||||
"cloud_run_url": {
|
"resources": [],
|
||||||
"value": "https://sereact-p64zpdtkta-uc.a.run.app",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"container_registry_url": {
|
|
||||||
"value": "gcr.io/gen-lang-client-0424120530/sereact",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"firestore_database_id": {
|
|
||||||
"value": "projects/gen-lang-client-0424120530/databases/imagedb",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"storage_bucket_name": {
|
|
||||||
"value": "sereact-storage-bucket",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "google_cloud_run_service",
|
|
||||||
"name": "sereact",
|
|
||||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 2,
|
|
||||||
"attributes": {
|
|
||||||
"autogenerate_revision_name": false,
|
|
||||||
"id": "locations/us-central1/namespaces/gen-lang-client-0424120530/services/sereact",
|
|
||||||
"location": "us-central1",
|
|
||||||
"metadata": [
|
|
||||||
{
|
|
||||||
"annotations": {},
|
|
||||||
"effective_annotations": {
|
|
||||||
"run.googleapis.com/ingress": "all",
|
|
||||||
"run.googleapis.com/ingress-status": "all",
|
|
||||||
"run.googleapis.com/operation-id": "0982194f-b3e8-45b8-a33f-7ed5fd529307",
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"effective_labels": {
|
|
||||||
"cloud.googleapis.com/location": "us-central1"
|
|
||||||
},
|
|
||||||
"generation": 1,
|
|
||||||
"labels": {},
|
|
||||||
"namespace": "gen-lang-client-0424120530",
|
|
||||||
"resource_version": "AAY108GXDwM",
|
|
||||||
"self_link": "/apis/serving.knative.dev/v1/namespaces/761163285547/services/sereact",
|
|
||||||
"terraform_labels": {},
|
|
||||||
"uid": "5b695749-5095-4fb5-86bd-4d86f77dc7da"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "sereact",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"status": [
|
|
||||||
{
|
|
||||||
"conditions": [
|
|
||||||
{
|
|
||||||
"message": "",
|
|
||||||
"reason": "",
|
|
||||||
"status": "True",
|
|
||||||
"type": "Ready"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"message": "",
|
|
||||||
"reason": "",
|
|
||||||
"status": "True",
|
|
||||||
"type": "ConfigurationsReady"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"message": "",
|
|
||||||
"reason": "",
|
|
||||||
"status": "True",
|
|
||||||
"type": "RoutesReady"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"latest_created_revision_name": "sereact-00001-bt2",
|
|
||||||
"latest_ready_revision_name": "sereact-00001-bt2",
|
|
||||||
"observed_generation": 1,
|
|
||||||
"traffic": [
|
|
||||||
{
|
|
||||||
"latest_revision": true,
|
|
||||||
"percent": 100,
|
|
||||||
"revision_name": "sereact-00001-bt2",
|
|
||||||
"tag": "",
|
|
||||||
"url": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"url": "https://sereact-p64zpdtkta-uc.a.run.app"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"template": [
|
|
||||||
{
|
|
||||||
"metadata": [
|
|
||||||
{
|
|
||||||
"annotations": {
|
|
||||||
"autoscaling.knative.dev/maxScale": "3"
|
|
||||||
},
|
|
||||||
"generation": 0,
|
|
||||||
"labels": {
|
|
||||||
"run.googleapis.com/startupProbeType": "Default"
|
|
||||||
},
|
|
||||||
"name": "",
|
|
||||||
"namespace": "",
|
|
||||||
"resource_version": "",
|
|
||||||
"self_link": "",
|
|
||||||
"uid": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"spec": [
|
|
||||||
{
|
|
||||||
"container_concurrency": 80,
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"args": null,
|
|
||||||
"command": null,
|
|
||||||
"env": [
|
|
||||||
{
|
|
||||||
"name": "DATABASE_NAME",
|
|
||||||
"value": "imagedb",
|
|
||||||
"value_from": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "GCS_BUCKET_NAME",
|
|
||||||
"value": "sereact-storage-bucket",
|
|
||||||
"value_from": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LOG_LEVEL",
|
|
||||||
"value": "INFO",
|
|
||||||
"value_from": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"env_from": [],
|
|
||||||
"image": "gcr.io/google-samples/hello-app:1.0",
|
|
||||||
"liveness_probe": [],
|
|
||||||
"name": "",
|
|
||||||
"ports": [
|
|
||||||
{
|
|
||||||
"container_port": 8080,
|
|
||||||
"name": "http1",
|
|
||||||
"protocol": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"limits": {
|
|
||||||
"cpu": "1",
|
|
||||||
"memory": "512Mi"
|
|
||||||
},
|
|
||||||
"requests": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"startup_probe": [
|
|
||||||
{
|
|
||||||
"failure_threshold": 1,
|
|
||||||
"grpc": [],
|
|
||||||
"http_get": [],
|
|
||||||
"initial_delay_seconds": 0,
|
|
||||||
"period_seconds": 240,
|
|
||||||
"tcp_socket": [
|
|
||||||
{
|
|
||||||
"port": 8080
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timeout_seconds": 240
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"volume_mounts": [],
|
|
||||||
"working_dir": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"node_selector": null,
|
|
||||||
"service_account_name": "761163285547-compute@developer.gserviceaccount.com",
|
|
||||||
"serving_state": "",
|
|
||||||
"timeout_seconds": 300,
|
|
||||||
"volumes": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timeouts": null,
|
|
||||||
"traffic": [
|
|
||||||
{
|
|
||||||
"latest_revision": true,
|
|
||||||
"percent": 100,
|
|
||||||
"revision_name": "",
|
|
||||||
"tag": "",
|
|
||||||
"url": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiMiJ9",
|
|
||||||
"dependencies": [
|
|
||||||
"google_project_service.services"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "google_cloud_run_service_iam_member",
|
|
||||||
"name": "public_access",
|
|
||||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"condition": [],
|
|
||||||
"etag": "BwY108GyUf0=",
|
|
||||||
"id": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact/roles/run.invoker/allUsers",
|
|
||||||
"location": "us-central1",
|
|
||||||
"member": "allUsers",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"role": "roles/run.invoker",
|
|
||||||
"service": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact"
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "bnVsbA==",
|
|
||||||
"dependencies": [
|
|
||||||
"google_cloud_run_service.sereact",
|
|
||||||
"google_project_service.services"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "google_firestore_database",
|
|
||||||
"name": "database",
|
|
||||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"app_engine_integration_mode": "DISABLED",
|
|
||||||
"cmek_config": [],
|
|
||||||
"concurrency_mode": "PESSIMISTIC",
|
|
||||||
"create_time": "",
|
|
||||||
"database_edition": "STANDARD",
|
|
||||||
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
|
||||||
"deletion_policy": "ABANDON",
|
|
||||||
"earliest_version_time": "2025-05-23T20:47:31.801717Z",
|
|
||||||
"etag": "IIelp4e8uo0DMPX0nai7uo0D",
|
|
||||||
"id": "projects/gen-lang-client-0424120530/databases/imagedb",
|
|
||||||
"key_prefix": "",
|
|
||||||
"location_id": "us-central1",
|
|
||||||
"name": "imagedb",
|
|
||||||
"point_in_time_recovery_enablement": "POINT_IN_TIME_RECOVERY_DISABLED",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"timeouts": null,
|
|
||||||
"type": "FIRESTORE_NATIVE",
|
|
||||||
"uid": "177e30f2-9b67-428c-9979-22e625b929c4",
|
|
||||||
"update_time": "",
|
|
||||||
"version_retention_period": "3600s"
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19",
|
|
||||||
"dependencies": [
|
|
||||||
"google_project_service.services"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "google_project_service",
|
|
||||||
"name": "services",
|
|
||||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"index_key": "cloudresourcemanager.googleapis.com",
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"disable_dependent_services": null,
|
|
||||||
"disable_on_destroy": false,
|
|
||||||
"id": "gen-lang-client-0424120530/cloudresourcemanager.googleapis.com",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"service": "cloudresourcemanager.googleapis.com",
|
|
||||||
"timeouts": null
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index_key": "containerregistry.googleapis.com",
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"disable_dependent_services": null,
|
|
||||||
"disable_on_destroy": false,
|
|
||||||
"id": "gen-lang-client-0424120530/containerregistry.googleapis.com",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"service": "containerregistry.googleapis.com",
|
|
||||||
"timeouts": null
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index_key": "firestore.googleapis.com",
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"disable_dependent_services": null,
|
|
||||||
"disable_on_destroy": false,
|
|
||||||
"id": "gen-lang-client-0424120530/firestore.googleapis.com",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"service": "firestore.googleapis.com",
|
|
||||||
"timeouts": null
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index_key": "run.googleapis.com",
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"disable_dependent_services": null,
|
|
||||||
"disable_on_destroy": false,
|
|
||||||
"id": "gen-lang-client-0424120530/run.googleapis.com",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"service": "run.googleapis.com",
|
|
||||||
"timeouts": null
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index_key": "storage.googleapis.com",
|
|
||||||
"schema_version": 0,
|
|
||||||
"attributes": {
|
|
||||||
"disable_dependent_services": null,
|
|
||||||
"disable_on_destroy": false,
|
|
||||||
"id": "gen-lang-client-0424120530/storage.googleapis.com",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"service": "storage.googleapis.com",
|
|
||||||
"timeouts": null
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mode": "managed",
|
|
||||||
"type": "google_storage_bucket",
|
|
||||||
"name": "app_bucket",
|
|
||||||
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
|
||||||
"instances": [
|
|
||||||
{
|
|
||||||
"schema_version": 3,
|
|
||||||
"attributes": {
|
|
||||||
"autoclass": [],
|
|
||||||
"cors": [],
|
|
||||||
"custom_placement_config": [],
|
|
||||||
"default_event_based_hold": false,
|
|
||||||
"effective_labels": {
|
|
||||||
"goog-terraform-provisioned": "true"
|
|
||||||
},
|
|
||||||
"enable_object_retention": false,
|
|
||||||
"encryption": [],
|
|
||||||
"force_destroy": false,
|
|
||||||
"hierarchical_namespace": [
|
|
||||||
{
|
|
||||||
"enabled": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "sereact-storage-bucket",
|
|
||||||
"labels": {},
|
|
||||||
"lifecycle_rule": [],
|
|
||||||
"location": "US-CENTRAL1",
|
|
||||||
"logging": [],
|
|
||||||
"name": "sereact-storage-bucket",
|
|
||||||
"project": "gen-lang-client-0424120530",
|
|
||||||
"project_number": 761163285547,
|
|
||||||
"public_access_prevention": "inherited",
|
|
||||||
"requester_pays": false,
|
|
||||||
"retention_policy": [],
|
|
||||||
"rpo": null,
|
|
||||||
"self_link": "https://www.googleapis.com/storage/v1/b/sereact-storage-bucket",
|
|
||||||
"soft_delete_policy": [
|
|
||||||
{
|
|
||||||
"effective_time": "2025-05-23T20:47:26.788Z",
|
|
||||||
"retention_duration_seconds": 604800
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storage_class": "STANDARD",
|
|
||||||
"terraform_labels": {
|
|
||||||
"goog-terraform-provisioned": "true"
|
|
||||||
},
|
|
||||||
"time_created": "2025-05-23T20:47:26.788Z",
|
|
||||||
"timeouts": null,
|
|
||||||
"uniform_bucket_level_access": true,
|
|
||||||
"updated": "2025-05-23T20:47:26.788Z",
|
|
||||||
"url": "gs://sereact-storage-bucket",
|
|
||||||
"versioning": [],
|
|
||||||
"website": []
|
|
||||||
},
|
|
||||||
"sensitive_attributes": [],
|
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsInJlYWQiOjI0MDAwMDAwMDAwMCwidXBkYXRlIjoyNDAwMDAwMDAwMDB9LCJzY2hlbWFfdmVyc2lvbiI6IjMifQ==",
|
|
||||||
"dependencies": [
|
|
||||||
"google_project_service.services"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"check_results": null
|
"check_results": null
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,9 +41,11 @@ variable "pubsub_topic_name" {
|
|||||||
variable "cloud_run_service_account" {
|
variable "cloud_run_service_account" {
|
||||||
description = "The service account email for Cloud Run"
|
description = "The service account email for Cloud Run"
|
||||||
type = string
|
type = string
|
||||||
|
default = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "cloud_function_service_account" {
|
variable "cloud_function_service_account" {
|
||||||
description = "The service account email for Cloud Functions"
|
description = "The service account email for Cloud Functions"
|
||||||
type = string
|
type = string
|
||||||
|
default = ""
|
||||||
}
|
}
|
||||||
@ -62,6 +62,9 @@ async def upload_image(
|
|||||||
file, str(current_user.team_id)
|
file, str(current_user.team_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Generate public URL
|
||||||
|
public_url = storage_service.generate_public_url(storage_path)
|
||||||
|
|
||||||
# Process tags
|
# Process tags
|
||||||
tag_list = []
|
tag_list = []
|
||||||
if tags:
|
if tags:
|
||||||
@ -74,6 +77,7 @@ async def upload_image(
|
|||||||
file_size=file_size,
|
file_size=file_size,
|
||||||
content_type=content_type,
|
content_type=content_type,
|
||||||
storage_path=storage_path,
|
storage_path=storage_path,
|
||||||
|
public_url=public_url,
|
||||||
team_id=current_user.team_id,
|
team_id=current_user.team_id,
|
||||||
uploader_id=current_user.id,
|
uploader_id=current_user.id,
|
||||||
description=description,
|
description=description,
|
||||||
@ -105,6 +109,7 @@ async def upload_image(
|
|||||||
file_size=created_image.file_size,
|
file_size=created_image.file_size,
|
||||||
content_type=created_image.content_type,
|
content_type=created_image.content_type,
|
||||||
storage_path=created_image.storage_path,
|
storage_path=created_image.storage_path,
|
||||||
|
public_url=created_image.public_url,
|
||||||
team_id=str(created_image.team_id),
|
team_id=str(created_image.team_id),
|
||||||
uploader_id=str(created_image.uploader_id),
|
uploader_id=str(created_image.uploader_id),
|
||||||
upload_date=created_image.upload_date,
|
upload_date=created_image.upload_date,
|
||||||
@ -163,6 +168,19 @@ async def list_images(
|
|||||||
# Convert to response
|
# Convert to response
|
||||||
response_images = []
|
response_images = []
|
||||||
for image in images:
|
for image in images:
|
||||||
|
# Generate public URL if not set
|
||||||
|
public_url = image.public_url
|
||||||
|
if not public_url and image.storage_path:
|
||||||
|
# Make the file public and generate URL
|
||||||
|
try:
|
||||||
|
storage_service.make_file_public(image.storage_path)
|
||||||
|
public_url = storage_service.generate_public_url(image.storage_path)
|
||||||
|
# Update the database with the public URL
|
||||||
|
await image_repository.update(image.id, {"public_url": public_url})
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to make file public or update URL for image {image.id}: {e}")
|
||||||
|
public_url = storage_service.generate_public_url(image.storage_path)
|
||||||
|
|
||||||
response_images.append(ImageResponse(
|
response_images.append(ImageResponse(
|
||||||
id=str(image.id),
|
id=str(image.id),
|
||||||
filename=image.filename,
|
filename=image.filename,
|
||||||
@ -170,6 +188,7 @@ async def list_images(
|
|||||||
file_size=image.file_size,
|
file_size=image.file_size,
|
||||||
content_type=image.content_type,
|
content_type=image.content_type,
|
||||||
storage_path=image.storage_path,
|
storage_path=image.storage_path,
|
||||||
|
public_url=public_url,
|
||||||
team_id=str(image.team_id),
|
team_id=str(image.team_id),
|
||||||
uploader_id=str(image.uploader_id),
|
uploader_id=str(image.uploader_id),
|
||||||
upload_date=image.upload_date,
|
upload_date=image.upload_date,
|
||||||
@ -214,6 +233,19 @@ async def get_image(
|
|||||||
# Update last accessed
|
# Update last accessed
|
||||||
await image_repository.update_last_accessed(obj_id)
|
await image_repository.update_last_accessed(obj_id)
|
||||||
|
|
||||||
|
# Generate public URL if not set
|
||||||
|
public_url = image.public_url
|
||||||
|
if not public_url and image.storage_path:
|
||||||
|
# Make the file public and generate URL
|
||||||
|
try:
|
||||||
|
storage_service.make_file_public(image.storage_path)
|
||||||
|
public_url = storage_service.generate_public_url(image.storage_path)
|
||||||
|
# Update the database with the public URL
|
||||||
|
await image_repository.update(image.id, {"public_url": public_url})
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to make file public or update URL for image {image.id}: {e}")
|
||||||
|
public_url = storage_service.generate_public_url(image.storage_path)
|
||||||
|
|
||||||
# Convert to response
|
# Convert to response
|
||||||
response = ImageResponse(
|
response = ImageResponse(
|
||||||
id=str(image.id),
|
id=str(image.id),
|
||||||
@ -222,6 +254,7 @@ async def get_image(
|
|||||||
file_size=image.file_size,
|
file_size=image.file_size,
|
||||||
content_type=image.content_type,
|
content_type=image.content_type,
|
||||||
storage_path=image.storage_path,
|
storage_path=image.storage_path,
|
||||||
|
public_url=public_url,
|
||||||
team_id=str(image.team_id),
|
team_id=str(image.team_id),
|
||||||
uploader_id=str(image.uploader_id),
|
uploader_id=str(image.uploader_id),
|
||||||
upload_date=image.upload_date,
|
upload_date=image.upload_date,
|
||||||
|
|||||||
@ -122,7 +122,10 @@ class StorageService:
|
|||||||
# Upload the file
|
# Upload the file
|
||||||
blob.upload_from_string(content, content_type=content_type)
|
blob.upload_from_string(content, content_type=content_type)
|
||||||
|
|
||||||
logger.info(f"File uploaded: {storage_path}")
|
# Make the blob publicly readable
|
||||||
|
blob.make_public()
|
||||||
|
|
||||||
|
logger.info(f"File uploaded and made public: {storage_path}")
|
||||||
|
|
||||||
# Seek back to the beginning for future reads
|
# Seek back to the beginning for future reads
|
||||||
await file.seek(0)
|
await file.seek(0)
|
||||||
@ -222,6 +225,29 @@ class StorageService:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error generating signed URL: {e}")
|
logger.error(f"Error generating signed URL: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def make_file_public(self, storage_path: str) -> bool:
|
||||||
|
"""
|
||||||
|
Make a file publicly accessible
|
||||||
|
|
||||||
|
Args:
|
||||||
|
storage_path: Storage path of the file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if file was made public, False if not found
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
blob = self.bucket.blob(storage_path)
|
||||||
|
if not blob.exists():
|
||||||
|
logger.warning(f"File not found for making public: {storage_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
blob.make_public()
|
||||||
|
logger.info(f"File made public: {storage_path}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error making file public: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
# Create a singleton service
|
# Create a singleton service
|
||||||
storage_service = StorageService()
|
storage_service = StorageService()
|
||||||
21
test_images_api.py
Normal file
21
test_images_api.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Test the images API
|
||||||
|
def test_images_api():
|
||||||
|
base_url = "http://localhost:8000"
|
||||||
|
|
||||||
|
# First, let's check if we need to bootstrap or if there are existing API keys
|
||||||
|
try:
|
||||||
|
# Try to get images without API key first to see the error
|
||||||
|
response = requests.get(f"{base_url}/api/v1/images")
|
||||||
|
print(f"Images API without auth: {response.status_code}")
|
||||||
|
print(f"Response: {response.text[:200]}...")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error testing images API: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_images_api()
|
||||||
Loading…
x
Reference in New Issue
Block a user