From e289fb723606a8d9eddc775bb557f38d21c114b5 Mon Sep 17 00:00:00 2001 From: xrendan Date: Fri, 20 Jun 2025 09:41:11 -0600 Subject: [PATCH] map promises to departments --- app/avo/resources/department.rb | 3 + app/avo/resources/department_promise.rb | 14 ++++ app/avo/resources/promise.rb | 4 + .../avo/department_promises_controller.rb | 4 + app/models/department.rb | 5 ++ app/models/department_promise.rb | 4 + app/models/promise.rb | 19 ++++- ...250620144837_create_department_promises.rb | 11 +++ .../20250620152703_add_promise_departments.rb | 81 +++++++++++++++++++ db/schema.rb | 14 +++- 10 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 app/avo/resources/department_promise.rb create mode 100644 app/controllers/avo/department_promises_controller.rb create mode 100644 app/models/department_promise.rb create mode 100644 db/migrate/20250620144837_create_department_promises.rb create mode 100644 db/migrate/20250620152703_add_promise_departments.rb diff --git a/app/avo/resources/department.rb b/app/avo/resources/department.rb index 15156b3..eb89353 100644 --- a/app/avo/resources/department.rb +++ b/app/avo/resources/department.rb @@ -14,5 +14,8 @@ def fields field :priority, as: :number field :government, as: :belongs_to field :ministers, as: :has_many + field :lead_promises, as: :has_many + + field :promises, as: :has_many end end diff --git a/app/avo/resources/department_promise.rb b/app/avo/resources/department_promise.rb new file mode 100644 index 0000000..ecee658 --- /dev/null +++ b/app/avo/resources/department_promise.rb @@ -0,0 +1,14 @@ +class Avo::Resources::DepartmentPromise < Avo::BaseResource + # self.includes = [] + # self.attachments = [] + # self.search = { + # query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) } + # } + + def fields + field :id, as: :id + field :is_lead, as: :boolean + field :department, as: :belongs_to + field :promise, as: :belongs_to + end +end diff --git a/app/avo/resources/promise.rb b/app/avo/resources/promise.rb index 57d6092..4fda9c3 100644 --- a/app/avo/resources/promise.rb +++ b/app/avo/resources/promise.rb @@ -30,6 +30,8 @@ def fields field :bc_priority_score, as: :number, sortable: true field :bc_promise_direction, as: :text field :bc_promise_rank, as: :text + + field :lead_department, as: :has_one # field :bc_promise_rank_rationale, as: :textarea # field :bc_ranked_at, as: :date_time field :candidate_or_government, as: :text @@ -86,6 +88,8 @@ def fields # field :policy_areas, as: :code # field :target_groups, as: :code + field :department_promises, as: :has_many + field :evidences, as: :has_many end end diff --git a/app/controllers/avo/department_promises_controller.rb b/app/controllers/avo/department_promises_controller.rb new file mode 100644 index 0000000..ed7f04b --- /dev/null +++ b/app/controllers/avo/department_promises_controller.rb @@ -0,0 +1,4 @@ +# This controller has been generated to enable Rails' resource routes. +# More information on https://docs.avohq.io/3.0/controllers.html +class Avo::DepartmentPromisesController < Avo::ResourcesController +end diff --git a/app/models/department.rb b/app/models/department.rb index 8f813d9..00c9e52 100644 --- a/app/models/department.rb +++ b/app/models/department.rb @@ -1,4 +1,9 @@ class Department < ApplicationRecord belongs_to :government has_many :ministers + + has_many :department_promises, dependent: :destroy + has_many :promises, through: :department_promises + has_many :lead_promises, -> { where(department_promises: { is_lead: true }) }, + through: :department_promises, source: :promise end diff --git a/app/models/department_promise.rb b/app/models/department_promise.rb new file mode 100644 index 0000000..0b751ea --- /dev/null +++ b/app/models/department_promise.rb @@ -0,0 +1,4 @@ +class DepartmentPromise < ApplicationRecord + belongs_to :department + belongs_to :promise +end diff --git a/app/models/promise.rb b/app/models/promise.rb index da77f54..6c4bb31 100644 --- a/app/models/promise.rb +++ b/app/models/promise.rb @@ -3,11 +3,28 @@ class Promise < ApplicationRecord has_many :activities, through: :evidences has_many :entries, through: :activities + has_many :department_promises, dependent: :destroy + # has_many :relevant_departments, through: :department_promises, source: :department + has_one :lead_department_promise, -> { where(is_lead: true) }, class_name: "DepartmentPromise" + has_one :lead_department, through: :lead_department_promise, source: :department + + def link_department!(department, is_lead: false) + Rails.logger.info("Linking department #{department.slug} to promise #{promise_id}") + if is_lead + lead_department_promise&.update(is_lead: false) + end + + dp = department_promises.find_or_initialize_by(department: department) + dp.is_lead = is_lead + dp.save! + end + def format_for_llm { promise_id: promise_id, title: concise_title, - description: description + description: description, + text: text } end end diff --git a/db/migrate/20250620144837_create_department_promises.rb b/db/migrate/20250620144837_create_department_promises.rb new file mode 100644 index 0000000..b725ff0 --- /dev/null +++ b/db/migrate/20250620144837_create_department_promises.rb @@ -0,0 +1,11 @@ +class CreateDepartmentPromises < ActiveRecord::Migration[8.0] + def change + create_table :department_promises do |t| + t.references :department, null: false, foreign_key: true + t.references :promise, null: false, foreign_key: true + t.boolean :is_lead, default: false, null: false + + t.timestamps + end + end +end diff --git a/db/migrate/20250620152703_add_promise_departments.rb b/db/migrate/20250620152703_add_promise_departments.rb new file mode 100644 index 0000000..34a3cc9 --- /dev/null +++ b/db/migrate/20250620152703_add_promise_departments.rb @@ -0,0 +1,81 @@ +class AddPromiseDepartments < ActiveRecord::Migration[8.0] + MAPPING = { + "Minister of National Defence": "national-defence", + "Minister of Public Safety": "public-safety-canada", + "Secretary of State (Defence Procurement)": "national-defence", + "Minister of Industry": "innovation-science-and-economic-development-canada", + "Minister of Foreign Affairs": "global-affairs-canada", + "Minister of Finance": "finance-canada", + "Minister of Jobs and Families": "employment-and-social-development-canada", + "Secretary of State (Children and Youth)": "employment-and-social-development-canada", + "Minister of Indigenous Services": "indigenous-services-canada", + "Minister of Immigration, Refugees and Citizenship": "immigration-refugees-and-citizenship-canada", + "Minister of Environment and Climate Change": "environment-and-climate-change-canada", + "President of the Treasury Board": "treasury-board-of-canada-secretariat", + "Minister of Crown-Indigenous Relations": "crown-indigenous-relations-and-northern-affairs-canada", + "Minister of Transport and Internal Trade": "transport-canada", + "President of the King\u2019s Privy Council for Canada and Minister responsible for Canada-U.S. Trade, Intergovernmental Affairs and One Canadian Economy": "privy-council-office-intergovernmental-affairs-secretariat", + "Minister of Artificial Intelligence and Digital Innovation": "artificial-intelligence-and-digital-innovation", + "Minister of Energy and Natural Resources": "natural-resources-canada", + "Minister of Health": "health-canada", + "Secretary of State (Labour)": "employment-and-social-development-canada", + "Minister of Canadian Identity and Culture": "canadian-heritage", + "Minister of Justice and Attorney General of Canada": "justice-canada", + "Minister of Housing and Infrastructure": "infrastructure-canada", + "Secretary of State (Combatting Crime)": "public-safety-canada", + "Secretary of State (Small Business and Tourism)": "innovation-science-and-economic-development-canada", + "Minister of Government Transformation, Public Works and Procurement": "public-services-and-procurement-canada", + "Secretary of State (Nature)": "environment-and-climate-change-canada", + "Minister of Agriculture and Agri-Food": "agriculture-and-agri-food-canada", + "Minister of Emergency Management and Community Resilience": "emergency-preparedness-canada", + "Leader of the Government in the House of Commons": nil, + "Secretary of State (Canada Revenue Agency and Financial Institutions)": "canada-revenue-agency", + "Minister of Northern and Arctic Affairs": "crown-indigenous-relations-and-northern-affairs-canada", + "Minister of Women and Gender Equality": "women-and-gender-equality-canada", + "Secretary of State (Seniors)": "employment-and-social-development-canada", + "Secretary of State (International Development)": "global-affairs-canada", + "Minister of Fisheries": "fisheries-and-oceans-canada", + "Minister of International Trade": "global-affairs-canada", + "Minister of Veterans Affairs": "veterans-affairs-canada", + "Secretary of State (Rural Development)": "rural-economic-development", + "Minister responsible for the Atlantic Canada Opportunities Agency": "atlantic-canada-opportunities-agency", + "Minister responsible for Canada Economic Development for Quebec Regions": "canada-economic-development-for-quebec-regions", + "Minister responsible for Pacific Economic Development Canada": "federal-economic-development-agency-for-southern-ontario", + "Minister of Northern and Arctic Affairs and Minister responsible for the Canadian Northern Economic Development Agency": "crown-indigenous-relations-and-northern-affairs-canada", + "Prime Minister": "prime-minister-office" + }.freeze + + def map_promise(promise) + relevant_departments = promise.relevant_departments + + relevant_departments&.each do |department| + dept_slug = MAPPING[department.to_sym] + dept = Department.find_by(slug: dept_slug) + + if dept.present? + promise.link_department!(dept, is_lead: false) + else + Rails.logger.warn("No department found for relevant department: #{department}") + end + end + + # Do lead department last otherwise, it could be overwritten by relevant departments + dept_slug = MAPPING[promise.responsible_department_lead&.to_sym] + dept = Department.find_by(slug: dept_slug) + if dept.present? + promise.link_department!(dept, is_lead: true) + else + Rails.logger.warn("No department found for lead department: #{promise.responsible_department_lead}") + end + end + + def up + Promise.find_each do |promise| + map_promise(promise) + end + end + + def down + DepartmentPromise.destroy_all + end +end diff --git a/db/schema.rb b/db/schema.rb index 94df139..7fbfd8d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_06_19_212356) do +ActiveRecord::Schema[8.0].define(version: 2025_06_20_152703) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -66,6 +66,16 @@ t.string "type" end + create_table "department_promises", force: :cascade do |t| + t.bigint "department_id", null: false + t.bigint "promise_id", null: false + t.boolean "is_lead", default: false, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["department_id"], name: "index_department_promises_on_department_id" + t.index ["promise_id"], name: "index_department_promises_on_promise_id" + end + create_table "departments", force: :cascade do |t| t.bigint "government_id", null: false t.string "slug", null: false @@ -368,6 +378,8 @@ add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "activities", "entries" add_foreign_key "activities", "governments" + add_foreign_key "department_promises", "departments" + add_foreign_key "department_promises", "promises" add_foreign_key "departments", "governments" add_foreign_key "entries", "entries", column: "parent_id" add_foreign_key "entries", "feeds"