diff --git a/bundlesize.config.json b/bundlesize.config.json index 3f164d93a2d..b4339f6ab83 100644 --- a/bundlesize.config.json +++ b/bundlesize.config.json @@ -30,7 +30,7 @@ }, { "path": "static/build/page-book.css", - "maxSize": "9.4KB" + "maxSize": "9.5KB" }, { "path": "static/build/page-edit.css", diff --git a/openlibrary/core/observations.py b/openlibrary/core/observations.py index 37693015200..4869565dd09 100644 --- a/openlibrary/core/observations.py +++ b/openlibrary/core/observations.py @@ -340,61 +340,85 @@ def get_patron_observations(cls, username, work_id=None): return list(oldb.query(query, vars=data)) + def get_multi_choice(type): + """ + Searches for the given type in the observations object, and returns the type's 'multi_choice' value. + + return: The multi_choice value for the given type + """ + for o in OBSERVATIONS['observations']: + if o['label'] == type: + return o['multi_choice'] + @classmethod - def persist_observations(cls, username, work_id, observations, edition_id=NULL_EDITION_VALUE): + def persist_observation(cls, username, work_id, observation, action, edition_id=NULL_EDITION_VALUE): """ - Insert or update a collection of observations. If no records exist - for the given work_id, new observations are inserted. + Inserts or deletes a single observation, depending on the given action. + + If the action is 'delete', the observation will be deleted from the observations table. + + If the action is 'add', and the observation type only allows a single value (multi_choice == True), + an attempt is made to delete previous observations of the same type before the new observation is + persisted. + Otherwise, the new observation is stored in the DB. """ - def get_observation_ids(observations): + def get_observation_ids(observation): """ - Given a list of observation key-value pairs, returns a list of observation IDs. + Given an observation key-value pair, returns an ObservationIds tuple. - return: List of observation IDs + return: An ObservationsIds tuple """ - observation_ids = [] + key = list(observation)[0] + item = next((o for o in OBSERVATIONS['observations'] if o['label'] == key)) - for o in observations: - key = list(o)[0] - observation = next((o for o in OBSERVATIONS['observations'] if o['label'] == key)) - - observation_ids.append( - ObservationIds( - observation['id'], - next((v['id'] for v in observation['values'] if v['name'] == o[key])) - ) - ) - - return observation_ids + return ObservationIds( + item['id'], + next((v['id'] for v in item['values'] if v['name'] == observation[key])) + ) oldb = db.get_db() - records = cls.get_patron_observations(username, work_id) - - observation_ids = get_observation_ids(observations) - - for r in records: - record_ids = ObservationIds(r['type'], r['value']) - # Delete values that are in existing records but not in submitted observations - if record_ids not in observation_ids: - cls.remove_observations( - username, - work_id, - edition_id=edition_id, - observation_type=r['type'], - observation_value=r['value'] - ) - else: - # If same value exists in both existing records and observations, remove from observations - observation_ids.remove(record_ids) - - if len(observation_ids): - # Insert all remaining observations - oldb.multiple_insert('observations', - [{'username': username, 'work_id': work_id, 'edition_id': edition_id, 'observation_value': id.value_id, 'observation_type': id.type_id} for id in observation_ids] + observation_ids = get_observation_ids(observation) + + data = { + 'username': username, + 'work_id': work_id, + 'edition_id': edition_id, + 'observation_type': observation_ids.type_id, + 'observation_value': observation_ids.value_id + } + + where_clause = 'username=$username AND work_id=$work_id AND observation_type=$observation_type ' + + + if action == 'delete': + # Delete observation and return: + where_clause += 'AND observation_value=$observation_value' + + return oldb.delete( + 'observations', + vars=data, + where=where_clause + ) + elif not cls.get_multi_choice(list(observation)[0]): + # A radio button value has changed. Delete old value, if one exists: + oldb.delete( + 'observations', + vars=data, + where=where_clause ) + # Insert new value and return: + return oldb.insert( + 'observations', + username=username, + work_id=work_id, + edition_id=edition_id, + observation_type=observation_ids.type_id, + observation_value=observation_ids.value_id + ) + @classmethod def remove_observations(cls, username, work_id, edition_id=NULL_EDITION_VALUE, observation_type=None, observation_value=None): """ diff --git a/openlibrary/plugins/openlibrary/api.py b/openlibrary/plugins/openlibrary/api.py index ba170f27500..913e2edc60a 100644 --- a/openlibrary/plugins/openlibrary/api.py +++ b/openlibrary/plugins/openlibrary/api.py @@ -462,10 +462,11 @@ def POST(self, work_id): data = json.loads(web.data()) - Observations.persist_observations( + Observations.persist_observation( data['username'], work_id, - data['observations'] + data['observation'], + data['action'] ) def response(msg, status="success"): diff --git a/openlibrary/plugins/openlibrary/js/patron-metadata/index.js b/openlibrary/plugins/openlibrary/js/patron-metadata/index.js index 6dda7101e0e..2b90ee9c110 100644 --- a/openlibrary/plugins/openlibrary/js/patron-metadata/index.js +++ b/openlibrary/plugins/openlibrary/js/patron-metadata/index.js @@ -1,5 +1,19 @@ import '../../../../../static/css/components/metadata-form.less'; +// Event name for submission status updates: +const OBSERVATION_SUBMISSION = 'observationSubmission'; + +// Used to denote a submission state change for all sections: +const ANY_SECTION_TYPE = 'allSections'; + +// Denotes all possible states of an observation submission: +const SubmissionState = { + INITIAL: 1, // Initial state --- nothing has been submitted yet. + PENDING: 2, // A submission has been made, but the server has not yet responded. + SUCCESS: 3, // The observation was successfully processed by the server. + FAILURE: 4 // Something went wrong while the observation was being processed by the server. +}; + export function initPatronMetadata() { function displayModal() { $.colorbox({ @@ -16,39 +30,84 @@ export function initPatronMetadata() { let className = observation.multi_choice ? 'multi-choice' : 'single-choice'; let $choices = $(`
`); let choiceIndex = observation.values.length; + let type = observation.label; for (const value of observation.values) { - let choiceId = `${observation.label}Choice${choiceIndex--}`; + let choiceId = `${type}Choice${choiceIndex--}`; let checked = ''; - if (observation.label in selectedValues - && selectedValues[observation.label].includes(value)) { + if (type in selectedValues + && selectedValues[type].includes(value)) { checked = 'checked'; } $choices.append(` `); + + ${value} + `); } - $form.append(` -