fixes
This commit is contained in:
5
.env
5
.env
@@ -9,8 +9,9 @@ GOOGLE_APPLICATION_CREDENTIALS=./rothbard-staging2-12345-firebase-adminsdk-fbsvc
|
|||||||
|
|
||||||
# Filevine auth
|
# Filevine auth
|
||||||
FILEVINE_CLIENT_ID=4F18738C-107A-4B82-BFAC-308F1B6A626A
|
FILEVINE_CLIENT_ID=4F18738C-107A-4B82-BFAC-308F1B6A626A
|
||||||
FILEVINE_CLIENT_SECRET=*2{aXWvYN(9!BiYUXC_tXj^n8
|
FILEVINE_CLIENT_SECRET=q<}QzfD^3t_atF-7+U8(gJCgj
|
||||||
FILEVINE_PERSONAL_ACCESS_TOKEN=C8F5C606B834D4EE0CBF0793969496F6210037EB934523756BA80BF2D8EC1880
|
FILEVINE_PERSONAL_ACCESS_TOKEN=68BEBFB8437B9668642BD71EDEAF09593ACF075CE35AE4079FC7588410094210
|
||||||
|
|
||||||
FILEVINE_ORG_ID=9227
|
FILEVINE_ORG_ID=9227
|
||||||
FILEVINE_USER_ID=100510
|
FILEVINE_USER_ID=100510
|
||||||
|
|
||||||
|
|||||||
2
app.py
2
app.py
@@ -383,7 +383,7 @@ def dashboard_export_xls():
|
|||||||
elif header == 'Notice Expir. Date':
|
elif header == 'Notice Expir. Date':
|
||||||
field_name = 'notice_expiration_date'
|
field_name = 'notice_expiration_date'
|
||||||
elif header == 'Date Case Filed':
|
elif header == 'Date Case Filed':
|
||||||
field_name = 'case_field_date'
|
field_name = 'case_filed_date'
|
||||||
elif header == 'Daily Rent Damages':
|
elif header == 'Daily Rent Damages':
|
||||||
field_name = 'daily_rent_damages'
|
field_name = 'daily_rent_damages'
|
||||||
elif header == 'Default Date':
|
elif header == 'Default Date':
|
||||||
|
|||||||
@@ -11,14 +11,15 @@ FV_USER_ID = os.environ.get("FILEVINE_USER_ID")
|
|||||||
|
|
||||||
class FilevineClient:
|
class FilevineClient:
|
||||||
def __init__(self, bearer_token: str = None):
|
def __init__(self, bearer_token: str = None):
|
||||||
self.bearer_token = bearer_token
|
|
||||||
self.base_url = "https://api.filevineapp.com/fv-app/v2"
|
self.base_url = "https://api.filevineapp.com/fv-app/v2"
|
||||||
|
self.bearer_token = bearer_token
|
||||||
self.headers = {
|
self.headers = {
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
"Authorization": f"Bearer {self.bearer_token}",
|
"Authorization": f"Bearer {self.bearer_token}",
|
||||||
"x-fv-orgid": str(FV_ORG_ID),
|
"x-fv-orgid": str(FV_ORG_ID),
|
||||||
"x-fv-userid": str(FV_USER_ID),
|
"x-fv-userid": str(FV_USER_ID),
|
||||||
}
|
}
|
||||||
|
self.get_bearer_token()
|
||||||
|
|
||||||
def get_bearer_token(self) -> str:
|
def get_bearer_token(self) -> str:
|
||||||
"""Get a new bearer token using Filevine credentials"""
|
"""Get a new bearer token using Filevine credentials"""
|
||||||
@@ -32,6 +33,7 @@ class FilevineClient:
|
|||||||
}
|
}
|
||||||
|
|
||||||
headers = {"Accept": "application/json"}
|
headers = {"Accept": "application/json"}
|
||||||
|
print("data is", data)
|
||||||
print(data)
|
print(data)
|
||||||
resp = requests.post(url, data=data, headers=headers, timeout=30)
|
resp = requests.post(url, data=data, headers=headers, timeout=30)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class ProjectModel:
|
|||||||
pending_tasks: List[Dict[str, Any]] = None,
|
pending_tasks: List[Dict[str, Any]] = None,
|
||||||
notice_service_date: str = "",
|
notice_service_date: str = "",
|
||||||
notice_expiration_date: str = "",
|
notice_expiration_date: str = "",
|
||||||
|
case_filed_date: str = "",
|
||||||
case_field_date: str = "",
|
case_field_date: str = "",
|
||||||
daily_rent_damages: str = "",
|
daily_rent_damages: str = "",
|
||||||
default_date: str = "",
|
default_date: str = "",
|
||||||
@@ -89,6 +90,7 @@ class ProjectModel:
|
|||||||
self.pending_tasks = pending_tasks or []
|
self.pending_tasks = pending_tasks or []
|
||||||
self.notice_service_date = notice_service_date
|
self.notice_service_date = notice_service_date
|
||||||
self.notice_expiration_date = notice_expiration_date
|
self.notice_expiration_date = notice_expiration_date
|
||||||
|
self.case_filed_date = case_filed_date or case_field_date
|
||||||
self.case_field_date = case_field_date
|
self.case_field_date = case_field_date
|
||||||
self.daily_rent_damages = daily_rent_damages
|
self.daily_rent_damages = daily_rent_damages
|
||||||
self.default_date = default_date
|
self.default_date = default_date
|
||||||
@@ -149,6 +151,7 @@ class ProjectModel:
|
|||||||
"pending_tasks": self.pending_tasks,
|
"pending_tasks": self.pending_tasks,
|
||||||
"notice_service_date": self.notice_service_date,
|
"notice_service_date": self.notice_service_date,
|
||||||
"notice_expiration_date": self.notice_expiration_date,
|
"notice_expiration_date": self.notice_expiration_date,
|
||||||
|
"case_filed_date": self.case_filed_date,
|
||||||
"case_field_date": self.case_field_date,
|
"case_field_date": self.case_field_date,
|
||||||
"daily_rent_damages": self.daily_rent_damages,
|
"daily_rent_damages": self.daily_rent_damages,
|
||||||
"default_date": self.default_date,
|
"default_date": self.default_date,
|
||||||
@@ -211,6 +214,7 @@ class ProjectModel:
|
|||||||
pending_tasks=data.get("pending_tasks", []),
|
pending_tasks=data.get("pending_tasks", []),
|
||||||
notice_service_date=data.get("notice_service_date", ""),
|
notice_service_date=data.get("notice_service_date", ""),
|
||||||
notice_expiration_date=data.get("notice_expiration_date", ""),
|
notice_expiration_date=data.get("notice_expiration_date", ""),
|
||||||
|
case_filed_date=data.get("case_filed_date", ""),
|
||||||
case_field_date=data.get("case_field_date", ""),
|
case_field_date=data.get("case_field_date", ""),
|
||||||
daily_rent_damages=data.get("daily_rent_damages", ""),
|
daily_rent_damages=data.get("daily_rent_damages", ""),
|
||||||
default_date=data.get("default_date", ""),
|
default_date=data.get("default_date", ""),
|
||||||
|
|||||||
32
sync.py
32
sync.py
@@ -29,6 +29,22 @@ def convert_to_pacific_time(date_str):
|
|||||||
if not date_str:
|
if not date_str:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Parse the UTC datetime
|
||||||
|
utc_time = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
|
||||||
|
|
||||||
|
# Set timezone to UTC
|
||||||
|
utc_time = utc_time.replace(tzinfo=pytz.UTC)
|
||||||
|
|
||||||
|
# Convert to Pacific Time
|
||||||
|
pacific_time = utc_time.astimezone(pytz.timezone('America/Los_Angeles'))
|
||||||
|
|
||||||
|
# Format as YYYY-MM-DD
|
||||||
|
return pacific_time.strftime('%Y-%m-%d')
|
||||||
|
except (ValueError, AttributeError) as e:
|
||||||
|
print(f"[WARN] Date conversion failed for '{date_str}': {e}")
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def extract_domains_from_emails(emails: List[str]) -> List[str]:
|
def extract_domains_from_emails(emails: List[str]) -> List[str]:
|
||||||
"""Extract unique domains from a list of email addresses.
|
"""Extract unique domains from a list of email addresses.
|
||||||
@@ -155,6 +171,10 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine
|
|||||||
# Extract default date
|
# Extract default date
|
||||||
default_date = convert_to_pacific_time(dates_and_deadlines.get("defaultDate")) or ''
|
default_date = convert_to_pacific_time(dates_and_deadlines.get("defaultDate")) or ''
|
||||||
case_filed_date = convert_to_pacific_time(dates_and_deadlines.get("dateCaseFiled")) or ''
|
case_filed_date = convert_to_pacific_time(dates_and_deadlines.get("dateCaseFiled")) or ''
|
||||||
|
cf = dates_and_deadlines.get("dateCaseFiled")
|
||||||
|
from pprint import pprint
|
||||||
|
print(f"CASE FILED {case_filed_date} {cf}")
|
||||||
|
pprint(dates_and_deadlines)
|
||||||
|
|
||||||
# Extract motion hearing dates
|
# Extract motion hearing dates
|
||||||
demurrer_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("demurrerHearingDate")) or ''
|
demurrer_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("demurrerHearingDate")) or ''
|
||||||
@@ -205,7 +225,6 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine
|
|||||||
import itertools
|
import itertools
|
||||||
# valid_property_managers = list(itertools.chain(*))
|
# valid_property_managers = list(itertools.chain(*))
|
||||||
valid_property_managers = [e.get('address').lower() for pm in property_managers if pm and pm.get('emails') for e in pm.get('emails') if e and e.get('address')]
|
valid_property_managers = [e.get('address').lower() for pm in property_managers if pm and pm.get('emails') for e in pm.get('emails') if e and e.get('address')]
|
||||||
pprint(valid_property_managers)
|
|
||||||
|
|
||||||
|
|
||||||
row = ProjectModel(
|
row = ProjectModel(
|
||||||
@@ -226,6 +245,7 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine
|
|||||||
notice_service_date=notice_service_date,
|
notice_service_date=notice_service_date,
|
||||||
notice_expiration_date=notice_expiration_date,
|
notice_expiration_date=notice_expiration_date,
|
||||||
case_field_date=case_filed_date,
|
case_field_date=case_filed_date,
|
||||||
|
case_filed_date=case_filed_date,
|
||||||
daily_rent_damages=daily_rent_damages,
|
daily_rent_damages=daily_rent_damages,
|
||||||
default_date=default_date,
|
default_date=default_date,
|
||||||
demurrer_hearing_date=demurrer_hearing_date,
|
demurrer_hearing_date=demurrer_hearing_date,
|
||||||
@@ -326,7 +346,7 @@ def main():
|
|||||||
|
|
||||||
# List projects (all pages) with filter for projects updated in the last 7 days
|
# List projects (all pages) with filter for projects updated in the last 7 days
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
seven_days_ago = (datetime.now() - timedelta(days=14)).strftime('%Y-%m-%d')
|
seven_days_ago = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
|
||||||
projects = client.list_all_projects(latest_activity_since=seven_days_ago)
|
projects = client.list_all_projects(latest_activity_since=seven_days_ago)
|
||||||
|
|
||||||
#projects = [p for p in projects if (p.get("projectId") or {}).get("native") == 15914808]
|
#projects = [p for p in projects if (p.get("projectId") or {}).get("native") == 15914808]
|
||||||
@@ -343,6 +363,14 @@ def main():
|
|||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def sync_single(x):
|
||||||
|
client = FilevineClient()
|
||||||
|
z = process_project(0, 1, client.fetch_project_detail(x), client)
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
#pprint(z)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -382,7 +382,7 @@
|
|||||||
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Date Case Filed')}">
|
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Date Case Filed')}">
|
||||||
|
|
||||||
{% call expander() %}
|
{% call expander() %}
|
||||||
{{ r.case_field_date }}
|
{{ r.case_filed_date || r.case_field_date }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Daily Rent Damages')}">
|
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Daily Rent Damages')}">
|
||||||
|
|||||||
152
terraform/main.tf
Normal file
152
terraform/main.tf
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
google-beta = {
|
||||||
|
source = "hashicorp/google-beta"
|
||||||
|
version = "~> 6.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "google" {
|
||||||
|
project = var.gcp_project_id
|
||||||
|
region = var.gcp_region
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Firebase Project Setup
|
||||||
|
resource "google_firebase_project" "default" {
|
||||||
|
provider = google-beta
|
||||||
|
project = var.gcp_project_id
|
||||||
|
}
|
||||||
|
|
||||||
|
# Firebase Web App
|
||||||
|
resource "google_firebase_web_app" "rothbard_portal" {
|
||||||
|
provider = google-beta
|
||||||
|
project = google_firebase_project.default.project
|
||||||
|
display_name = "Rothbard Client Portal"
|
||||||
|
|
||||||
|
app_urls = ["https://${var.domain_name}"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Firestore Database
|
||||||
|
resource "google_firestore_database" "default" {
|
||||||
|
provider = google-beta
|
||||||
|
project = var.gcp_project_id
|
||||||
|
name = "(default)"
|
||||||
|
location_id = var.firestore_location
|
||||||
|
type = "FIRESTORE_NATIVE"
|
||||||
|
|
||||||
|
delete_protection_state = "DELETE_PROTECTION_DISABLED"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Firebase Authentication - Complete Configuration
|
||||||
|
resource "google_firebase_auth_config" "default" {
|
||||||
|
provider = google-beta
|
||||||
|
project = var.gcp_project_id
|
||||||
|
|
||||||
|
sign_in_options {
|
||||||
|
email {
|
||||||
|
enabled = true
|
||||||
|
password_required = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable other providers for security
|
||||||
|
phone {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
google {
|
||||||
|
enabled = var.enable_google_signin
|
||||||
|
}
|
||||||
|
|
||||||
|
facebook {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
apple {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Email configuration
|
||||||
|
email {
|
||||||
|
reset_password_template {
|
||||||
|
from_email_address = var.auth_from_email
|
||||||
|
from_display_name = var.auth_from_name
|
||||||
|
reply_to = var.auth_reply_to
|
||||||
|
subject = "Reset your Rothbard Law Group password"
|
||||||
|
html = file("${path.module}/templates/reset_password.html")
|
||||||
|
text = file("${path.module}/templates/reset_password.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
email_verification_template {
|
||||||
|
from_email_address = var.auth_from_email
|
||||||
|
from_display_name = var.auth_from_name
|
||||||
|
reply_to = var.auth_reply_to
|
||||||
|
subject = "Verify your Rothbard Law Group account"
|
||||||
|
html = file("${path.module}/templates/email_verification.html")
|
||||||
|
text = file("${path.module}/templates/email_verification.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
sign_in {
|
||||||
|
allow_duplicate_emails = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Multi-factor authentication (disabled for simplicity)
|
||||||
|
multi_factor_auth {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Anonymous user access (disabled)
|
||||||
|
anonymous {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Service Account for the Flask App
|
||||||
|
resource "google_service_account" "flask_app" {
|
||||||
|
account_id = "rothbard-flask-app"
|
||||||
|
display_name = "Rothbard Flask App Service Account"
|
||||||
|
}
|
||||||
|
|
||||||
|
# IAM permissions for the Flask App
|
||||||
|
resource "google_project_iam_member" "firestore_access" {
|
||||||
|
project = var.gcp_project_id
|
||||||
|
role = "roles/datastore.user"
|
||||||
|
member = "serviceAccount:${google_service_account.flask_app.email}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_project_iam_member" "firebase_admin" {
|
||||||
|
project = var.gcp_project_id
|
||||||
|
role = "roles/firebase.admin"
|
||||||
|
member = "serviceAccount:${google_service_account.flask_app.email}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Firestore Security Rules - Note: Firestore security policies are managed through Firestore rules
|
||||||
|
# This section is commented out as google_firestore_security_policy is not supported
|
||||||
|
# Security rules should be managed through firestore.rules file or Firebase console
|
||||||
|
|
||||||
|
# Firebase Hosting (optional - for static assets)
|
||||||
|
resource "google_firebase_hosting_site" "default" {
|
||||||
|
provider = google-beta
|
||||||
|
project = var.gcp_project_id
|
||||||
|
site_id = "rothbard-portal"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output important values
|
||||||
|
output "firebase_web_app_id" {
|
||||||
|
description = "Firebase Web App ID"
|
||||||
|
value = google_firebase_web_app.rothbard_portal.app_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "firebase_project_id" {
|
||||||
|
description = "Firebase Project ID"
|
||||||
|
value = google_firebase_project.default.project
|
||||||
|
}
|
||||||
|
|
||||||
|
output "service_account_email" {
|
||||||
|
description = "Service account email for Flask app"
|
||||||
|
value = google_service_account.flask_app.email
|
||||||
|
}
|
||||||
144
terraform/modules/cloud_run/main.tf
Normal file
144
terraform/modules/cloud_run/main.tf
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# Cloud Run Service for Flask App
|
||||||
|
resource "google_cloud_run_service" "flask_app" {
|
||||||
|
name = "${var.app_name}-service"
|
||||||
|
location = var.gcp_region
|
||||||
|
|
||||||
|
template {
|
||||||
|
spec {
|
||||||
|
containers {
|
||||||
|
image = var.container_image
|
||||||
|
|
||||||
|
# Environment variables for the Flask app
|
||||||
|
env {
|
||||||
|
name = "FLASK_SECRET_KEY"
|
||||||
|
value = var.flask_secret_key
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "FIREBASE_PROJECT_ID"
|
||||||
|
value = var.firebase_project_id
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||||
|
value = "/etc/secrets/service-account.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Filevine API credentials
|
||||||
|
env {
|
||||||
|
name = "FILEVINE_CLIENT_ID"
|
||||||
|
value = var.filevine_client_id
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "FILEVINE_CLIENT_SECRET"
|
||||||
|
value = var.filevine_client_secret
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "FILEVINE_PERSONAL_ACCESS_TOKEN"
|
||||||
|
value = var.filevine_pat
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "FILEVINE_ORG_ID"
|
||||||
|
value = var.filevine_org_id
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "FILEVINE_USER_ID"
|
||||||
|
value = var.filevine_user_id
|
||||||
|
}
|
||||||
|
|
||||||
|
# Memory and CPU limits
|
||||||
|
resources {
|
||||||
|
limits = {
|
||||||
|
cpu = "1000m"
|
||||||
|
memory = "512Mi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mount service account key
|
||||||
|
volume_mount {
|
||||||
|
name = "service-account-key"
|
||||||
|
mount_path = "/etc/secrets"
|
||||||
|
read_only = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Service account for the container
|
||||||
|
service_account_name = var.service_account_email
|
||||||
|
|
||||||
|
# Volumes
|
||||||
|
volumes {
|
||||||
|
name = "service-account-key"
|
||||||
|
secret {
|
||||||
|
secret_name = google_secret_manager_secret.service_account_key.secret_id
|
||||||
|
items {
|
||||||
|
key = "latest"
|
||||||
|
path = "service-account.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Allow unauthenticated access
|
||||||
|
container_concurrency = 100
|
||||||
|
timeout_seconds = 300
|
||||||
|
}
|
||||||
|
|
||||||
|
# Traffic settings
|
||||||
|
metadata {
|
||||||
|
annotations = {
|
||||||
|
"autoscaling.knative.dev/maxScale" = "10"
|
||||||
|
"autoscaling.knative.dev/minScale" = "1"
|
||||||
|
"run.googleapis.com/ingress" = "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
traffic {
|
||||||
|
percent = 100
|
||||||
|
latest_revision = true
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [google_secret_manager_secret_version.service_account_key]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make Cloud Run service publicly accessible
|
||||||
|
resource "google_cloud_run_service_iam_member" "public" {
|
||||||
|
location = google_cloud_run_service.flask_app.location
|
||||||
|
project = google_cloud_run_service.flask_app.project
|
||||||
|
service = google_cloud_run_service.flask_app.name
|
||||||
|
role = "roles/run.invoker"
|
||||||
|
member = "allUsers"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Store service account key in Secret Manager
|
||||||
|
resource "google_secret_manager_secret" "service_account_key" {
|
||||||
|
project = var.gcp_project_id
|
||||||
|
secret_id = "${var.app_name}-service-account-key"
|
||||||
|
|
||||||
|
replication {
|
||||||
|
automatic {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_secret_manager_secret_version" "service_account_key" {
|
||||||
|
secret = google_secret_manager_secret.service_account_key.id
|
||||||
|
secret_data = var.service_account_key_data
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cloud Storage bucket for container storage (if needed)
|
||||||
|
resource "google_storage_bucket" "app_storage" {
|
||||||
|
name = "${var.app_name}-storage-${var.gcp_project_id}"
|
||||||
|
location = var.gcp_region
|
||||||
|
force_destroy = true
|
||||||
|
|
||||||
|
uniform_bucket_level_access = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output the service URL
|
||||||
|
output "service_url" {
|
||||||
|
description = "Cloud Run service URL"
|
||||||
|
value = google_cloud_run_service.flask_app.status[0].url
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user