From 324ac956f0d730f6adb5e0ac0a898422452fe525 Mon Sep 17 00:00:00 2001 From: NewAgeAirbender Date: Tue, 7 Sep 2021 17:08:33 -0500 Subject: [PATCH 1/2] get duplicate sponsors matched and deltasets created --- js/admin/duplicate-sponsors.js | 115 ++++++++++++++++++ js/admin/people.js | 2 + people_admin/urls.py | 12 ++ people_admin/views.py | 33 +++++ .../people_admin/duplicate_sponsors.html | 12 ++ templates/people_admin/people_matcher.html | 2 + 6 files changed, 176 insertions(+) create mode 100644 js/admin/duplicate-sponsors.js create mode 100644 templates/people_admin/duplicate_sponsors.html diff --git a/js/admin/duplicate-sponsors.js b/js/admin/duplicate-sponsors.js new file mode 100644 index 00000000..5739e356 --- /dev/null +++ b/js/admin/duplicate-sponsors.js @@ -0,0 +1,115 @@ +import React from 'react'; +import Cookies from "js-cookie"; + +class DuplicateSponsors extends React.Component { + constructor(props) { + super(props); + this.state = { + submitSuccess: false, + state: this.props.state, + sponsors: ['sponsorGroup0'], + matchRequests: [] + } + this.handleInputChange = this.handleInputChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.pullFormData = this.pullFormData.bind(this); + this.addNewSponsorGroup = this.addNewSponsorGroup.bind(this); + } + + handleInputChange(event) { + const target = event.target; + const { value, name } = target; + const parent = event.target.parentElement.parentElement.id; + // const matchRequest = {[parent]: {[name]: value}}; + // this.state.matchRequest.push(matchRequest); + } + + handleSubmit(event) { + const csrftoken = Cookies.get("csrftoken"); + const url = "/admin/people/update/duplicate_sponsors/"; + const sponsorData = this.pullFormData(); + + fetch(url, { + method: "POST", + credentials: "same-origin", + headers: { + "Accept": "application/json", + "X-Requested-With": "XMLHttpRequest", + "X-CSRFToken": csrftoken, + }, + body: JSON.stringify(sponsorData), + }).then(response => { + this.setState({submitSuccess: true}); + return response.json(); + }).catch(error => { + console.log(error); + }) + event.preventDefault(); + } + + addNewSponsorGroup(event) { + event.preventDefault(); + let sponsorDivs = [...this.state.sponsors]; + sponsorDivs.push(`sponsorGroup${sponsorDivs.length}`); + this.setState({sponsors: sponsorDivs }); + } + + pullFormData() { + const requested = []; + const sponsors = [...this.state.sponsors]; + sponsors.forEach((sponsor) => { + const parent = document.getElementById(sponsor); + const request = {}; + parent.childNodes.forEach(child => { + const select = child.childNodes[1]; + if (select) { + const { name, value } = select; + request[name] = value; + } + }); + requested.push({ ...request }); + }); + return requested; + } + + render() { + const { submitSuccess } = this.state; + const options = this.props.state_sponsors.map((sponsor) => { + return }); + const sponsorGroups = this.state.sponsors.map((sponsor) => { + return
+ + + +
+
+ }); + + return( +
+ {submitSuccess ? ( +
+

Sponsor edits submitted successfully.

+ Back to Jurisdictions +
+ ) : ( +
+ {sponsorGroups} + + + Cancel +
+ )} + +
+ ) + } +} + +export default DuplicateSponsors; diff --git a/js/admin/people.js b/js/admin/people.js index 86416bda..ce3abb10 100644 --- a/js/admin/people.js +++ b/js/admin/people.js @@ -2,6 +2,8 @@ import React from "react"; import {addDataHookListener} from "../utils"; import PeopleList from "./people-list"; import NewPersonForm from "./add-person"; +import DuplicateSponsors from "./duplicate-sponsors"; addDataHookListener("people-list", "context", PeopleList); addDataHookListener("new-person", "context", NewPersonForm); +addDataHookListener("duplicate-sponsors", "context", DuplicateSponsors); diff --git a/people_admin/urls.py b/people_admin/urls.py index 9fd0acc2..c74f5860 100644 --- a/people_admin/urls.py +++ b/people_admin/urls.py @@ -9,6 +9,8 @@ new_legislator, apply_new_legislator, apply_bulk_edits, + duplicate_sponsors, + apply_duplicate_sponsors, ) # Only allow valid state abbreviations @@ -57,4 +59,14 @@ apply_bulk_edits, name="apply_bulk_edits", ), + re_path( + r"^(?P{})/duplicate_sponsors/$".format(state_abbr_pattern), + duplicate_sponsors, + name="duplicate_sponsors", + ), + re_path( + r"^update/duplicate_sponsors/", + apply_duplicate_sponsors, + name="apply_duplicate_sponsors", + ), ] diff --git a/people_admin/views.py b/people_admin/views.py index 2ea0db77..304f6d3c 100644 --- a/people_admin/views.py +++ b/people_admin/views.py @@ -243,3 +243,36 @@ def apply_bulk_edits(request): data_changes=updates, ) return JsonResponse({"status": "success"}) + + +@user_passes_test(lambda u: u.has_perm(EDIT_PERM)) +def duplicate_sponsors(request, state): + jid = abbr_to_jid(state) + state_sponsors = [ + person_data(p) + for p in Person.objects.filter( + current_jurisdiction_id=jid, current_role__isnull=False + ).order_by("family_name", "name") + ] + + context = {"state": state, "state_sponsors": state_sponsors} + + return render(request, "people_admin/duplicate_sponsors.html", {"context": context}) + + +@user_passes_test(lambda u: u.has_perm(EDIT_PERM)) +def apply_duplicate_sponsors(request): + form_data = json.load(request) + + delta = DeltaSet.objects.create( + name=f"duplicates by {request.user}", + created_by=request.user, + ) + + for match in form_data: + change = ["append", "other_id", {"id": match["secondSponsor"]}] + PersonDelta.objects.create( + person_id=match["firstSponsor"], delta_set=delta, data_changes=change + ) + + return JsonResponse({"status": "success"}) diff --git a/templates/people_admin/duplicate_sponsors.html b/templates/people_admin/duplicate_sponsors.html new file mode 100644 index 00000000..545c3206 --- /dev/null +++ b/templates/people_admin/duplicate_sponsors.html @@ -0,0 +1,12 @@ +{% extends "public/components/base.html" %} +{% load static %} + +{% block scripts %} + {{ context|json_script:"context" }} + + +{% endblock %} + +{% block content %} +
+{% endblock %} diff --git a/templates/people_admin/people_matcher.html b/templates/people_admin/people_matcher.html index 2d1bb2ea..96a0786f 100644 --- a/templates/people_admin/people_matcher.html +++ b/templates/people_admin/people_matcher.html @@ -67,6 +67,8 @@

