diff --git a/js/admin/duplicate-sponsors.js b/js/admin/duplicate-sponsors.js new file mode 100644 index 00000000..b9478309 --- /dev/null +++ b/js/admin/duplicate-sponsors.js @@ -0,0 +1,106 @@ +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); + } + + 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]; + const { name, value } = select; + const sponsorName = value.split(': ')[0]; + const sponsorId = value.split(': ')[1]; + request[`${name}Name`] = sponsorName; + request[`${name}Id`] = sponsorId; + }); + requested.push({ ...request }); + }); + return requested; + } + + render() { + const { submitSuccess } = this.state; + const options = this.props.state_sponsors.map((sponsor) => { + const value = `${sponsor.name }: ${sponsor.id}`; + 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 4502f54a..ff1663d0 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, create_delta_sets, create_pr, ) @@ -59,6 +61,16 @@ 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", + ), re_path( r"^(?P{})/deltas/$".format(state_abbr_pattern), create_delta_sets, diff --git a/people_admin/views.py b/people_admin/views.py index 71e0acdb..8e8319ec 100644 --- a/people_admin/views.py +++ b/people_admin/views.py @@ -3,6 +3,7 @@ from django.shortcuts import render, get_object_or_404 from django.db.models import Count from openstates.data.models import LegislativeSession, Person + 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 @@ -248,6 +249,51 @@ def apply_bulk_edits(request): 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.get_or_create( + name=f"duplicates by {request.user}", + created_by=request.user, + ) + + for match in form_data: + additional_id = [ + "append", + "other_identifiers", + {"scheme": "openstates", "identifier": match["secondId"]}, + ] + additional_name = ["append", "other_names", {"name": match["secondName"]}] + PersonDelta.objects.create( + 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"}) + + @never_cache @user_passes_test(lambda u: u.has_perm(EDIT_PERM)) def create_delta_sets(request, state): 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 edb546b5..a455e826 100644 --- a/templates/people_admin/people_matcher.html +++ b/templates/people_admin/people_matcher.html @@ -68,6 +68,8 @@

People Matcher

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

Unmatched Total: {{ unmatched_total }}

+

Think you see multiple sponsors available for a match?

+