People Matcher

{{ session|default:"All Sessions" }}

Unmatched Total: {{ unmatched_total }}

+

Think you see multiple sponsors available for a match?

+

From af3286fb9014cf3e091f552c7e8f70d8e0bfa69b Mon Sep 17 00:00:00 2001 From: NewAgeAirbender Date: Wed, 8 Sep 2021 14:33:14 -0500 Subject: [PATCH 2/2] creates pr for duplicate sponsor request --- js/admin/duplicate-sponsors.js | 25 ++++++++----------------- people_admin/views.py | 20 +++++++++++++++++--- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/js/admin/duplicate-sponsors.js b/js/admin/duplicate-sponsors.js index 5739e356..b9478309 100644 --- a/js/admin/duplicate-sponsors.js +++ b/js/admin/duplicate-sponsors.js @@ -16,14 +16,6 @@ class DuplicateSponsors extends React.Component { this.addNewSponsorGroup = this.addNewSponsorGroup.bind(this); } - handleInputChange(event) { - const target = event.target; - const { value, name } = target; - const parent = event.target.parentElement.parentElement.id; - // const matchRequest = {[parent]: {[name]: value}}; - // this.state.matchRequest.push(matchRequest); - } - handleSubmit(event) { const csrftoken = Cookies.get("csrftoken"); const url = "/admin/people/update/duplicate_sponsors/"; @@ -62,10 +54,11 @@ class DuplicateSponsors extends React.Component { const request = {}; parent.childNodes.forEach(child => { const select = child.childNodes[1]; - if (select) { const { name, value } = select; - request[name] = value; - } + const sponsorName = value.split(': ')[0]; + const sponsorId = value.split(': ')[1]; + request[`${name}Name`] = sponsorName; + request[`${name}Id`] = sponsorId; }); requested.push({ ...request }); }); @@ -75,17 +68,15 @@ class DuplicateSponsors extends React.Component { render() { const { submitSuccess } = this.state; const options = this.props.state_sponsors.map((sponsor) => { - return }); + const value = `${sponsor.name }: ${sponsor.id}`; + return }); const sponsorGroups = this.state.sponsors.map((sponsor) => { return
-
diff --git a/people_admin/views.py b/people_admin/views.py index 304f6d3c..45960e26 100644 --- a/people_admin/views.py +++ b/people_admin/views.py @@ -3,6 +3,8 @@ from django.shortcuts import render, get_object_or_404 from django.db.models import Count from openstates.data.models import LegislativeSession, Person + +from people_admin.git import delta_set_to_pr from utils.common import abbr_to_jid, sessions_with_bills, states from django.views.decorators.http import require_http_methods from django.views.decorators.cache import never_cache @@ -264,15 +266,27 @@ def duplicate_sponsors(request, state): def apply_duplicate_sponsors(request): form_data = json.load(request) - delta = DeltaSet.objects.create( + delta = DeltaSet.objects.get_or_create( name=f"duplicates by {request.user}", created_by=request.user, ) for match in form_data: - change = ["append", "other_id", {"id": match["secondSponsor"]}] + additional_id = [ + "append", + "other_identifiers", + {"scheme": "openstates", "identifier": match["secondId"]}, + ] + additional_name = ["append", "other_names", {"name": match["secondName"]}] PersonDelta.objects.create( - person_id=match["firstSponsor"], delta_set=delta, data_changes=change + person_id=match["firstId"], + delta_set=delta, + data_changes=[additional_id, additional_name], ) + ds = DeltaSet.objects.get(id=delta, pr_status="N") + print(f"creating {ds.id} | {ds.name} | {ds.created_by}") + ds.pr_url = delta_set_to_pr(ds) + ds.pr_status = "C" + ds.save() return JsonResponse({"status": "success"})